textures/loading
[fishladder.git] / fishladder.c
1 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
2
3 //#define VG_STEAM
4 #include "vg/vg.h"
5
6 SHADER_DEFINE( colour_shader,
7
8 // VERTEX
9 "layout (location=0) in vec2 a_co;"
10 "uniform mat4 uPv;"
11 "uniform mat4 uMdl;"
12 ""
13 "void main()"
14 "{"
15 " vec4 vert_pos = uPv * uMdl * vec4( a_co.x, 0.0, a_co.y, 1.0 );"
16 " gl_Position = vert_pos;"
17 "}",
18
19 // FRAGMENT
20 "out vec4 FragColor;"
21 "uniform vec4 uColour;"
22 ""
23 "void main()"
24 "{"
25 " FragColor = uColour;"
26 "}"
27 ,
28 UNIFORMS({ "uPv", "uMdl", "uColour" })
29 )
30
31 /*
32 SHADER_DEFINE( tilemap_shader,
33
34 // VERTEX
35 "layout (location=0) in vec2 a_co;"
36 "uniform mat4 uPv;"
37 "uniform vec4 uTextureInfo;" // Cell dx,dy 1.0/mx, 1.0/my
38 "uniform "
39 ""
40 "uniform vec2 uPosition;"
41 "uniform int uCellIndex;"
42 ""
43 "out vec2 s_uv;"
44 ""
45 "void main()"
46 "{"
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,"
49 "}"
50 */
51
52 mat4 m_projection;
53 mat4 m_view;
54 mat4 m_mdl;
55
56 int main( int argc, char *argv[] )
57 {
58 vg_init( argc, argv, "FishLadder" );
59 }
60
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? */
69
70 static struct
71 {
72 u32 x,y;
73
74 struct cell
75 {
76 u32 flags;
77 u32 model_id;
78
79 char *conditions;
80
81 int level;
82 int diff[2];
83 }
84 * cells;
85
86 vec3 origin;
87 struct cell *selected;
88 int select_valid;
89 u32 frame;
90
91 u32 *io;
92
93 struct vstack
94 {
95 struct vframe
96 {
97 int x, y;
98 int i;
99 }
100 frames[ 64 ];
101
102 int level;
103 u32 flags;
104 }
105 stack;
106
107 GLuint tile_texture;
108 GLuint flow_texture;
109 }
110 map;
111
112 static void map_free(void)
113 {
114 for( int i = 0; i < arrlen( map.io ); i ++ )
115 {
116 arrfree( map.cells[ map.io[i] ].conditions );
117 }
118
119 arrfree( map.cells );
120 arrfree( map.io );
121 map.x = 0;
122 map.y = 0;
123 map.cells = NULL;
124 map.io = NULL;
125 }
126
127 static struct cell *map_tile_at( int pos[2] )
128 {
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];
131 return NULL;
132 }
133
134 static int map_load( const char *str )
135 {
136 map_free();
137
138 char *c = str;
139
140 // Scan for width
141 for(;; map.x ++)
142 {
143 if( str[map.x] == ';' )
144 break;
145 else if( !str[map.x] )
146 {
147 vg_error( "Unexpected EOF when parsing level!\n" );
148 return 0;
149 }
150 }
151
152 struct cell *row = arraddnptr( map.cells, map.x );
153 int cx = 0;
154 int reg_start = 0, reg_end = 0;
155
156 for(;;)
157 {
158 if( !*c )
159 break;
160
161 if( *c == ';' )
162 {
163 c ++;
164
165 // Parse attribs
166 if( *c != '\n' )
167 {
168 while( *c )
169 {
170 if( reg_start < reg_end )
171 {
172 if( *c >= 'a' && *c <= 'z' )
173 {
174 arrpush( map.cells[ map.io[ reg_start ] ].conditions, *c );
175 }
176 else
177 {
178 if( *c == ',' || *c == '\n' )
179 {
180 reg_start ++;
181
182 if( *c == '\n' )
183 break;
184 }
185 else
186 {
187 vg_error( "Unkown attrib '%c' (row: %u)\n", *c, map.y );
188 return 0;
189 }
190 }
191 }
192 else
193 {
194 vg_error( "Over-assigned values (row: %u)\n", map.y );
195 return 0;
196 }
197
198 c ++;
199 }
200 }
201
202 if( reg_start != reg_end )
203 {
204 vg_error( "Not enough values assigned (row: %u, %u of %u)\n", map.y, reg_start, reg_end );
205 return 0;
206 }
207
208 if( cx != map.x )
209 {
210 vg_error( "Map row underflow (row: %u, %u<%u)\n", map.y, cx, map.x );
211 return 0;
212 }
213
214 row = arraddnptr( map.cells, map.x );
215 cx = 0;
216 map.y ++;
217 reg_end = reg_start = arrlen( map.io );
218 }
219 else
220 {
221 if( cx == map.x )
222 {
223 vg_error( "Map row overflow (row: %u, %u>%u)\n", map.y, cx, map.x );
224 return 0;
225 }
226
227 row[ cx ].conditions = NULL;
228
229 // Parse the various cell types
230 if( *c == '+' || *c == '-' )
231 {
232 arrpush( map.io, cx + map.y*map.x );
233 row[ cx ++ ].flags = *c == '+'? CELL_FLAG_INPUT: CELL_FLAG_OUTPUT;
234 reg_end ++;
235 }
236 else if( *c == '#' )
237 {
238 row[ cx ++ ].flags = CELL_FLAG_WALL;
239 }
240 else
241 {
242 row[ cx ++ ].flags = 0x00;
243 }
244 }
245
246 c ++;
247 }
248
249 // Origin top left corner
250 map.origin[0] = -((float)map.x) * 0.5f;
251 map.origin[2] = -((float)map.y) * 0.5f;
252
253 vg_success( "Map loaded! (%u:%u)\n", map.x, map.y );
254 return 1;
255 }
256
257 void vg_update(void)
258 {
259 // Update camera
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 );
263
264 glm_mat4_identity( m_view );
265 glm_translate_z( m_view, -10.f );
266 glm_rotate_x( m_view, 1.0f, m_view );
267
268 glm_mat4_mul( m_projection, m_view, vg_pv );
269
270 // Compute map update
271 map.frame ^= 0x1;
272 for( int y = 0; y < map.y; y ++ )
273 {
274 for( int x = 0; x < map.x; x ++ )
275 {
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} );
281
282 if( thistile->flags & CELL_FLAG_CANAL )
283 {
284 for( int i = 0; i < vg_list_size( output_dirs ); i ++ )
285 {
286 tile = map_tile_at( (int [2]){ x+output_dirs[i][0], y+output_dirs[i][1] } );
287
288 if( tile && tile->flags & CELL_FLAG_CANAL )
289 output_count ++;
290 }
291
292 if( output_count >= 3 )
293 thistile->flags |= CELL_FLAG_CONNECTOR;
294 else
295 thistile->flags &= ~CELL_FLAG_CONNECTOR;
296 }
297 }
298 }
299
300 // Get mouse ray
301 vec3 ray_origin;
302 vec3 ray_dir;
303
304 mat4 pv_inverse;
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 );
310
311 // Get floor tile intersection
312 float ray_t = -ray_origin[1] / ray_dir[1];
313
314 vec3 tile_pos;
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 );
318
319 int tile_x = floorf( tile_pos[0] );
320 int tile_y = floorf( tile_pos[2] );
321
322 map.selected = map_tile_at( (int [2]){tile_x, tile_y} );
323
324 if( map.selected )
325 {
326 // Check if valid
327 int validation[][2] = { {1,1}, {-1,1}, {-1,-1}, {1,-1} };
328 struct cell *a, *b, *c;
329
330 map.select_valid = 1;
331 for( int i = 0; i < vg_list_size( validation ); i ++ )
332 {
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] } );
335
336 if( a && b && (a->flags & b->flags & CELL_FLAG_CANAL) )
337 {
338 c = map_tile_at( (int [2]){ tile_x+validation[i][0], tile_y+validation[i][1] } );
339
340 if( c && (c->flags & CELL_FLAG_CANAL ) )
341 {
342 map.select_valid = 0;
343 break;
344 }
345 }
346 }
347
348 if( map.select_valid )
349 {
350 if( vg_get_button_down("primary") )
351 {
352 if( map.selected->flags & CELL_FLAG_CANAL )
353 {
354 map.selected->flags &= ~(CELL_FLAG_CANAL | CELL_FLAG_CONNECTOR);
355 }
356 else
357 {
358 map.selected->flags |= CELL_FLAG_CANAL;
359 }
360 }
361 }
362 }
363 }
364
365 GLuint tile_vao;
366 GLuint tile_vbo;
367
368 void vg_render(void)
369 {
370 glViewport( 0,0, vg_window_x, vg_window_y );
371
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 );
375
376 glBindVertexArray( tile_vao );
377
378 SHADER_USE( colour_shader );
379 glUniformMatrix4fv( SHADER_UNIFORM( colour_shader, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
380
381 for( int y = 0; y < map.y; y ++ )
382 {
383 for( int x = 0; x < map.x; x ++ )
384 {
385 glm_mat4_identity( m_mdl );
386 glm_translate( m_mdl,
387 (vec3){
388 map.origin[0] + (float)x + 0.5f,
389 0.f,
390 map.origin[2] + (float)y + 0.5f
391 }
392 );
393 glUniformMatrix4fv( SHADER_UNIFORM( colour_shader, "uMdl" ), 1, GL_FALSE, (float *)m_mdl );
394
395 struct cell *cell = &map.cells[ y*map.x+x ];
396
397 vec4 colour = { 0.7f, 0.7f, 0.7f, 1.f };
398
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 );
403
404 if( cell->flags & CELL_FLAG_CONNECTOR )
405 glm_vec3_copy( (vec3){ 0.6f, 0.f, 0.9f }, colour );
406
407 if( map.selected == cell )
408 {
409 if( !map.select_valid )
410 glm_vec3_copy( (vec3){ 1.f, 0.f, 0.f }, colour );
411
412 float flash = sinf( vg_time*2.5f ) * 0.25f + 0.75f;
413 glm_vec3_scale( colour, flash, colour );
414 }
415
416 glUniform4fv( SHADER_UNIFORM( colour_shader, "uColour" ), 1, colour );
417 glDrawArrays( GL_TRIANGLES, 0, 6 );
418 }
419 }
420 }
421
422 void vg_start(void)
423 {
424 SHADER_INIT( colour_shader );
425
426 glGenVertexArrays( 1, &tile_vao );
427 glGenBuffers( 1, &tile_vbo );
428
429 float quad_mesh[] =
430 {
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
433 };
434
435 glBindVertexArray( tile_vao );
436 glBindBuffer( GL_ARRAY_BUFFER, tile_vbo );
437 glBufferData
438 (
439 GL_ARRAY_BUFFER,
440 sizeof( quad_mesh ),
441 quad_mesh,
442 GL_STATIC_DRAW
443 );
444
445 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0 );
446 glEnableVertexAttribArray( 0 );
447
448 VG_CHECK_GL();
449
450 map.tile_texture = vg_tex2d_rgba( "textures/rivertiles_flowm.tga" );
451 map.flow_texture = vg_tex2d_rgba( "textures/rivertiles_ripple.tga" );
452
453 map_load
454 (
455 "#####-#####;aa\n"
456 "# #;\n"
457 "# #;\n"
458 "# -;bb\n"
459 "# #;\n"
460 "# #;\n"
461 "#####+#####;abab\n"
462 );
463 }
464
465 void vg_free(void)
466 {
467 map_free();
468
469 glDeleteTextures( 1, &map.tile_texture );
470 glDeleteTextures( 1, &map.flow_texture );
471 }
472
473 void vg_ui(void)
474 {
475
476 }