X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=fishladder.c;h=f6673f77aeda5c4c920682daa231c419fd81a79f;hb=49a2d3825e61f53012816135ac4c4278c0b27632;hp=a9ce03a8dbc245a27f1f7ee670b298d1e2bcf06e;hpb=f17b92e32e2edae3692d5ea87844fbdf4a779952;p=fishladder.git diff --git a/fishladder.c b/fishladder.c index a9ce03a..f6673f7 100644 --- a/fishladder.c +++ b/fishladder.c @@ -3,27 +3,369 @@ //#define VG_STEAM #include "vg/vg.h" +SHADER_DEFINE( colour_shader, + + // VERTEX + "layout (location=0) in vec3 a_co;" + "uniform mat4 uPv;" + "uniform mat4 uMdl;" + "" + "void main()" + "{" + " vec4 vert_pos = uPv * uMdl * vec4( a_co, 1.0 );" + " gl_Position = vert_pos;" + "}", + + // FRAGMENT + "out vec4 FragColor;" + "uniform vec4 uColour;" + "" + "void main()" + "{" + " FragColor = uColour;" + "}" + , + UNIFORMS({ "uPv", "uMdl", "uColour" }) +) + +mat4 m_projection; +mat4 m_view; +mat4 m_pv; +mat4 m_mdl; + int main( int argc, char *argv[] ) { vg_init( argc, argv, "FishLadder" ); } -void vg_start(void) +#define CELL_FLAG_INPUT 0x1 +#define CELL_FLAG_OUTPUT 0x2 + #define CELL_FLAG_IO (CELL_FLAG_INPUT|CELL_FLAG_OUTPUT) +#define CELL_FLAG_WALL 0x4 +#define CELL_FLAG_HOVER 0x8 +#define CELL_FLAG_ITER 0x10 +#define CELL_FLAG_CANAL 0x20 + +static struct +{ + u32 x,y; + + struct cell + { + u32 flags; + u32 model_id; + + char *conditions; + } + * cells; + + vec3 origin; + struct cell *selected; + int select_valid; + + u32 *io; + + struct vstack + { + struct vframe + { + int x, y; + int i; + } + frames[ 64 ]; + + int level; + u32 flags; + } + stack; +} +map; + +static void map_free(void) { + for( int i = 0; i < arrlen( map.io ); i ++ ) + { + arrfree( map.cells[ map.io[i] ].conditions ); + } + arrfree( map.cells ); + arrfree( map.io ); + map.x = 0; + map.y = 0; + map.cells = NULL; + map.io = NULL; +} + +static struct cell *map_tile_at( int pos[2] ) +{ + if( pos[0] >= 0 && pos[0] < map.x && pos[1] >= 0 && pos[1] < map.y ) + return map.cells + pos[1]*map.x + pos[0]; + return NULL; +} + +static int map_load( const char *str ) +{ + map_free(); + + char *c = str; + + // Scan for width + for(;; map.x ++) + { + if( str[map.x] == ';' ) + break; + else if( !str[map.x] ) + { + vg_error( "Unexpected EOF when parsing level!\n" ); + return 0; + } + } + + struct cell *row = arraddnptr( map.cells, map.x ); + int cx = 0; + int reg_start = 0, reg_end = 0; + + for(;;) + { + if( !*c ) + break; + + if( *c == ';' ) + { + c ++; + + // Parse attribs + if( *c != '\n' ) + { + while( *c ) + { + if( reg_start < reg_end ) + { + if( *c >= 'a' && *c <= 'z' ) + { + arrpush( map.cells[ map.io[ reg_start ] ].conditions, *c ); + } + else + { + if( *c == ',' || *c == '\n' ) + { + reg_start ++; + + if( *c == '\n' ) + break; + } + else + { + vg_error( "Unkown attrib '%c' (row: %u)\n", *c, map.y ); + return 0; + } + } + } + else + { + vg_error( "Over-assigned values (row: %u)\n", map.y ); + return 0; + } + + c ++; + } + } + + if( reg_start != reg_end ) + { + vg_error( "Not enough values assigned (row: %u, %u of %u)\n", map.y, reg_start, reg_end ); + return 0; + } + + if( cx != map.x ) + { + vg_error( "Map row underflow (row: %u, %u<%u)\n", map.y, cx, map.x ); + return 0; + } + + row = arraddnptr( map.cells, map.x ); + cx = 0; + map.y ++; + reg_end = reg_start = arrlen( map.io ); + } + else + { + if( cx == map.x ) + { + vg_error( "Map row overflow (row: %u, %u>%u)\n", map.y, cx, map.x ); + return 0; + } + + row[ cx ].conditions = NULL; + + // Parse the various cell types + if( *c == '+' || *c == '-' ) + { + arrpush( map.io, cx + map.y*map.x ); + row[ cx ++ ].flags = *c == '+'? CELL_FLAG_INPUT: CELL_FLAG_OUTPUT; + reg_end ++; + } + else if( *c == '#' ) + { + row[ cx ++ ].flags = CELL_FLAG_WALL; + } + else + { + row[ cx ++ ].flags = 0x00; + } + } + + c ++; + } + + // Origin top left corner + map.origin[0] = -((float)map.x) * 0.5f; + map.origin[2] = -((float)map.y) * 0.5f; + + vg_success( "Map loaded! (%u:%u)\n", map.x, map.y ); + return 1; } void vg_update(void) { + // Update camera + float ratio = (float)vg_window_y / (float)vg_window_x; + float const size = 7.5f; + glm_ortho( -size, size, -size*ratio, size*ratio, 0.1f, 100.f, m_projection ); + + glm_mat4_identity( m_view ); + glm_translate_z( m_view, -10.f ); + glm_rotate_x( m_view, 1.0f, m_view ); + + glm_mat4_mul( m_projection, m_view, m_pv ); + + // Get mouse ray + vec3 ray_origin; + vec3 ray_dir; + + mat4 pv_inverse; + vec4 vp = { 0.f, 0.f, vg_window_x, vg_window_y }; + glm_mat4_inv( m_pv, pv_inverse ); + glm_unprojecti( (vec3){ vg_mouse_x, vg_window_y-vg_mouse_y, -1.f }, pv_inverse, vp, ray_dir ); + glm_unprojecti( (vec3){ vg_mouse_x, vg_window_y-vg_mouse_y, 0.f }, pv_inverse, vp, ray_origin ); + glm_vec3_sub( ray_dir, ray_origin, ray_dir ); + + // Get floor tile intersection + float ray_t = -ray_origin[1] / ray_dir[1]; + vec3 tile_pos; + glm_vec3_copy( ray_origin, tile_pos ); + glm_vec3_muladds( ray_dir, ray_t, tile_pos ); + glm_vec3_sub( tile_pos, map.origin, tile_pos ); + + int tile_x = floorf( tile_pos[0] ); + int tile_y = floorf( tile_pos[2] ); + + map.selected = map_tile_at( (int [2]){tile_x, tile_y} ); } +GLuint tile_vao; +GLuint tile_vbo; + void vg_render(void) { + glViewport( 0,0, vg_window_x, vg_window_y ); + + glEnable( GL_DEPTH_TEST ); + glClearColor( 0.94f, 0.94f, 0.94f, 1.0f ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + SHADER_USE( colour_shader ); + glUniformMatrix4fv( SHADER_UNIFORM( colour_shader, "uPv" ), 1, GL_FALSE, (float *)m_pv ); + for( int y = 0; y < map.y; y ++ ) + { + for( int x = 0; x < map.x; x ++ ) + { + glm_mat4_identity( m_mdl ); + glm_translate( m_mdl, + (vec3){ + map.origin[0] + (float)x + 0.5f, + 0.f, + map.origin[2] + (float)y + 0.5f + } + ); + glUniformMatrix4fv( SHADER_UNIFORM( colour_shader, "uMdl" ), 1, GL_FALSE, (float *)m_mdl ); + + struct cell *cell = &map.cells[ y*map.x+x ]; + + if( map.selected != cell ) + { + if( cell->flags & CELL_FLAG_INPUT ) + glUniform4f( SHADER_UNIFORM( colour_shader, "uColour" ), 0.9f, 0.5f, 0.5f, 1.0f ); + else if( cell->flags & CELL_FLAG_OUTPUT ) + glUniform4f( SHADER_UNIFORM( colour_shader, "uColour" ), 0.5f, 0.9f, 0.5f, 1.0f ); + else if( cell->flags & CELL_FLAG_WALL ) + glUniform4f( SHADER_UNIFORM( colour_shader, "uColour" ), 0.1f, 0.1f, 0.1f, 1.0f ); + else + glUniform4f( SHADER_UNIFORM( colour_shader, "uColour" ), 0.7f, 0.7f, 0.7f, 1.0f ); + } + else + { + float flash = sinf( vg_time*2.5f ) * 0.25f + 0.75f; + glUniform4f( SHADER_UNIFORM( colour_shader, "uColour" ), flash,flash,flash, 1.0f ); + } + + glDrawArrays( GL_TRIANGLES, 0, 6 ); + } + } +} + +void vg_start(void) +{ + SHADER_INIT( colour_shader ); + + glGenVertexArrays( 1, &tile_vao ); + glGenBuffers( 1, &tile_vbo ); + + float quad_mesh[] = + { + -0.5f, 0.f, -0.5f, + -0.5f, 0.f, 0.5f, + 0.5f, 0.f, 0.5f, + -0.5f, 0.f, -0.5f, + 0.5f, 0.f, 0.5f, + 0.5f, 0.f, -0.5f + }; + + glBindVertexArray( tile_vao ); + glBindBuffer( GL_ARRAY_BUFFER, tile_vbo ); + glBufferData + ( + GL_ARRAY_BUFFER, + sizeof( quad_mesh ), + quad_mesh, + GL_STATIC_DRAW + ); + + glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0 ); + glEnableVertexAttribArray( 0 ); + + VG_CHECK_GL(); + + map_load + ( + "#####-#####;aa\n" + "# #;\n" + "# #;\n" + "# -;bb\n" + "# #;\n" + "# #;\n" + "#####+#####;abab\n" + ); } void vg_free(void) +{ + map_free(); +} + +void vg_ui(void) { }