1 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
6 #define CELL_SHEET_X 512
7 #define CELL_SHEET_Y 512
9 SHADER_DEFINE( colour_shader
,
12 "layout (location=0) in vec2 a_co;"
18 " vec4 vert_pos = uPv * uMdl * vec4( a_co.x, 0.0, a_co.y, 1.0 );"
19 " gl_Position = vert_pos;"
24 "uniform vec4 uColour;"
28 " FragColor = uColour;"
31 UNIFORMS({ "uPv", "uMdl", "uColour" })
34 SHADER_DEFINE( tilemap_shader
,
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
41 "uniform vec2 uOrigin;"
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);"
53 "uniform sampler2D uTexTiles;"
54 "uniform sampler2D uTexRipples;"
55 "uniform float uTime;"
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 );"
70 UNIFORMS({ "uPv", "uTexTiles", "uTexRipples", "uTime", "uOrigin" })
77 int main( int argc
, char *argv
[] )
79 vg_init( argc
, argv
, "FishLadder" );
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
124 struct cell
*selected
;
153 static void map_free(void)
155 for( int i
= 0; i
< arrlen( map
.io
); i
++ )
157 arrfree( map
.cells
[ map
.io
[i
] ].conditions
);
160 arrfree( map
.cells
);
168 static struct cell
*map_tile( int pos
[2] )
170 return map
.cells
+ pos
[1]*map
.x
+ pos
[0];
173 static struct cell
*map_tile_at( int pos
[2] )
175 if( pos
[0] >= 0 && pos
[0] < map
.x
&& pos
[1] >= 0 && pos
[1] < map
.y
)
176 return map
.cells
+ pos
[1]*map
.x
+ pos
[0];
180 static struct cell
*map_tile_at_cond( int pos
[2], u32 flags
)
182 struct cell
*cell
= map_tile_at( pos
);
183 if( cell
&& (cell
->flags
& flags
) )
189 static void map_tile_coords_from_index( int i
, int coords
[2] )
191 coords
[0] = i
% map
.x
;
192 coords
[1] = (i
- coords
[0])/map
.x
;
195 static void map_stack_refresh(void)
197 for( int i
= 0; i
< map
.x
*map
.y
; i
++ )
198 map
.cells
[i
].flags
&= ~CELL_FLAG_VISITED
;
201 static void map_stack_init( int coords
[2] )
204 map
.stack
.frames
[0].i
= 0;
205 map
.stack
.frames
[0].x
= coords
[0];
206 map
.stack
.frames
[0].y
= coords
[1];
209 static struct cell
*map_stack_next(void)
211 struct cell
*tile
= NULL
;
215 struct vframe
*frame
= &map
.stack
.frames
[ map
.stack
.level
];
217 int output_dirs
[][2] = { {0,1}, {-1,0}, {1,0} };
221 int *dir
= output_dirs
[ frame
->i
];
222 tile
= map_tile_at_cond( (int[2]){frame
->x
+dir
[0], frame
->y
+dir
[1]}, CELL_FLAG_WALKABLE
);
224 if( tile
&& !(tile
->flags
& CELL_FLAG_VISITED
) )
228 frame
[1].x
= frame
[0].x
+dir
[0];
229 frame
[1].y
= frame
[0].y
+dir
[1];
231 tile
->flags
|= CELL_FLAG_VISITED
;
246 if( map
.stack
.level
< 0 )
254 static void map_stack_current_coords( int coords
[2], int offset
)
256 coords
[0] = map
.stack
.frames
[ map
.stack
.level
+offset
].x
;
257 coords
[1] = map
.stack
.frames
[ map
.stack
.level
+offset
].y
;
260 static void map_update_visual(void)
264 static int compute_flow_counter
= 0;
265 compute_flow_counter
^= 0x1;
267 for( int i
= 0; i
< map
.y
*map
.x
; i
++ )
269 struct cell
*cell
= map
.cells
+ i
;
271 cell
->flowing
[compute_flow_counter
] = cell
->flowing
[compute_flow_counter
^0x1];
273 if( !map
.cells
[i
].source_count
)
274 cell
->flowing
[ compute_flow_counter
] = vg_max( cell
->flowing
[ compute_flow_counter
] - 10, 0 );
276 map
.cells
[i
].source_count
= 0;
279 for( int y
= 0; y
< map
.y
; y
++ )
281 for( int x
= 0; x
< map
.x
; x
++ )
283 struct cell
*cur
= map
.cells
+ y
*map
.x
+ x
;
284 u8
*cellbytes
= celldata
+ (y
*map
.x
+x
)*4;
286 if( cur
->flags
& CELL_FLAG_WALKABLE
)
288 struct cell
*a
, *b
, *c
, *d
;
290 a
= map_tile_at_cond( (int[2]){ x
,y
+1 }, CELL_FLAG_WALKABLE
);
291 b
= map_tile_at_cond( (int[2]){ x
+1,y
}, CELL_FLAG_WALKABLE
);
292 c
= map_tile_at_cond( (int[2]){ x
,y
-1 }, CELL_FLAG_WALKABLE
);
293 d
= map_tile_at_cond( (int[2]){ x
-1,y
}, CELL_FLAG_WALKABLE
);
295 u32 config
= (a
?0x1:0x0) | (b
?0x2:0x0) | (c
?0x4:0x0) | (d
?0x8:0x0);
296 cellbytes
[ 0 ] = config
;
298 if( cur
->flags
& CELL_FLAG_OUTPUT
)
299 cur
->flowing
[ compute_flow_counter
] = 128;
303 // TODO: Random background tiles
309 int const k_rate_flow
= 16;
312 for( int i
= 0; i
< arrlen( map
.io
); i
++ )
315 if( map
.cells
[ map
.io
[i
] ].flags
& CELL_FLAG_OUTPUT
)
317 map_tile_coords_from_index( map
.io
[i
], inputcoord
);
318 map_stack_init( inputcoord
);
319 struct cell
*cell
= map_tile_at( inputcoord
);
325 map_stack_current_coords( cr
, 0 );
327 u8
*cellbytes
= celldata
+ (cr
[1]*map
.x
+cr
[0])*4;
329 int outflow
= cell
->flowing
[ compute_flow_counter
^ 0x1 ];
330 int sourcing
= outflow
? 1: 0;
331 int outrate
= outflow
== 128? k_rate_flow
: 0;
333 struct cell
*a
, *b
, *d
;
334 a
= map_tile( (int[2]){ cr
[0], cr
[1]+1 } );
335 b
= map_tile( (int[2]){ cr
[0]+1, cr
[1] } );
336 d
= map_tile( (int[2]){ cr
[0]-1, cr
[1] } );
338 int compute_l
= 0, compute_r
= 0;
340 switch( cellbytes
[0] )
343 case 1: case 5: case 11: case 9: case 3:
344 a
->flowing
[ compute_flow_counter
] += outrate
;
345 a
->source_count
+= sourcing
;
347 case 2: case 6: compute_r
= 1; break;
348 case 8: case 12: compute_l
= 1; break;
349 case 10: case 14: compute_l
= 1; compute_r
= 1; break;
353 if( compute_r
&& (celldata
[ (cr
[1]*map
.x
+cr
[0]+1)*4 ] != 14) )
355 b
->flowing
[ compute_flow_counter
] += outrate
;
356 b
->source_count
+= sourcing
;
359 if( compute_l
&& (celldata
[ (cr
[1]*map
.x
+cr
[0]-1)*4 ] != 14) )
361 d
->flowing
[ compute_flow_counter
] += outrate
;
362 d
->source_count
+= sourcing
;
365 if( cellbytes
[0] == 10 )
368 map_stack_current_coords( crl
, -1 );
376 while( (cell
= map_stack_next()) );
380 for( int i
= 0; i
< map
.y
*map
.x
; i
++ )
382 map
.cells
[i
].flowing
[ compute_flow_counter
] = vg_min( 128, map
.cells
[i
].flowing
[ compute_flow_counter
] );
383 celldata
[ i
*4+2 ] = map
.cells
[i
].flowing
[ compute_flow_counter
];
386 glBindBuffer( GL_ARRAY_BUFFER
, map
.tiles_vbo
);
387 glBufferSubData( GL_ARRAY_BUFFER
, 16*sizeof(float) + 1024*2*sizeof(float), map
.x
*map
.y
*4, celldata
);
390 static int map_load( const char *str
)
399 if( str
[map
.x
] == ';' )
401 else if( !str
[map
.x
] )
403 vg_error( "Unexpected EOF when parsing level!\n" );
408 struct cell
*row
= arraddnptr( map
.cells
, map
.x
);
410 int reg_start
= 0, reg_end
= 0;
426 if( reg_start
< reg_end
)
428 if( *c
>= 'a' && *c
<= 'z' )
430 arrpush( map
.cells
[ map
.io
[ reg_start
] ].conditions
, *c
);
434 if( *c
== ',' || *c
== '\n' )
443 vg_error( "Unkown attrib '%c' (row: %u)\n", *c
, map
.y
);
450 vg_error( "Over-assigned values (row: %u)\n", map
.y
);
458 if( reg_start
!= reg_end
)
460 vg_error( "Not enough values assigned (row: %u, %u of %u)\n", map
.y
, reg_start
, reg_end
);
466 vg_error( "Map row underflow (row: %u, %u<%u)\n", map
.y
, cx
, map
.x
);
470 row
= arraddnptr( map
.cells
, map
.x
);
473 reg_end
= reg_start
= arrlen( map
.io
);
479 vg_error( "Map row overflow (row: %u, %u>%u)\n", map
.y
, cx
, map
.x
);
483 row
[ cx
].conditions
= NULL
;
484 row
[ cx
].flowing
[ 0 ] = 0;
485 row
[ cx
].source_count
= 0;
487 // Parse the various cell types
488 if( *c
== '+' || *c
== '-' )
490 arrpush( map
.io
, cx
+ map
.y
*map
.x
);
491 row
[ cx
++ ].flags
= *c
== '+'? CELL_FLAG_INPUT
: CELL_FLAG_OUTPUT
;
496 row
[ cx
++ ].flags
= CELL_FLAG_WALL
;
500 row
[ cx
++ ].flags
= 0x00;
507 // Origin top left corner
508 map
.origin
[0] = -((float)map
.x
) * 0.5f
;
509 map
.origin
[2] = -((float)map
.y
) * 0.5f
;
511 float *offset_array
= (float *)malloc( map
.x
*map
.y
*2*sizeof(float) );
513 for( int y
= 0; y
< map
.y
; y
++ )
515 for( int x
= 0; x
< map
.x
; x
++ )
517 float *coord
= offset_array
+ (y
*map
.x
+x
)*2;
523 glBindBuffer( GL_ARRAY_BUFFER
, map
.tiles_vbo
);
524 glBufferSubData( GL_ARRAY_BUFFER
, 16*sizeof(float), map
.x
*map
.y
*2*sizeof(float), offset_array
);
526 free( offset_array
);
527 vg_success( "Map loaded! (%u:%u)\n", map
.x
, map
.y
);
531 static int map_tile_availible( int co
[2] )
533 // Extract 5x5 grid surrounding tile
535 for( int y
= vg_max( co
[1]-2, 0 ); y
< vg_min( map
.y
, co
[1]+3 ); y
++ )
536 for( int x
= vg_max( co
[0]-2, 0 ); x
< vg_min( map
.x
, co
[0]+3 ); x
++ )
538 struct cell
*cell
= map_tile( (int[2]){ x
, y
} );
540 if( cell
&& (cell
->flags
& CELL_FLAG_WALKABLE
) )
541 blob
|= 0x1 << ((y
-(co
[1]-2))*5 + x
-(co
[0]-2));
544 // Run filter over center 3x3 grid to check for invalid configurations
545 int kernel
[] = { 0, 1, 2, 5, 6, 7, 10, 11, 12 };
546 for( int i
= 0; i
< vg_list_size(kernel
); i
++ )
548 if( blob
& (0x1 << (6+kernel
[i
])) )
550 // (reference window: 0x1CE7) Illegal moves
559 u32 invalid
[] = { 0x8E2, 0x63, 0xC6, 0xC60, 0x18C0, 0x862, 0x8C2 };
560 u32 window
= blob
>> kernel
[i
];
562 for( int j
= 0; j
< vg_list_size(invalid
); j
++ )
563 if((window
& invalid
[j
]) == invalid
[j
])
574 float ratio
= (float)vg_window_y
/ (float)vg_window_x
;
575 float const size
= 7.5f
;
576 glm_ortho( -size
, size
, -size
*ratio
, size
*ratio
, 0.01f
, 150.f
, m_projection
);
578 glm_mat4_identity( m_view
);
579 glm_translate_z( m_view
, -10.f
);
580 glm_rotate_x( m_view
, 1.5708f
, m_view
);
582 glm_mat4_mul( m_projection
, m_view
, vg_pv
);
584 // Compute map update
585 for( int y
= 0; y
< map
.y
; y
++ )
587 for( int x
= 0; x
< map
.x
; x
++ )
589 struct cell
*tile
, *upper
, *lower
, *l
, *r
;
590 tile
= map_tile_at( (int [2]){ x
, y
} );
591 tile
->flags
&= ~(CELL_FLAG_SPLIT
|CELL_FLAG_MERGE
|CELL_FLAG_UPLVL
);
593 if( tile
->flags
& CELL_FLAG_WALKABLE
)
595 r
= map_tile_at_cond( (int[2]){ x
+1, y
}, CELL_FLAG_WALKABLE
);
596 l
= map_tile_at_cond( (int[2]){ x
-1, y
}, CELL_FLAG_WALKABLE
);
600 upper
= map_tile_at_cond( (int[2]){ x
, y
-1 }, CELL_FLAG_WALKABLE
);
601 lower
= map_tile_at_cond( (int[2]){ x
, y
+1 }, CELL_FLAG_WALKABLE
);
605 tile
->flags
|= CELL_FLAG_MERGE
| CELL_FLAG_UPLVL
;
610 tile
->flags
|= CELL_FLAG_SPLIT
;
611 l
->flags
|= CELL_FLAG_UPLVL
;
612 r
->flags
|= CELL_FLAG_UPLVL
;
619 // Compute classification
623 for( int i = 0; i < arrlen( map.io ); i ++ )
625 struct *cell cell = &map.cells[ map.io ];
628 if( cell->flags & CELL_FLAG_INPUT )
630 map_tile_coords_from_index( map.io, coords );
631 map_stack_init( coords );
635 if( cell->flags & CELL_FLAG_CONNECTOR )
640 while( (cell = map_stack_next()) );
649 vec4 vp
= { 0.f
, 0.f
, vg_window_x
, vg_window_y
};
650 glm_mat4_inv( vg_pv
, pv_inverse
);
651 glm_unprojecti( (vec3
){ vg_mouse_x
, vg_window_y
-vg_mouse_y
, -1.f
}, pv_inverse
, vp
, ray_dir
);
652 glm_unprojecti( (vec3
){ vg_mouse_x
, vg_window_y
-vg_mouse_y
, 0.f
}, pv_inverse
, vp
, ray_origin
);
653 glm_vec3_sub( ray_dir
, ray_origin
, ray_dir
);
655 // Get floor tile intersection
656 float ray_t
= -ray_origin
[1] / ray_dir
[1];
659 glm_vec3_copy( ray_origin
, tile_pos
);
660 glm_vec3_muladds( ray_dir
, ray_t
, tile_pos
);
661 glm_vec3_sub( tile_pos
, map
.origin
, tile_pos
);
663 int tile_x
= floorf( tile_pos
[0] );
664 int tile_y
= floorf( tile_pos
[2] );
666 map
.selected
= map_tile_at( (int [2]){tile_x
, tile_y
} );
670 static int fish_counter
= 0;
673 if( fish_counter
> 20 )
677 // Advance characters
678 for( int i
= 0; i
< map
.num_fishes
; i
++ )
680 struct fish
*fish
= map
.fishes
+ i
;
685 struct cell
*tile
, *next
;
686 tile
= map_tile_at( fish
->co
);
688 if( tile
->flags
& CELL_FLAG_OUTPUT
)
690 vg_info( "Fish got zucced (%d)\n", i
);
696 if( tile
->flags
& CELL_FLAG_SPLIT
)
699 int new_dir
[][2] = { {0,-1},{1,0},{-1,0} };
702 for( int j
= 0; j
< 3; j
++ )
704 test_dir
= new_dir
[ tile
->state
];
705 tile
->state
= (tile
->state
+1)%3;
707 next
= map_tile_at( (int[2]){ fish
->co
[0]+test_dir
[0], fish
->co
[1]+test_dir
[1] } );
708 if( next
&& (next
->flags
& (CELL_FLAG_WALKABLE
)) )
710 fish
->dir
[0] = test_dir
[0];
711 fish
->dir
[1] = test_dir
[1];
718 next
= map_tile_at( (int[2]){ fish
->co
[0]+fish
->dir
[0], fish
->co
[1]+fish
->dir
[1] } );
719 if( !next
|| (next
&& !(next
->flags
& CELL_FLAG_WALKABLE
)) )
727 vg_info( "Fish died! (%d)\n", i
);
733 fish
->co
[0] += fish
->dir
[0];
734 fish
->co
[1] += fish
->dir
[1];
738 for( int i
= 0; i
< arrlen( map
.io
); i
++ )
740 struct cell
*input
= &map
.cells
[ map
.io
[i
] ];
742 if( input
->flags
& CELL_FLAG_INPUT
)
744 if( input
->state
< arrlen( input
->conditions
) )
746 struct fish
*fish
= &map
.fishes
[ map
.num_fishes
];
747 map_tile_coords_from_index( map
.io
[i
], fish
->co
);
749 int output_dirs
[][2] = { {0,-1}, {-1,0}, {1,0} };
752 for( int i
= 0; i
< vg_list_size( output_dirs
); i
++ )
754 int *dir
= output_dirs
[i
];
755 struct cell
*next
= map_tile_at( (int[2]){ fish
->co
[0]+dir
[0], fish
->co
[1]+dir
[1] } );
756 if( next
&& next
->flags
& CELL_FLAG_CANAL
)
758 fish
->dir
[0] = dir
[0];
759 fish
->dir
[1] = dir
[1];
774 vg_info( "There are now %u active fish\n", map
.num_fishes
);
777 if( vg_get_button_down( "go" ) )
782 vg_info( "Ending!\n" );
787 if( vg_get_button_down( "go" ) )
792 for( int i
= 0; i
< map
.x
*map
.y
; i
++ )
793 map
.cells
[ i
].state
= 0;
795 vg_info( "Starting!\n" );
800 map
.select_valid
= map_tile_availible( (int[2]){ tile_x
, tile_y
} );
802 if( map
.select_valid
)
804 if( vg_get_button_down("primary") )
806 if( map
.selected
->flags
& CELL_FLAG_CANAL
)
808 map
.selected
->flags
&= ~(CELL_FLAG_CANAL
);
812 map
.selected
->flags
|= CELL_FLAG_CANAL
;
825 glViewport( 0,0, vg_window_x
, vg_window_y
);
827 //glEnable( GL_DEPTH_TEST );
828 glClearColor( 0.94f
, 0.94f
, 0.94f
, 1.0f
);
829 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
832 glBindVertexArray( tile_vao );
834 SHADER_USE( colour_shader );
835 glUniformMatrix4fv( SHADER_UNIFORM( colour_shader, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
837 for( int y = 0; y < map.y; y ++ )
839 for( int x = 0; x < map.x; x ++ )
841 glm_mat4_identity( m_mdl );
842 glm_translate( m_mdl,
844 map.origin[0] + (float)x,
846 map.origin[2] + (float)y
849 glUniformMatrix4fv( SHADER_UNIFORM( colour_shader, "uMdl" ), 1, GL_FALSE, (float *)m_mdl );
851 struct cell *cell = &map.cells[ y*map.x+x ];
853 vec4 colour = { 0.7f, 0.7f, 0.7f, 1.f };
855 if( cell->flags & CELL_FLAG_INPUT ) glm_vec3_copy( (vec3){ 0.9f,0.5f,0.5f }, colour );
856 else if( cell->flags & CELL_FLAG_OUTPUT ) glm_vec3_copy( (vec3){ 0.5f,0.9f,0.5f }, colour );
857 else if( cell->flags & CELL_FLAG_WALL ) glm_vec3_copy( (vec3){ 0.1f,0.1f,0.1f }, colour );
858 else if( cell->flags & CELL_FLAG_CANAL ) glm_vec3_copy( (vec3){ 0.5f,0.5f,0.8f }, colour );
860 if( cell->flags & CELL_FLAG_SPLIT )
861 glm_vec3_copy( (vec3){ 0.6f, 0.f, 0.9f }, colour );
862 else if( cell->flags & CELL_FLAG_MERGE )
863 glm_vec3_copy( (vec3){ 0.f, 0.6f, 0.8f }, colour );
865 if( map.selected == cell )
867 if( !map.select_valid )
868 glm_vec3_copy( (vec3){ 1.f, 0.f, 0.f }, colour );
870 float flash = sinf( vg_time*2.5f ) * 0.25f + 0.75f;
871 glm_vec3_scale( colour, flash, colour );
874 glUniform4fv( SHADER_UNIFORM( colour_shader, "uColour" ), 1, colour );
875 glDrawArrays( GL_TRIANGLES, 0, 6 );
879 glUniform4f( SHADER_UNIFORM( colour_shader, "uColour" ), 1.f, 0.f, 1.f, 1.f );
881 for( int i = 0; i < map.num_fishes; i ++ )
883 struct fish *fish = map.fishes + i;
887 glm_mat4_identity( m_mdl );
888 glm_translate( m_mdl,
890 map.origin[0] + (float)fish->co[0] + 0.5f,
892 map.origin[2] + (float)fish->co[1] + 0.5f
895 glm_scale_uni( m_mdl, 0.2f );
896 glUniformMatrix4fv( SHADER_UNIFORM( colour_shader, "uMdl" ), 1, GL_FALSE, (float *)m_mdl );
897 glDrawArrays( GL_TRIANGLES, 0, 6 );
902 glBindVertexArray( map
.tiles_vao
);
906 SHADER_USE( tilemap_shader
);
907 glUniformMatrix4fv( SHADER_UNIFORM( tilemap_shader
, "uPv" ), 1, GL_FALSE
, (float *)vg_pv
);
909 glUniform1i( SHADER_UNIFORM( tilemap_shader
, "uTexTiles" ), 0 );
910 glActiveTexture( GL_TEXTURE0
);
911 glBindTexture( GL_TEXTURE_2D
, map
.tile_texture
);
913 glUniform1i( SHADER_UNIFORM( tilemap_shader
, "uTexRipples" ), 1 );
914 glActiveTexture( GL_TEXTURE1
);
915 glBindTexture( GL_TEXTURE_2D
, map
.flow_texture
);
917 glUniform2f( SHADER_UNIFORM( tilemap_shader
, "uOrigin" ), map
.origin
[0], map
.origin
[2] );
918 glUniform1f( SHADER_UNIFORM( tilemap_shader
, "uTime" ), vg_time
* 0.5f
);
920 glDrawArraysInstanced( GL_TRIANGLES
, 0, 6, map
.x
*map
.y
);
923 void vg_register(void)
925 SHADER_INIT( colour_shader
);
926 SHADER_INIT( tilemap_shader
);
931 glGenVertexArrays( 1, &tile_vao
);
932 glGenBuffers( 1, &tile_vbo
);
936 0.0f
, 0.0f
, 0.0f
, 1.0f
, 1.0f
, 1.0f
,
937 0.0f
, 0.0f
, 1.0f
, 1.0f
, 1.0f
, 0.0f
,
940 0.0f
, 0.0f
, 0.0f
, 0.0f
943 glBindVertexArray( tile_vao
);
944 glBindBuffer( GL_ARRAY_BUFFER
, tile_vbo
);
953 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
, 2 * sizeof(float), (void*)0 );
954 glEnableVertexAttribArray( 0 );
958 // Create map buffers
959 glGenVertexArrays( 1, &map
.tiles_vao
);
960 glGenBuffers( 1, &map
.tiles_vbo
);
962 glBindVertexArray( map
.tiles_vao
);
963 glBindBuffer( GL_ARRAY_BUFFER
, map
.tiles_vbo
);
964 glBufferData( GL_ARRAY_BUFFER
,
965 sizeof( quad_mesh
) +
966 sizeof( float )*2 * 1024 +
967 sizeof( u8
)*4 * 1024,
972 glBufferSubData( GL_ARRAY_BUFFER
, 0, sizeof( quad_mesh
), quad_mesh
);
975 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
, 2*sizeof(float), (void*)0 );
976 glEnableVertexAttribArray( 0 );
978 // Offset, data arrays (instancing)
979 glVertexAttribPointer( 1, 2, GL_FLOAT
, GL_FALSE
, 2*sizeof(float), (void*)(sizeof(quad_mesh
)) );
980 glEnableVertexAttribArray( 1 );
981 glVertexAttribDivisor( 1, 1 );
983 glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE
, GL_FALSE
, 4, (void*)(sizeof(quad_mesh
)+sizeof(float)*2*1024) );
984 glEnableVertexAttribArray( 2 );
985 glVertexAttribDivisor( 2, 1 );
987 map
.tile_texture
= vg_tex2d_rgba( "textures/rivertiles_flowm.tga" );
991 map
.flow_texture
= vg_tex2d_rgba( "textures/rivertiles_ripple.tga" );
997 "##-#####-##;aaa,aa\n"
1004 "##+#####+##;aa,aaa\n"
1012 glDeleteVertexArrays( 1, &tile_vao
);
1013 glDeleteVertexArrays( 1, &map
.tiles_vao
);
1015 glDeleteBuffers( 1, &tile_vbo
);
1016 glDeleteBuffers( 1, &map
.tiles_vbo
);
1018 glDeleteTextures( 1, &map
.tile_texture
);
1019 glDeleteTextures( 1, &map
.flow_texture
);