1 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
6 SHADER_DEFINE( shader_tile_colour
,
9 "layout (location=0) in vec2 a_co;"
11 "uniform vec2 uOffset;"
15 "gl_Position = vec4( uPv * vec3( a_co + uOffset, 1.0 ), 1.0 );"
20 "uniform vec4 uColour;"
24 "FragColor = uColour;"
27 UNIFORMS({ "uPv", "uOffset", "uColour" })
34 #define FLAG_INPUT 0x1
35 #define FLAG_OUTPUT 0x2
36 #define FLAG_CANAL 0x4
63 static void map_free(void)
65 for( int i
= 0; i
< arrlen( world
.io
); i
++ )
66 arrfree( world
.io
[ i
].conditions
);
68 arrfree( world
.data
);
77 static int map_load( const char *str
)
86 if( str
[world
.w
] == ';' )
88 else if( !str
[world
.w
] )
90 vg_error( "Unexpected EOF when parsing level\n" );
95 struct cell
*row
= arraddnptr( world
.data
, world
.w
);
97 int reg_start
= 0, reg_end
= 0;
113 if( reg_start
< reg_end
)
115 if( *c
>= 'a' && *c
<= 'z' )
117 arrpush( world
.io
[ reg_start
].conditions
, *c
);
121 if( *c
== ',' || *c
== '\n' )
130 vg_error( "Unkown attribute '%c' (row: %u)\n", *c
, world
.h
);
137 vg_error( "Too many values to assign (row: %u)\n", world
.h
);
145 if( reg_start
!= reg_end
)
147 vg_error( "Not enough values assigned (row: %u, %u of %u)\n", world
.h
, reg_start
, reg_end
);
153 vg_error( "Not enough cells to match previous row definition (row: %u, %u<%u)\n", world
.h
, cx
, world
.w
);
157 row
= arraddnptr( world
.data
, world
.w
);
160 reg_end
= reg_start
= arrlen( world
.io
);
166 vg_error( "Too many cells to match previous row definition (row: %u, %u>%u)\n", world
.h
, cx
, world
.w
);
170 // Tile initialization
174 if( *c
== '+' || *c
== '-' )
176 struct cell_terminal term
= { .id
= cx
+ world
.h
*world
.w
};
177 arrpush( world
.io
, term
);
178 row
[ cx
++ ].state
= *c
== '+'? FLAG_INPUT
: FLAG_OUTPUT
;
183 row
[ cx
++ ].state
= FLAG_WALL
;
187 row
[ cx
++ ].state
= 0x00;
194 vg_success( "Map loaded! (%u:%u)\n", world
.w
, world
.h
);
198 int main( int argc
, char *argv
[] )
200 vg_init( argc
, argv
, "FishLadder" );
203 void vg_register(void)
205 SHADER_INIT( shader_tile_colour
);
210 glGenVertexArrays( 1, &world
.tile_vao
);
211 glGenBuffers( 1, &world
.tile_vbo
);
215 0.05f
, 0.05f
, 0.05f
, 0.95f
, 0.95f
, 0.95f
,
216 0.05f
, 0.05f
, 0.95f
, 0.95f
, 0.95f
, 0.05f
219 glBindVertexArray( world
.tile_vao
);
220 glBindBuffer( GL_ARRAY_BUFFER
, world
.tile_vbo
);
229 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
, 2 * sizeof(float), (void*)0 );
230 glEnableVertexAttribArray( 0 );
237 "###-#####-###;aaa,aa\n"
244 "###+#####+###;aa,aaa\n"
251 glDeleteVertexArrays( 1, &world
.tile_vao
);
252 glDeleteBuffers( 1, &world
.tile_vbo
);
259 float ratio
= (float)vg_window_y
/ (float)vg_window_x
;
260 float const size
= 9.5f
;
263 origin
[0] = -0.5f
* world
.w
;
264 origin
[1] = -0.5f
* world
.h
;
267 m3x3_projection( m_projection
, -size
, size
, size
*ratio
, -size
*ratio
);
268 m3x3_identity( m_view
);
269 m3x3_translate( m_view
, origin
);
270 m3x3_mul( m_projection
, m_view
, vg_pv
);
271 vg_projection_update();
274 v2_copy( vg_mouse_ws
, tile_pos
);
276 int tile_x
= floorf( tile_pos
[0] );
277 int tile_y
= floorf( tile_pos
[1] );
279 if( tile_x
>= 2 && tile_x
< world
.w
-2 && tile_y
>= 2 && tile_y
<= world
.h
-2 )
281 world
.selected
= tile_y
* world
.w
+ tile_x
;
283 struct cell
*cell
= &world
.data
[tile_y
*world
.w
+tile_x
];
284 if( cell
->state
& (FLAG_WALL
|FLAG_INPUT
|FLAG_OUTPUT
) )
290 if( vg_get_button_down("primary") )
292 cell
->state
^= FLAG_CANAL
;
299 for( int y
= 1; y
< world
.h
-1; y
++ )
301 for( int x
= 1; x
< world
.w
-1; x
++ )
303 struct cell
*cell
= &world
.data
[y
*world
.w
+x
];
305 if( !(cell
->state
& FLAG_CANAL
) )
308 if( cell
->state
& FLAG_INPUT
)
313 v2i dirs
[] = {{1,0},{0,1},{-1,0},{0,-1}};
315 for( int i
= 0; i
< vg_list_size( dirs
); i
++ )
317 struct cell
*neighbour
= &world
.data
[(y
+dirs
[i
][1])*world
.w
+x
+dirs
[i
][0]];
319 if( neighbour
->state
& FLAG_CANAL
)
321 neighbour
->water
= vg_max( neighbour
->water
, cell
->water
-1 );
333 glViewport( 0,0, vg_window_x
, vg_window_y
);
335 glDisable( GL_DEPTH_TEST
);
336 glClearColor( 0.01f
, 0.01f
, 0.01f
, 1.0f
);
337 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
339 glBindVertexArray( world
.tile_vao
);
340 SHADER_USE( shader_tile_colour
);
341 glUniformMatrix3fv( SHADER_UNIFORM( shader_tile_colour
, "uPv" ), 1, GL_FALSE
, (float *)vg_pv
);
343 for( int y
= 0; y
< world
.h
; y
++ )
345 for( int x
= 0; x
< world
.w
; x
++ )
347 glUniform2f( SHADER_UNIFORM( shader_tile_colour
, "uOffset" ), (float)x
, (float)y
);
351 struct cell
*cell
= &world
.data
[y
*world
.w
+x
];
353 if( cell
->state
& FLAG_WALL
) { v4_copy( (v4f
){ 0.2f
, 0.2f
, 0.2f
, 1.0f
}, colour
); }
354 else if( cell
->state
& FLAG_CANAL
) { v4_copy( (v4f
){ 0.6f
, 0.6f
, 0.6f
, 1.0f
}, colour
); }
355 else if( cell
->state
& FLAG_INPUT
) { v4_copy( (v4f
){ 0.2f
, 0.3f
, 0.7f
, 1.0f
}, colour
); }
356 else if( cell
->state
& FLAG_OUTPUT
) { v4_copy( (v4f
){ 0.2f
, 0.7f
, 0.3f
, 1.0f
}, colour
); }
357 else v4_copy( (v4f
){ 0.9f
, 0.9f
, 0.9f
, 1.0f
}, colour
);
360 v4_copy( (v4f
){ 0.2f
, 0.3f
, 0.7f
* (float)(cell
->water
) * (1.0f
/8.0f
), 1.0f
}, colour
);
362 if( world
.selected
== y
*world
.w
+ x
)
363 v3_muls( colour
, sinf( vg_time
)*0.25f
+ 0.5f
, colour
);
365 glUniform4fv( SHADER_UNIFORM( shader_tile_colour
, "uColour" ), 1, colour
);
367 glDrawArrays( GL_TRIANGLES
, 0, 6 );