1 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
6 SHADER_DEFINE( colour_shader
,
9 "layout (location=0) in vec2 a_co;"
15 " vec4 vert_pos = uPv * uMdl * vec4( a_co.x, 0.0, a_co.y, 1.0 );"
16 " gl_Position = vert_pos;"
21 "uniform vec4 uColour;"
25 " FragColor = uColour;"
28 UNIFORMS({ "uPv", "uMdl", "uColour" })
32 SHADER_DEFINE( tilemap_shader,
35 "layout (location=0) in vec2 a_co;"
37 "uniform vec4 uTextureInfo;" // Cell dx,dy 1.0/mx, 1.0/my
40 "uniform vec2 uPosition;"
41 "uniform int uCellIndex;"
47 " gl_Position = uPv * vec4( uPosition.x + a_co.x, 0.0, uPosition.y + a_co.y, 0.0 );"
48 " s_uv = vec2( mod( uCellIndex,"
56 int main( int argc
, char *argv
[] )
58 vg_init( argc
, argv
, "FishLadder" );
61 #define CELL_FLAG_INPUT 0x1
62 #define CELL_FLAG_OUTPUT 0x2
63 #define CELL_FLAG_IO (CELL_FLAG_INPUT|CELL_FLAG_OUTPUT)
64 #define CELL_FLAG_WALL 0x4
65 #define CELL_FLAG_HOVER 0x8
66 #define CELL_FLAG_ITER 0x10
67 #define CELL_FLAG_CANAL 0x20
68 #define CELL_FLAG_CONNECTOR 0x40 /* Does this cell split and have an incoming vertical connection? */
87 struct cell
*selected
;
112 static void map_free(void)
114 for( int i
= 0; i
< arrlen( map
.io
); i
++ )
116 arrfree( map
.cells
[ map
.io
[i
] ].conditions
);
119 arrfree( map
.cells
);
127 static struct cell
*map_tile_at( int pos
[2] )
129 if( pos
[0] >= 0 && pos
[0] < map
.x
&& pos
[1] >= 0 && pos
[1] < map
.y
)
130 return map
.cells
+ pos
[1]*map
.x
+ pos
[0];
134 static int map_load( const char *str
)
143 if( str
[map
.x
] == ';' )
145 else if( !str
[map
.x
] )
147 vg_error( "Unexpected EOF when parsing level!\n" );
152 struct cell
*row
= arraddnptr( map
.cells
, map
.x
);
154 int reg_start
= 0, reg_end
= 0;
170 if( reg_start
< reg_end
)
172 if( *c
>= 'a' && *c
<= 'z' )
174 arrpush( map
.cells
[ map
.io
[ reg_start
] ].conditions
, *c
);
178 if( *c
== ',' || *c
== '\n' )
187 vg_error( "Unkown attrib '%c' (row: %u)\n", *c
, map
.y
);
194 vg_error( "Over-assigned values (row: %u)\n", map
.y
);
202 if( reg_start
!= reg_end
)
204 vg_error( "Not enough values assigned (row: %u, %u of %u)\n", map
.y
, reg_start
, reg_end
);
210 vg_error( "Map row underflow (row: %u, %u<%u)\n", map
.y
, cx
, map
.x
);
214 row
= arraddnptr( map
.cells
, map
.x
);
217 reg_end
= reg_start
= arrlen( map
.io
);
223 vg_error( "Map row overflow (row: %u, %u>%u)\n", map
.y
, cx
, map
.x
);
227 row
[ cx
].conditions
= NULL
;
229 // Parse the various cell types
230 if( *c
== '+' || *c
== '-' )
232 arrpush( map
.io
, cx
+ map
.y
*map
.x
);
233 row
[ cx
++ ].flags
= *c
== '+'? CELL_FLAG_INPUT
: CELL_FLAG_OUTPUT
;
238 row
[ cx
++ ].flags
= CELL_FLAG_WALL
;
242 row
[ cx
++ ].flags
= 0x00;
249 // Origin top left corner
250 map
.origin
[0] = -((float)map
.x
) * 0.5f
;
251 map
.origin
[2] = -((float)map
.y
) * 0.5f
;
253 vg_success( "Map loaded! (%u:%u)\n", map
.x
, map
.y
);
260 float ratio
= (float)vg_window_y
/ (float)vg_window_x
;
261 float const size
= 7.5f
;
262 glm_ortho( -size
, size
, -size
*ratio
, size
*ratio
, 0.1f
, 100.f
, m_projection
);
264 glm_mat4_identity( m_view
);
265 glm_translate_z( m_view
, -10.f
);
266 glm_rotate_x( m_view
, 1.0f
, m_view
);
268 glm_mat4_mul( m_projection
, m_view
, vg_pv
);
270 // Compute map update
272 for( int y
= 0; y
< map
.y
; y
++ )
274 for( int x
= 0; x
< map
.x
; x
++ )
276 // Cell is a connector if it has at least 3 connections
277 int output_dirs
[][2] = { {0,-1}, {-1,0}, {1,0}, {0,1} };
278 u32 output_count
= 0;
279 struct cell
*tile
, *thistile
;
280 thistile
= map_tile_at( (int [2]){x
,y
} );
282 if( thistile
->flags
& CELL_FLAG_CANAL
)
284 for( int i
= 0; i
< vg_list_size( output_dirs
); i
++ )
286 tile
= map_tile_at( (int [2]){ x
+output_dirs
[i
][0], y
+output_dirs
[i
][1] } );
288 if( tile
&& tile
->flags
& CELL_FLAG_CANAL
)
292 if( output_count
>= 3 )
293 thistile
->flags
|= CELL_FLAG_CONNECTOR
;
295 thistile
->flags
&= ~CELL_FLAG_CONNECTOR
;
305 vec4 vp
= { 0.f
, 0.f
, vg_window_x
, vg_window_y
};
306 glm_mat4_inv( vg_pv
, pv_inverse
);
307 glm_unprojecti( (vec3
){ vg_mouse_x
, vg_window_y
-vg_mouse_y
, -1.f
}, pv_inverse
, vp
, ray_dir
);
308 glm_unprojecti( (vec3
){ vg_mouse_x
, vg_window_y
-vg_mouse_y
, 0.f
}, pv_inverse
, vp
, ray_origin
);
309 glm_vec3_sub( ray_dir
, ray_origin
, ray_dir
);
311 // Get floor tile intersection
312 float ray_t
= -ray_origin
[1] / ray_dir
[1];
315 glm_vec3_copy( ray_origin
, tile_pos
);
316 glm_vec3_muladds( ray_dir
, ray_t
, tile_pos
);
317 glm_vec3_sub( tile_pos
, map
.origin
, tile_pos
);
319 int tile_x
= floorf( tile_pos
[0] );
320 int tile_y
= floorf( tile_pos
[2] );
322 map
.selected
= map_tile_at( (int [2]){tile_x
, tile_y
} );
327 int validation
[][2] = { {1,1}, {-1,1}, {-1,-1}, {1,-1} };
328 struct cell
*a
, *b
, *c
;
330 map
.select_valid
= 1;
331 for( int i
= 0; i
< vg_list_size( validation
); i
++ )
333 a
= map_tile_at( (int [2]){ tile_x
+validation
[i
][0], tile_y
} );
334 b
= map_tile_at( (int [2]){ tile_x
, tile_y
+validation
[i
][1] } );
336 if( a
&& b
&& (a
->flags
& b
->flags
& CELL_FLAG_CANAL
) )
338 c
= map_tile_at( (int [2]){ tile_x
+validation
[i
][0], tile_y
+validation
[i
][1] } );
340 if( c
&& (c
->flags
& CELL_FLAG_CANAL
) )
342 map
.select_valid
= 0;
348 if( map
.select_valid
)
350 if( vg_get_button_down("primary") )
352 if( map
.selected
->flags
& CELL_FLAG_CANAL
)
354 map
.selected
->flags
&= ~(CELL_FLAG_CANAL
| CELL_FLAG_CONNECTOR
);
358 map
.selected
->flags
|= CELL_FLAG_CANAL
;
370 glViewport( 0,0, vg_window_x
, vg_window_y
);
372 glEnable( GL_DEPTH_TEST
);
373 glClearColor( 0.94f
, 0.94f
, 0.94f
, 1.0f
);
374 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
376 glBindVertexArray( tile_vao
);
378 SHADER_USE( colour_shader
);
379 glUniformMatrix4fv( SHADER_UNIFORM( colour_shader
, "uPv" ), 1, GL_FALSE
, (float *)vg_pv
);
381 for( int y
= 0; y
< map
.y
; y
++ )
383 for( int x
= 0; x
< map
.x
; x
++ )
385 glm_mat4_identity( m_mdl
);
386 glm_translate( m_mdl
,
388 map
.origin
[0] + (float)x
+ 0.5f
,
390 map
.origin
[2] + (float)y
+ 0.5f
393 glUniformMatrix4fv( SHADER_UNIFORM( colour_shader
, "uMdl" ), 1, GL_FALSE
, (float *)m_mdl
);
395 struct cell
*cell
= &map
.cells
[ y
*map
.x
+x
];
397 vec4 colour
= { 0.7f
, 0.7f
, 0.7f
, 1.f
};
399 if( cell
->flags
& CELL_FLAG_INPUT
) glm_vec3_copy( (vec3
){ 0.9f
,0.5f
,0.5f
}, colour
);
400 else if( cell
->flags
& CELL_FLAG_OUTPUT
) glm_vec3_copy( (vec3
){ 0.5f
,0.9f
,0.5f
}, colour
);
401 else if( cell
->flags
& CELL_FLAG_WALL
) glm_vec3_copy( (vec3
){ 0.1f
,0.1f
,0.1f
}, colour
);
402 else if( cell
->flags
& CELL_FLAG_CANAL
) glm_vec3_copy( (vec3
){ 0.5f
,0.5f
,0.8f
}, colour
);
404 if( cell
->flags
& CELL_FLAG_CONNECTOR
)
405 glm_vec3_copy( (vec3
){ 0.6f
, 0.f
, 0.9f
}, colour
);
407 if( map
.selected
== cell
)
409 if( !map
.select_valid
)
410 glm_vec3_copy( (vec3
){ 1.f
, 0.f
, 0.f
}, colour
);
412 float flash
= sinf( vg_time
*2.5f
) * 0.25f
+ 0.75f
;
413 glm_vec3_scale( colour
, flash
, colour
);
416 glUniform4fv( SHADER_UNIFORM( colour_shader
, "uColour" ), 1, colour
);
417 glDrawArrays( GL_TRIANGLES
, 0, 6 );
424 SHADER_INIT( colour_shader
);
426 glGenVertexArrays( 1, &tile_vao
);
427 glGenBuffers( 1, &tile_vbo
);
431 0.0f
, 0.0f
, 0.0f
, 1.0f
, 1.0f
, 1.0f
,
432 0.0f
, 0.0f
, 1.0f
, 1.0f
, 1.0f
, 0.0f
435 glBindVertexArray( tile_vao
);
436 glBindBuffer( GL_ARRAY_BUFFER
, tile_vbo
);
445 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
, 2 * sizeof(float), (void*)0 );
446 glEnableVertexAttribArray( 0 );
450 map
.tile_texture
= vg_tex2d_rgba( "textures/rivertiles_flowm.tga" );
451 map
.flow_texture
= vg_tex2d_rgba( "textures/rivertiles_ripple.tga" );
469 glDeleteTextures( 1, &map
.tile_texture
);
470 glDeleteTextures( 1, &map
.flow_texture
);