1 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
6 SHADER_DEFINE( colour_shader
,
9 "layout (location=0) in vec3 a_co;"
15 " vec4 vert_pos = uPv * uMdl * vec4( a_co, 1.0 );"
16 " gl_Position = vert_pos;"
21 "uniform vec4 uColour;"
25 " FragColor = uColour;"
28 UNIFORMS({ "uPv", "uMdl", "uColour" })
35 int main( int argc
, char *argv
[] )
37 vg_init( argc
, argv
, "FishLadder" );
40 #define CELL_FLAG_INPUT 0x1
41 #define CELL_FLAG_OUTPUT 0x2
42 #define CELL_FLAG_IO (CELL_FLAG_INPUT|CELL_FLAG_OUTPUT)
43 #define CELL_FLAG_WALL 0x4
44 #define CELL_FLAG_HOVER 0x8
45 #define CELL_FLAG_ITER 0x10
46 #define CELL_FLAG_CANAL 0x20
47 #define CELL_FLAG_CONNECTOR 0x40 /* Does this cell split and have an incoming vertical connection? */
48 #define CELL_FLAG_WALKABLE (CELL_FLAG_IO|CELL_FLAG_CANAL)
49 #define CELL_FLAG_VISITED 0x80
78 struct cell
*selected
;
101 static void map_free(void)
103 for( int i
= 0; i
< arrlen( map
.io
); i
++ )
105 arrfree( map
.cells
[ map
.io
[i
] ].conditions
);
108 arrfree( map
.cells
);
116 static struct cell
*map_tile_at( int pos
[2] )
118 if( pos
[0] >= 0 && pos
[0] < map
.x
&& pos
[1] >= 0 && pos
[1] < map
.y
)
119 return map
.cells
+ pos
[1]*map
.x
+ pos
[0];
123 void map_tile_coords_from_index( int i
, int coords
[2] )
125 coords
[0] = i
% map
.x
;
126 coords
[1] = (i
- coords
[0])/map
.x
;
129 static void map_stack_refresh(void)
131 for( int i
= 0; i
< map
.x
*map
.y
; i
++ )
132 map
.cells
[i
].flags
&= ~CELL_FLAG_VISITED
;
135 static void map_stack_init( int coords
[2] )
138 map
.stack
.frames
[0].i
= 0;
139 map
.stack
.frames
[0].x
= coords
[0];
140 map
.stack
.frames
[0].y
= coords
[1];
143 static struct cell
*map_stack_next(void)
145 struct cell
*tile
= NULL
;
149 struct vframe
*frame
= &map
.stack
.frames
[ map
.stack
.level
];
151 int output_dirs
[][2] = { {0,-1}, {-1,0}, {1,0} };
155 int *dir
= output_dirs
[ frame
->i
];
156 tile
= map_tile_at( (int[2]){frame
->x
+dir
[0], frame
->y
+dir
[1]} );
159 if( tile
&& !(tile
->flags
& CELL_FLAG_VISITED
) )
163 frame
[1].x
= frame
[0].x
+dir
[0];
164 frame
[1].y
= frame
[0].y
+dir
[1];
174 if( map
.stack
.level
< 0 )
182 static int map_load( const char *str
)
191 if( str
[map
.x
] == ';' )
193 else if( !str
[map
.x
] )
195 vg_error( "Unexpected EOF when parsing level!\n" );
200 struct cell
*row
= arraddnptr( map
.cells
, map
.x
);
202 int reg_start
= 0, reg_end
= 0;
218 if( reg_start
< reg_end
)
220 if( *c
>= 'a' && *c
<= 'z' )
222 arrpush( map
.cells
[ map
.io
[ reg_start
] ].conditions
, *c
);
226 if( *c
== ',' || *c
== '\n' )
235 vg_error( "Unkown attrib '%c' (row: %u)\n", *c
, map
.y
);
242 vg_error( "Over-assigned values (row: %u)\n", map
.y
);
250 if( reg_start
!= reg_end
)
252 vg_error( "Not enough values assigned (row: %u, %u of %u)\n", map
.y
, reg_start
, reg_end
);
258 vg_error( "Map row underflow (row: %u, %u<%u)\n", map
.y
, cx
, map
.x
);
262 row
= arraddnptr( map
.cells
, map
.x
);
265 reg_end
= reg_start
= arrlen( map
.io
);
271 vg_error( "Map row overflow (row: %u, %u>%u)\n", map
.y
, cx
, map
.x
);
275 row
[ cx
].conditions
= NULL
;
277 // Parse the various cell types
278 if( *c
== '+' || *c
== '-' )
280 arrpush( map
.io
, cx
+ map
.y
*map
.x
);
281 row
[ cx
++ ].flags
= *c
== '+'? CELL_FLAG_INPUT
: CELL_FLAG_OUTPUT
;
286 row
[ cx
++ ].flags
= CELL_FLAG_WALL
;
290 row
[ cx
++ ].flags
= 0x00;
297 // Origin top left corner
298 map
.origin
[0] = -((float)map
.x
) * 0.5f
;
299 map
.origin
[2] = -((float)map
.y
) * 0.5f
;
301 vg_success( "Map loaded! (%u:%u)\n", map
.x
, map
.y
);
305 static int map_tile_availible( int co
[2] )
307 // Extract 5x5 grid surrounding tile
309 for( int y
= vg_max( co
[1]-2, 0 ); y
< vg_min( map
.y
, co
[1]+3 ); y
++ )
310 for( int x
= vg_max( co
[0]-2, 0 ); x
< vg_min( map
.x
, co
[0]+3 ); x
++ )
312 struct cell
*cell
= map_tile_at( (int[2]){ x
, y
} );
314 if( cell
&& (cell
->flags
& CELL_FLAG_WALKABLE
) )
315 blob
|= 0x1 << ((y
-(co
[1]-2))*5 + x
-(co
[0]-2));
318 // Run filter over center 3x3 grid to check for invalid configurations
319 int kernel
[] = { 0, 1, 2, 5, 6, 7, 10, 11, 12 };
320 for( int i
= 0; i
< vg_list_size(kernel
); i
++ )
322 if( blob
& (0x1 << (6+kernel
[i
])) )
324 // (reference window: 0x1CE7) Illegal moves
333 u32 invalid
[] = { 0x8E2, 0x63, 0xC6, 0xC60, 0x18C0, 0x862, 0x8C2 };
334 u32 window
= blob
>> kernel
[i
];
336 for( int j
= 0; j
< vg_list_size(invalid
); j
++ )
337 if((window
& invalid
[j
]) == invalid
[j
])
348 float ratio
= (float)vg_window_y
/ (float)vg_window_x
;
349 float const size
= 7.5f
;
350 glm_ortho( -size
, size
, -size
*ratio
, size
*ratio
, 0.1f
, 100.f
, m_projection
);
352 glm_mat4_identity( m_view
);
353 glm_translate_z( m_view
, -10.f
);
354 glm_rotate_x( m_view
, 1.0f
, m_view
);
356 glm_mat4_mul( m_projection
, m_view
, vg_pv
);
358 // Compute map update
359 for( int y
= 0; y
< map
.y
; y
++ )
361 for( int x
= 0; x
< map
.x
; x
++ )
363 // Cell is a connector if it has at least 3 connections
364 int output_dirs
[][2] = { {0,-1}, {-1,0}, {1,0}, {0,1} };
365 u32 output_count
= 0;
366 struct cell
*tile
, *thistile
;
367 thistile
= map_tile_at( (int [2]){x
,y
} );
369 if( thistile
->flags
& CELL_FLAG_CANAL
)
371 for( int i
= 0; i
< vg_list_size( output_dirs
); i
++ )
373 tile
= map_tile_at( (int [2]){ x
+output_dirs
[i
][0], y
+output_dirs
[i
][1] } );
375 if( tile
&& tile
->flags
& CELL_FLAG_CANAL
)
379 if( output_count
>= 3 )
380 thistile
->flags
|= CELL_FLAG_CONNECTOR
;
382 thistile
->flags
&= ~CELL_FLAG_CONNECTOR
;
392 vec4 vp
= { 0.f
, 0.f
, vg_window_x
, vg_window_y
};
393 glm_mat4_inv( vg_pv
, pv_inverse
);
394 glm_unprojecti( (vec3
){ vg_mouse_x
, vg_window_y
-vg_mouse_y
, -1.f
}, pv_inverse
, vp
, ray_dir
);
395 glm_unprojecti( (vec3
){ vg_mouse_x
, vg_window_y
-vg_mouse_y
, 0.f
}, pv_inverse
, vp
, ray_origin
);
396 glm_vec3_sub( ray_dir
, ray_origin
, ray_dir
);
398 // Get floor tile intersection
399 float ray_t
= -ray_origin
[1] / ray_dir
[1];
402 glm_vec3_copy( ray_origin
, tile_pos
);
403 glm_vec3_muladds( ray_dir
, ray_t
, tile_pos
);
404 glm_vec3_sub( tile_pos
, map
.origin
, tile_pos
);
406 int tile_x
= floorf( tile_pos
[0] );
407 int tile_y
= floorf( tile_pos
[2] );
409 map
.selected
= map_tile_at( (int [2]){tile_x
, tile_y
} );
413 static int fish_counter
= 0;
416 if( fish_counter
> 20 )
420 // Advance characters
421 for( int i
= 0; i
< map
.num_fishes
; i
++ )
423 struct fish
*fish
= map
.fishes
+ i
;
428 struct cell
*tile
, *next
;
429 tile
= map_tile_at( fish
->co
);
431 if( tile
->flags
& CELL_FLAG_OUTPUT
)
433 vg_info( "Fish got zucced (%d)\n", i
);
439 if( tile
->flags
& CELL_FLAG_CONNECTOR
)
442 int new_dir
[][2] = { {0,-1},{1,0},{-1,0} };
445 for( int j
= 0; j
< 3; j
++ )
447 test_dir
= new_dir
[ tile
->state
];
448 tile
->state
= (tile
->state
+1)%3;
450 next
= map_tile_at( (int[2]){ fish
->co
[0]+test_dir
[0], fish
->co
[1]+test_dir
[1] } );
451 if( next
&& (next
->flags
& (CELL_FLAG_WALKABLE
)) )
453 fish
->dir
[0] = test_dir
[0];
454 fish
->dir
[1] = test_dir
[1];
461 next
= map_tile_at( (int[2]){ fish
->co
[0]+fish
->dir
[0], fish
->co
[1]+fish
->dir
[1] } );
462 if( !next
|| (next
&& !(next
->flags
& CELL_FLAG_WALKABLE
)) )
470 vg_info( "Fish died! (%d)\n", i
);
476 fish
->co
[0] += fish
->dir
[0];
477 fish
->co
[1] += fish
->dir
[1];
481 for( int i
= 0; i
< arrlen( map
.io
); i
++ )
483 struct cell
*input
= &map
.cells
[ map
.io
[i
] ];
485 if( input
->flags
& CELL_FLAG_INPUT
)
487 if( input
->state
< arrlen( input
->conditions
) )
489 struct fish
*fish
= &map
.fishes
[ map
.num_fishes
];
490 map_tile_coords_from_index( map
.io
[i
], fish
->co
);
492 int output_dirs
[][2] = { {0,-1}, {-1,0}, {1,0} };
495 for( int i
= 0; i
< vg_list_size( output_dirs
); i
++ )
497 int *dir
= output_dirs
[i
];
498 struct cell
*next
= map_tile_at( (int[2]){ fish
->co
[0]+dir
[0], fish
->co
[1]+dir
[1] } );
499 if( next
&& next
->flags
& CELL_FLAG_CANAL
)
501 fish
->dir
[0] = dir
[0];
502 fish
->dir
[1] = dir
[1];
517 vg_info( "There are now %u active fish\n", map
.num_fishes
);
520 if( vg_get_button_down( "go" ) )
525 vg_info( "Ending!\n" );
530 if( vg_get_button_down( "go" ) )
535 for( int i
= 0; i
< map
.x
*map
.y
; i
++ )
536 map
.cells
[ i
].state
= 0;
538 vg_info( "Starting!\n" );
543 map
.select_valid
= map_tile_availible( (int[2]){ tile_x
, tile_y
} );
545 if( map
.select_valid
)
547 if( vg_get_button_down("primary") )
549 if( map
.selected
->flags
& CELL_FLAG_CANAL
)
551 map
.selected
->flags
&= ~(CELL_FLAG_CANAL
| CELL_FLAG_CONNECTOR
);
555 map
.selected
->flags
|= CELL_FLAG_CANAL
;
568 glViewport( 0,0, vg_window_x
, vg_window_y
);
570 glEnable( GL_DEPTH_TEST
);
571 glClearColor( 0.94f
, 0.94f
, 0.94f
, 1.0f
);
572 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
574 glBindVertexArray( tile_vao
);
576 SHADER_USE( colour_shader
);
577 glUniformMatrix4fv( SHADER_UNIFORM( colour_shader
, "uPv" ), 1, GL_FALSE
, (float *)vg_pv
);
579 for( int y
= 0; y
< map
.y
; y
++ )
581 for( int x
= 0; x
< map
.x
; x
++ )
583 glm_mat4_identity( m_mdl
);
584 glm_translate( m_mdl
,
586 map
.origin
[0] + (float)x
+ 0.5f
,
588 map
.origin
[2] + (float)y
+ 0.5f
591 glUniformMatrix4fv( SHADER_UNIFORM( colour_shader
, "uMdl" ), 1, GL_FALSE
, (float *)m_mdl
);
593 struct cell
*cell
= &map
.cells
[ y
*map
.x
+x
];
595 vec4 colour
= { 0.7f
, 0.7f
, 0.7f
, 1.f
};
597 if( cell
->flags
& CELL_FLAG_INPUT
) glm_vec3_copy( (vec3
){ 0.9f
,0.5f
,0.5f
}, colour
);
598 else if( cell
->flags
& CELL_FLAG_OUTPUT
) glm_vec3_copy( (vec3
){ 0.5f
,0.9f
,0.5f
}, colour
);
599 else if( cell
->flags
& CELL_FLAG_WALL
) glm_vec3_copy( (vec3
){ 0.1f
,0.1f
,0.1f
}, colour
);
600 else if( cell
->flags
& CELL_FLAG_CANAL
) glm_vec3_copy( (vec3
){ 0.5f
,0.5f
,0.8f
}, colour
);
602 if( cell
->flags
& CELL_FLAG_CONNECTOR
)
603 glm_vec3_copy( (vec3
){ 0.6f
, 0.f
, 0.9f
}, colour
);
605 if( map
.selected
== cell
)
607 if( !map
.select_valid
)
608 glm_vec3_copy( (vec3
){ 1.f
, 0.f
, 0.f
}, colour
);
610 float flash
= sinf( vg_time
*2.5f
) * 0.25f
+ 0.75f
;
611 glm_vec3_scale( colour
, flash
, colour
);
614 glUniform4fv( SHADER_UNIFORM( colour_shader
, "uColour" ), 1, colour
);
615 glDrawArrays( GL_TRIANGLES
, 0, 6 );
619 glUniform4f( SHADER_UNIFORM( colour_shader
, "uColour" ), 1.f
, 0.f
, 1.f
, 1.f
);
621 for( int i
= 0; i
< map
.num_fishes
; i
++ )
623 struct fish
*fish
= map
.fishes
+ i
;
627 glm_mat4_identity( m_mdl
);
628 glm_translate( m_mdl
,
630 map
.origin
[0] + (float)fish
->co
[0] + 0.5f
,
632 map
.origin
[2] + (float)fish
->co
[1] + 0.5f
635 glm_scale_uni( m_mdl
, 0.2f
);
636 glUniformMatrix4fv( SHADER_UNIFORM( colour_shader
, "uMdl" ), 1, GL_FALSE
, (float *)m_mdl
);
637 glDrawArrays( GL_TRIANGLES
, 0, 6 );
644 SHADER_INIT( colour_shader
);
646 glGenVertexArrays( 1, &tile_vao
);
647 glGenBuffers( 1, &tile_vbo
);
659 glBindVertexArray( tile_vao
);
660 glBindBuffer( GL_ARRAY_BUFFER
, tile_vbo
);
669 glVertexAttribPointer( 0, 3, GL_FLOAT
, GL_FALSE
, 3 * sizeof(float), (void*)0 );
670 glEnableVertexAttribArray( 0 );