f342895d4ed669f445e3cb69b16f1477b4dc4af6
[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 // Cell data:
129 // | byte 3 | byte 2 | byte 1 | byte 0 |
130 // | anim | cfg | rflags | sflags |
131
132 // Static flags
133 // Level defined (fixed)
134 #define FLAG_WALL 0x1 /* Border cells // non passable */
135 #define FLAG_LEVEL_CANAL 0x2 /* Used to mark canals from IO or static sections etc */
136
137 // Player defined
138 #define FLAG_CANAL 0x4 /* Cell is marked as canal and can transport water */
139 #define FLAG_UNUSED0 0x8
140 #define FLAG_UNUSED1 0x10
141 #define FLAG_UNUSED2 0x20
142 #define FLAG_UNUSED3 0x40
143 #define FLAG_UNUSED4 0x80
144
145 // Volatile flags
146 #define FLAG_WATER 0x100 /* Does this cell have water flowing through it */
147 #define FLAG_UNUSED5 0x200
148 #define FLAG_UNUSED6 0x400
149 #define FLAG_UNUSED7 0x800
150
151 #define FLAG_UNUSED8 0x1000
152 #define FLAG_UNUSED9 0x2000
153 #define FLAG_UNUSEDA 0x4000
154 #define FLAG_UNUSEDB 0x8000
155
156 // Combined
157 #define CFLAG_TRANSPORT (FLAG_CANAL|FLAG_LEVEL_CANAL)
158
159 static struct
160 {
161 u32 x,y;
162
163 v2f origin;
164 struct cell *selected;
165 int select_valid;
166 int playing;
167 u32 frame;
168
169 u32 *io;
170
171 struct vstack
172 {
173 struct vframe
174 {
175 int x, y;
176 int i;
177 }
178 frames[ 64 ];
179
180 int level;
181 u32 flags;
182 }
183 stack;
184
185 GLuint tile_texture;
186 GLuint flow_texture;
187
188 GLuint tiles_vao;
189 GLuint tiles_vbo;
190 }
191 map;
192
193 static void map_free(void)
194 {
195 for( int i = 0; i < arrlen( map.io ); i ++ )
196 {
197 arrfree( map.cells[ map.io[i] ].conditions );
198 }
199
200 arrfree( map.cells );
201 arrfree( map.io );
202 map.x = 0;
203 map.y = 0;
204 map.cells = NULL;
205 map.io = NULL;
206 }
207
208 static struct cell *ptile( int pos[2] )
209 {
210 return map.cells + pos[1]*map.x + pos[0];
211 }
212
213 static struct cell *gettile( int pos[2] )
214 {
215 if( pos[0] >= 0 && pos[0] < map.x && pos[1] >= 0 && pos[1] < map.y )
216 return map.cells + pos[1]*map.x + pos[0];
217 return NULL;
218 }
219
220 static struct cell *getiftile( int pos[2], u32 flags )
221 {
222 struct cell *cell = gettile( pos );
223 if( cell && (cell->flags & flags) )
224 return cell;
225
226 return NULL;
227 }
228
229 static void map_tile_coords_from_index( int i, int coords[2] )
230 {
231 coords[0] = i % map.x;
232 coords[1] = (i - coords[0])/map.x;
233 }
234
235 static void map_stack_refresh(void)
236 {
237 for( int i = 0; i < map.x*map.y; i ++ )
238 map.cells[i].flags &= ~CELL_FLAG_VISITED;
239 }
240
241 static void map_stack_init( int coords[2] )
242 {
243 map.stack.level = 0;
244 map.stack.frames[0].i = 0;
245 map.stack.frames[0].x = coords[0];
246 map.stack.frames[0].y = coords[1];
247 }
248
249 static struct cell *map_stack_next(void)
250 {
251 struct cell *tile = NULL;
252
253 while( !tile )
254 {
255 struct vframe *frame = &map.stack.frames[ map.stack.level ];
256
257 int output_dirs[][2] = { {0,1}, {-1,0}, {1,0} };
258
259 if( frame->i < 3 )
260 {
261 int *dir = output_dirs[ frame->i ];
262 tile = getiftile( (int[2]){frame->x+dir[0], frame->y+dir[1]}, CELL_FLAG_WALKABLE );
263
264 if( tile && !(tile->flags & CELL_FLAG_VISITED) )
265 {
266 map.stack.level ++;
267 frame[1].i = 0;
268 frame[1].x = frame[0].x+dir[0];
269 frame[1].y = frame[0].y+dir[1];
270
271 tile->flags |= CELL_FLAG_VISITED;
272
273 if( frame->i == 0 )
274 frame->i = 400;
275 }
276 else
277 tile = NULL;
278
279 frame->i ++;
280 }
281 else
282 {
283 map.stack.level --;
284 tile = NULL;
285
286 if( map.stack.level < 0 )
287 return NULL;
288 }
289 }
290
291 return tile;
292 }
293
294 static void map_stack_current_coords( int coords[2], int offset )
295 {
296 coords[0] = map.stack.frames[ map.stack.level+offset ].x;
297 coords[1] = map.stack.frames[ map.stack.level+offset ].y;
298 }
299
300 static void map_reclassify( v4i bounds )
301 {
302 u8 celldata[ 4096 ];
303
304 for( int y = bounds[1]; y < bounds[3]; y ++ )
305 {
306 for( int x = bounds[0]; x < bounds[2]; x ++ )
307 {
308 struct cell *cur = map.cells + y*map.x + x;
309 u8 *cellbytes = celldata + (y*map.x+x)*4;
310
311 if( cur->flags & CELL_FLAG_WALKABLE )
312 {
313 struct cell *a, *b, *c, *d;
314
315 a = getiftile( (int[2]){ x,y+1 }, CELL_FLAG_WALKABLE );
316 b = getiftile( (int[2]){ x+1,y }, CELL_FLAG_WALKABLE );
317 c = getiftile( (int[2]){ x,y-1 }, CELL_FLAG_WALKABLE );
318 d = getiftile( (int[2]){ x-1,y }, CELL_FLAG_WALKABLE );
319
320 u32 config = (a?0x1:0x0) | (b?0x2:0x0) | (c?0x4:0x0) | (d?0x8:0x0);
321 cellbytes[ 0 ] = config;
322 }
323 else
324 {
325 // TODO: Random background tiles
326 cellbytes[ 0 ] = 15;
327 }
328
329 cellbytes[ 1 ] = 0x00;
330 cellbytes[ 2 ] = 0x00;
331 cellbytes[ 3 ] = 0x00;
332 }
333 }
334
335 glBindBuffer( GL_ARRAY_BUFFER, map.tiles_vbo );
336 glBufferSubData( GL_ARRAY_BUFFER, 16*sizeof(float) + 1024*2*sizeof(float), map.x*map.y*4, celldata );
337 }
338
339 static int map_load( const char *str )
340 {
341 map_free();
342
343 char const *c = str;
344
345 // Scan for width
346 for(;; map.x ++)
347 {
348 if( str[map.x] == ';' )
349 break;
350 else if( !str[map.x] )
351 {
352 vg_error( "Unexpected EOF when parsing level!\n" );
353 return 0;
354 }
355 }
356
357 struct cell *row = arraddnptr( map.cells, map.x );
358 int cx = 0;
359 int reg_start = 0, reg_end = 0;
360
361 for(;;)
362 {
363 if( !*c )
364 break;
365
366 if( *c == ';' )
367 {
368 c ++;
369
370 // Parse attribs
371 if( *c != '\n' )
372 {
373 while( *c )
374 {
375 if( reg_start < reg_end )
376 {
377 if( *c >= 'a' && *c <= 'z' )
378 {
379 arrpush( map.cells[ map.io[ reg_start ] ].conditions, *c );
380 }
381 else
382 {
383 if( *c == ',' || *c == '\n' )
384 {
385 reg_start ++;
386
387 if( *c == '\n' )
388 break;
389 }
390 else
391 {
392 vg_error( "Unkown attrib '%c' (row: %u)\n", *c, map.y );
393 return 0;
394 }
395 }
396 }
397 else
398 {
399 vg_error( "Over-assigned values (row: %u)\n", map.y );
400 return 0;
401 }
402
403 c ++;
404 }
405 }
406
407 if( reg_start != reg_end )
408 {
409 vg_error( "Not enough values assigned (row: %u, %u of %u)\n", map.y, reg_start, reg_end );
410 return 0;
411 }
412
413 if( cx != map.x )
414 {
415 vg_error( "Map row underflow (row: %u, %u<%u)\n", map.y, cx, map.x );
416 return 0;
417 }
418
419 row = arraddnptr( map.cells, map.x );
420 cx = 0;
421 map.y ++;
422 reg_end = reg_start = arrlen( map.io );
423 }
424 else
425 {
426 if( cx == map.x )
427 {
428 vg_error( "Map row overflow (row: %u, %u>%u)\n", map.y, cx, map.x );
429 return 0;
430 }
431
432 row[ cx ].conditions = NULL;
433
434 // Parse the various cell types
435 if( *c == '+' || *c == '-' )
436 {
437 arrpush( map.io, cx + map.y*map.x );
438 row[ cx ++ ].flags = *c == '+'? CELL_FLAG_INPUT: CELL_FLAG_OUTPUT;
439 reg_end ++;
440 }
441 else if( *c == '#' )
442 {
443 row[ cx ++ ].flags = CELL_FLAG_WALL;
444 }
445 else
446 {
447 row[ cx ++ ].flags = 0x00;
448 }
449 }
450
451 c ++;
452 }
453
454 // Origin top left corner
455 map.origin[0] = -((float)map.x) * 0.5f;
456 map.origin[1] = -((float)map.y) * 0.5f;
457
458 float *offset_array = (float *)malloc( map.x*map.y*2*sizeof(float) );
459
460 for( int y = 0; y < map.y; y ++ )
461 {
462 for( int x = 0; x < map.x; x ++ )
463 {
464 float *coord = offset_array + (y*map.x+x)*2;
465 coord[0] = x;
466 coord[1] = y;
467 }
468 }
469
470 glBindBuffer( GL_ARRAY_BUFFER, map.tiles_vbo );
471 glBufferSubData( GL_ARRAY_BUFFER, 16*sizeof(float), map.x*map.y*2*sizeof(float), offset_array );
472
473 free( offset_array );
474 vg_success( "Map loaded! (%u:%u)\n", map.x, map.y );
475 return 1;
476 }
477
478 // Determines if tile at position co is contentious
479 static int map_tile_availible( int co[2] )
480 {
481 // Extract tiles area of influence as a 5x5 grid in bitfield format
482 u32 blob = 0x1000;
483 for( int y = vg_max( co[1]-2, 0 ); y < vg_min( map.y, co[1]+3 ); y ++ )
484 for( int x = vg_max( co[0]-2, 0 ); x < vg_min( map.x, co[0]+3 ); x ++ )
485 if( getiftile( (int[2]){ x, y }, CELL_FLAG_WALKABLE ) )
486 blob |= 0x1 << ((y-(co[1]-2))*5 + x-(co[0]-2));
487
488 // Run filter over center 3x3 grid to check for invalid configurations
489 // The kernel codes both the offsets for reaching each tile inside it, as well as the offsets
490 // to move the kernel as a whole.
491 int kernel[] = { 0, 1, 2, 5, 6, 7, 10, 11, 12 };
492 for( int i = 0; i < vg_list_size(kernel); i ++ )
493 if( blob & (0x1 << (6+kernel[i])) )
494 {
495 // Illegal moves list in bitfield format
496 u32 invalid[] = { 0x8E2, 0x63, 0xC6, 0xC60, 0x18C0, 0x862, 0x8C2 };
497 u32 window = blob >> kernel[i];
498
499 for( int j = 0; j < vg_list_size(invalid); j ++ )
500 if((window & invalid[j]) == invalid[j])
501 return 0;
502 }
503
504 return 1;
505 }
506
507 void vg_update(void)
508 {
509 // Update camera
510 float ratio = (float)vg_window_y / (float)vg_window_x;
511 float const size = 7.5f;
512
513 m3x3_projection( m_projection, -size, size, size*ratio, -size*ratio );
514 m3x3_identity( m_view );
515 m3x3_mul( m_projection, m_view, vg_pv );
516 vg_projection_update();
517
518 // Compute map update
519 for( int y = 0; y < map.y; y ++ )
520 {
521 for( int x = 0; x < map.x; x ++ )
522 {
523 struct cell *tile, *upper, *lower, *l, *r;
524 tile = gettile( (int [2]){ x, y } );
525 tile->flags &= ~(CELL_FLAG_SPLIT|CELL_FLAG_MERGE|CELL_FLAG_UPLVL);
526
527 if( tile->flags & CELL_FLAG_WALKABLE )
528 {
529 r = getiftile( (int[2]){ x+1, y }, CELL_FLAG_WALKABLE );
530 l = getiftile( (int[2]){ x-1, y }, CELL_FLAG_WALKABLE );
531
532 if( r && l )
533 {
534 upper = getiftile( (int[2]){ x, y-1 }, CELL_FLAG_WALKABLE );
535 lower = getiftile( (int[2]){ x, y+1 }, CELL_FLAG_WALKABLE );
536
537 if( upper )
538 {
539 tile->flags |= CELL_FLAG_MERGE | CELL_FLAG_UPLVL;
540 }
541
542 if( lower )
543 {
544 tile->flags |= CELL_FLAG_SPLIT;
545 l->flags |= CELL_FLAG_UPLVL;
546 r->flags |= CELL_FLAG_UPLVL;
547 }
548 }
549 }
550 }
551 }
552
553 map_reclassify();
554
555 v2f tile_pos;
556 v2_copy( vg_mouse_ws, tile_pos );
557 v2_sub( tile_pos, map.origin, tile_pos );
558
559 int tile_x = floorf( tile_pos[0] );
560 int tile_y = floorf( tile_pos[1] );
561
562 map.selected = ptile( (int [2]){tile_x, tile_y} );
563
564 if( map.playing )
565 {
566 if( vg_get_button_down( "go" ) )
567 {
568 map.playing = 0;
569 vg_info( "Ending!\n" );
570 }
571 }
572 else
573 {
574 if( vg_get_button_down( "go" ) )
575 {
576 map.playing = 1;
577 vg_info( "Starting!\n" );
578 }
579
580 if( map.selected )
581 {
582 map.select_valid = map_tile_availible( (int[2]){ tile_x, tile_y } );
583
584 if( map.select_valid )
585 {
586 if( vg_get_button_down("primary") )
587 {
588 if( map.selected->flags & CELL_FLAG_CANAL )
589 {
590 map.selected->flags &= ~(CELL_FLAG_CANAL);
591 }
592 else
593 {
594 map.selected->flags |= CELL_FLAG_CANAL;
595 }
596 }
597 }
598 }
599 }
600 }
601
602 GLuint tile_vao;
603 GLuint tile_vbo;
604 GLuint fish_texture;
605
606 void vg_render(void)
607 {
608 glViewport( 0,0, vg_window_x, vg_window_y );
609
610 //glEnable( GL_DEPTH_TEST );
611 glClearColor( 0.94f, 0.94f, 0.94f, 1.0f );
612 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
613
614 glBindVertexArray( map.tiles_vao );
615
616 //map_update_visual();
617
618 SHADER_USE( tilemap_shader );
619 glUniformMatrix3fv( SHADER_UNIFORM( tilemap_shader, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
620
621 glUniform1i( SHADER_UNIFORM( tilemap_shader, "uTexTiles" ), 0 );
622 glActiveTexture( GL_TEXTURE0 );
623 glBindTexture( GL_TEXTURE_2D, map.tile_texture );
624
625 glUniform1i( SHADER_UNIFORM( tilemap_shader, "uTexRipples" ), 1 );
626 glActiveTexture( GL_TEXTURE1 );
627 glBindTexture( GL_TEXTURE_2D, map.flow_texture );
628
629 glUniform2fv( SHADER_UNIFORM( tilemap_shader, "uOrigin" ), 1, map.origin );
630 glUniform1f( SHADER_UNIFORM( tilemap_shader, "uTime" ), vg_time * 0.5f );
631
632 glDrawArraysInstanced( GL_TRIANGLES, 0, 6, map.x*map.y );
633
634 /*
635 SHADER_USE( fish_shader );
636 glUniformMatrix3fv( SHADER_UNIFORM( fish_shader, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
637 glUniform1i( SHADER_UNIFORM( fish_shader, "uTexMain" ), 0 );
638 glActiveTexture( GL_TEXTURE0 );
639 glBindTexture( GL_TEXTURE_2D, fish_texture );
640 glUniform3f( SHADER_UNIFORM( fish_shader, "uPosition" ), 0.0f, 0.0f, floorf( vg_time*20.0f ) );
641 glUniform3f( SHADER_UNIFORM( fish_shader, "uColour" ), 1.0f, 0.1f, 0.1f );
642
643 glEnable( GL_BLEND );
644 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
645 glBlendEquation( GL_FUNC_ADD );
646
647 glDrawArrays( GL_TRIANGLES, 0, 6 );
648
649 glDisable( GL_BLEND );
650 */
651 }
652
653 void vg_register(void)
654 {
655 SHADER_INIT( colour_shader );
656 SHADER_INIT( tilemap_shader );
657 SHADER_INIT( fish_shader );
658 }
659
660 void vg_start(void)
661 {
662 glGenVertexArrays( 1, &tile_vao );
663 glGenBuffers( 1, &tile_vbo );
664
665 float quad_mesh[] =
666 {
667 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
668 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f,
669
670 // Padding
671 0.0f, 0.0f, 0.0f, 0.0f
672 };
673
674 glBindVertexArray( tile_vao );
675 glBindBuffer( GL_ARRAY_BUFFER, tile_vbo );
676 glBufferData
677 (
678 GL_ARRAY_BUFFER,
679 sizeof( quad_mesh ),
680 quad_mesh,
681 GL_STATIC_DRAW
682 );
683
684 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0 );
685 glEnableVertexAttribArray( 0 );
686
687 VG_CHECK_GL();
688
689 // Create map buffers
690 glGenVertexArrays( 1, &map.tiles_vao );
691 glGenBuffers( 1, &map.tiles_vbo );
692
693 glBindVertexArray( map.tiles_vao );
694 glBindBuffer( GL_ARRAY_BUFFER, map.tiles_vbo );
695 glBufferData( GL_ARRAY_BUFFER,
696 sizeof( quad_mesh ) +
697 sizeof( float )*2 * 1024 +
698 sizeof( u8 )*4 * 1024,
699 NULL,
700 GL_DYNAMIC_DRAW
701 );
702
703 glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof( quad_mesh ), quad_mesh );
704
705 // Base quad
706 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (void*)0 );
707 glEnableVertexAttribArray( 0 );
708
709 // Offset, data arrays (instancing)
710 glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (void*)(sizeof(quad_mesh)) );
711 glEnableVertexAttribArray( 1 );
712 glVertexAttribDivisor( 1, 1 );
713
714 glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE, GL_FALSE, 4, (void*)(sizeof(quad_mesh)+sizeof(float)*2*1024) );
715 glEnableVertexAttribArray( 2 );
716 glVertexAttribDivisor( 2, 1 );
717
718 map.tile_texture = vg_tex2d_rgba( "textures/rivertiles_flowm.tga" );
719 vg_tex2d_nearest();
720 vg_tex2d_repeat();
721
722 map.flow_texture = vg_tex2d_rgba( "textures/rivertiles_ripple.tga" );
723 vg_tex2d_nearest();
724 vg_tex2d_repeat();
725
726 fish_texture = vg_tex2d_rgba( "textures/fishe_swim.tga" );
727 vg_tex2d_nearest();
728 vg_tex2d_repeat();
729
730 map_load
731 (
732 "##-#####-##;aaa,aa\n"
733 "# #;\n"
734 "# #;\n"
735 "# #;\n"
736 "# #;\n"
737 "# #;\n"
738 "# #;\n"
739 "##+#####+##;aa,aaa\n"
740 );
741 }
742
743 void vg_free(void)
744 {
745 map_free();
746
747 glDeleteVertexArrays( 1, &tile_vao );
748 glDeleteVertexArrays( 1, &map.tiles_vao );
749
750 glDeleteBuffers( 1, &tile_vbo );
751 glDeleteBuffers( 1, &map.tiles_vbo );
752
753 glDeleteTextures( 1, &map.tile_texture );
754 glDeleteTextures( 1, &map.flow_texture );
755 }
756
757 void vg_ui(void)
758 {
759
760 }