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? */
66 struct cell
*selected
;
88 static void map_free(void)
90 for( int i
= 0; i
< arrlen( map
.io
); i
++ )
92 arrfree( map
.cells
[ map
.io
[i
] ].conditions
);
103 static struct cell
*map_tile_at( int pos
[2] )
105 if( pos
[0] >= 0 && pos
[0] < map
.x
&& pos
[1] >= 0 && pos
[1] < map
.y
)
106 return map
.cells
+ pos
[1]*map
.x
+ pos
[0];
110 static int map_load( const char *str
)
119 if( str
[map
.x
] == ';' )
121 else if( !str
[map
.x
] )
123 vg_error( "Unexpected EOF when parsing level!\n" );
128 struct cell
*row
= arraddnptr( map
.cells
, map
.x
);
130 int reg_start
= 0, reg_end
= 0;
146 if( reg_start
< reg_end
)
148 if( *c
>= 'a' && *c
<= 'z' )
150 arrpush( map
.cells
[ map
.io
[ reg_start
] ].conditions
, *c
);
154 if( *c
== ',' || *c
== '\n' )
163 vg_error( "Unkown attrib '%c' (row: %u)\n", *c
, map
.y
);
170 vg_error( "Over-assigned values (row: %u)\n", map
.y
);
178 if( reg_start
!= reg_end
)
180 vg_error( "Not enough values assigned (row: %u, %u of %u)\n", map
.y
, reg_start
, reg_end
);
186 vg_error( "Map row underflow (row: %u, %u<%u)\n", map
.y
, cx
, map
.x
);
190 row
= arraddnptr( map
.cells
, map
.x
);
193 reg_end
= reg_start
= arrlen( map
.io
);
199 vg_error( "Map row overflow (row: %u, %u>%u)\n", map
.y
, cx
, map
.x
);
203 row
[ cx
].conditions
= NULL
;
205 // Parse the various cell types
206 if( *c
== '+' || *c
== '-' )
208 arrpush( map
.io
, cx
+ map
.y
*map
.x
);
209 row
[ cx
++ ].flags
= *c
== '+'? CELL_FLAG_INPUT
: CELL_FLAG_OUTPUT
;
214 row
[ cx
++ ].flags
= CELL_FLAG_WALL
;
218 row
[ cx
++ ].flags
= 0x00;
225 // Origin top left corner
226 map
.origin
[0] = -((float)map
.x
) * 0.5f
;
227 map
.origin
[2] = -((float)map
.y
) * 0.5f
;
229 vg_success( "Map loaded! (%u:%u)\n", map
.x
, map
.y
);
236 float ratio
= (float)vg_window_y
/ (float)vg_window_x
;
237 float const size
= 7.5f
;
238 glm_ortho( -size
, size
, -size
*ratio
, size
*ratio
, 0.1f
, 100.f
, m_projection
);
240 glm_mat4_identity( m_view
);
241 glm_translate_z( m_view
, -10.f
);
242 glm_rotate_x( m_view
, 1.0f
, m_view
);
244 glm_mat4_mul( m_projection
, m_view
, vg_pv
);
246 // Compute map update
248 for( int y
= 0; y
< map
.y
; y
++ )
250 for( int x
= 0; x
< map
.x
; x
++ )
252 // Cell is a connector if it has at least 3 connections
253 int output_dirs
[][2] = { {0,-1}, {-1,0}, {1,0}, {0,1} };
254 u32 output_count
= 0;
255 struct cell
*tile
, *thistile
;
256 thistile
= map_tile_at( (int [2]){x
,y
} );
258 if( thistile
->flags
& CELL_FLAG_CANAL
)
260 for( int i
= 0; i
< vg_list_size( output_dirs
); i
++ )
262 tile
= map_tile_at( (int [2]){ x
+output_dirs
[i
][0], y
+output_dirs
[i
][1] } );
264 if( tile
&& tile
->flags
& CELL_FLAG_CANAL
)
268 if( output_count
>= 3 )
269 thistile
->flags
|= CELL_FLAG_CONNECTOR
;
271 thistile
->flags
&= ~CELL_FLAG_CONNECTOR
;
281 vec4 vp
= { 0.f
, 0.f
, vg_window_x
, vg_window_y
};
282 glm_mat4_inv( vg_pv
, pv_inverse
);
283 glm_unprojecti( (vec3
){ vg_mouse_x
, vg_window_y
-vg_mouse_y
, -1.f
}, pv_inverse
, vp
, ray_dir
);
284 glm_unprojecti( (vec3
){ vg_mouse_x
, vg_window_y
-vg_mouse_y
, 0.f
}, pv_inverse
, vp
, ray_origin
);
285 glm_vec3_sub( ray_dir
, ray_origin
, ray_dir
);
287 // Get floor tile intersection
288 float ray_t
= -ray_origin
[1] / ray_dir
[1];
291 glm_vec3_copy( ray_origin
, tile_pos
);
292 glm_vec3_muladds( ray_dir
, ray_t
, tile_pos
);
293 glm_vec3_sub( tile_pos
, map
.origin
, tile_pos
);
295 int tile_x
= floorf( tile_pos
[0] );
296 int tile_y
= floorf( tile_pos
[2] );
298 map
.selected
= map_tile_at( (int [2]){tile_x
, tile_y
} );
303 int validation
[][2] = { {1,1}, {-1,1}, {-1,-1}, {1,-1} };
304 struct cell
*a
, *b
, *c
;
306 map
.select_valid
= 1;
307 for( int i
= 0; i
< vg_list_size( validation
); i
++ )
309 a
= map_tile_at( (int [2]){ tile_x
+validation
[i
][0], tile_y
} );
310 b
= map_tile_at( (int [2]){ tile_x
, tile_y
+validation
[i
][1] } );
312 if( a
&& b
&& (a
->flags
& b
->flags
& CELL_FLAG_CANAL
) )
314 c
= map_tile_at( (int [2]){ tile_x
+validation
[i
][0], tile_y
+validation
[i
][1] } );
316 if( c
&& (c
->flags
& CELL_FLAG_CANAL
) )
318 map
.select_valid
= 0;
324 if( map
.select_valid
)
326 if( vg_get_button_down("primary") )
328 if( map
.selected
->flags
& CELL_FLAG_CANAL
)
330 map
.selected
->flags
&= ~(CELL_FLAG_CANAL
| CELL_FLAG_CONNECTOR
);
334 map
.selected
->flags
|= CELL_FLAG_CANAL
;
346 glViewport( 0,0, vg_window_x
, vg_window_y
);
348 glEnable( GL_DEPTH_TEST
);
349 glClearColor( 0.94f
, 0.94f
, 0.94f
, 1.0f
);
350 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
352 glBindVertexArray( tile_vao
);
354 SHADER_USE( colour_shader
);
355 glUniformMatrix4fv( SHADER_UNIFORM( colour_shader
, "uPv" ), 1, GL_FALSE
, (float *)vg_pv
);
357 for( int y
= 0; y
< map
.y
; y
++ )
359 for( int x
= 0; x
< map
.x
; x
++ )
361 glm_mat4_identity( m_mdl
);
362 glm_translate( m_mdl
,
364 map
.origin
[0] + (float)x
+ 0.5f
,
366 map
.origin
[2] + (float)y
+ 0.5f
369 glUniformMatrix4fv( SHADER_UNIFORM( colour_shader
, "uMdl" ), 1, GL_FALSE
, (float *)m_mdl
);
371 struct cell
*cell
= &map
.cells
[ y
*map
.x
+x
];
373 vec4 colour
= { 0.7f
, 0.7f
, 0.7f
, 1.f
};
375 if( cell
->flags
& CELL_FLAG_INPUT
) glm_vec3_copy( (vec3
){ 0.9f
,0.5f
,0.5f
}, colour
);
376 else if( cell
->flags
& CELL_FLAG_OUTPUT
) glm_vec3_copy( (vec3
){ 0.5f
,0.9f
,0.5f
}, colour
);
377 else if( cell
->flags
& CELL_FLAG_WALL
) glm_vec3_copy( (vec3
){ 0.1f
,0.1f
,0.1f
}, colour
);
378 else if( cell
->flags
& CELL_FLAG_CANAL
) glm_vec3_copy( (vec3
){ 0.5f
,0.5f
,0.8f
}, colour
);
380 if( cell
->flags
& CELL_FLAG_CONNECTOR
)
381 glm_vec3_copy( (vec3
){ 0.6f
, 0.f
, 0.9f
}, colour
);
383 if( map
.selected
== cell
)
385 if( !map
.select_valid
)
386 glm_vec3_copy( (vec3
){ 1.f
, 0.f
, 0.f
}, colour
);
388 float flash
= sinf( vg_time
*2.5f
) * 0.25f
+ 0.75f
;
389 glm_vec3_scale( colour
, flash
, colour
);
392 glUniform4fv( SHADER_UNIFORM( colour_shader
, "uColour" ), 1, colour
);
393 glDrawArrays( GL_TRIANGLES
, 0, 6 );
400 SHADER_INIT( colour_shader
);
402 glGenVertexArrays( 1, &tile_vao
);
403 glGenBuffers( 1, &tile_vbo
);
415 glBindVertexArray( tile_vao
);
416 glBindBuffer( GL_ARRAY_BUFFER
, tile_vbo
);
425 glVertexAttribPointer( 0, 3, GL_FLOAT
, GL_FALSE
, 3 * sizeof(float), (void*)0 );
426 glEnableVertexAttribArray( 0 );