timings
[carveJwlIkooP6JGAAIwe30JlM.git] / world_routes.h
1 /*
2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #ifndef ROUTES_H
6 #define ROUTES_H
7
8 #include <time.h>
9 #include "world.h"
10 #include "world_gate.h"
11
12 #if 0
13 #include "shaders/vblend.h"
14 #endif
15
16 #include "shaders/scene_route.h"
17 #include "shaders/routeui.h"
18
19
20 VG_STATIC
21 void world_routes_local_set_record( world_instance *world, ent_route *route,
22 double lap_time )
23 {
24 vg_success( " NEW LAP TIME: %f\n", lap_time );
25
26 if( route->official_track_id != 0xffffffff ){
27 double time_centiseconds = lap_time * 100.0;
28 if( time_centiseconds > (float)0xfffe ) /* skill issue */
29 return;
30
31 highscore_record temp;
32 temp.trackid = route->official_track_id;
33 temp.datetime = time(NULL);
34 temp.playerid = 0;
35 temp.points = 0;
36 temp.time = time_centiseconds;
37
38 highscores_push_record( &temp );
39
40 struct track_info *ti = &track_infos[ route->official_track_id ];
41 ti->push = 1;
42
43 if( ti->achievement_id ){
44 steam_set_achievement( ti->achievement_id );
45 steam_store_achievements();
46 }
47 }
48 else{
49 vg_warn( "There is no associated track for this record...\n" );
50 }
51 }
52
53
54 VG_STATIC void world_routes_clear( world_instance *world )
55 {
56 for( u32 i=0; i<mdl_arrcount( &world->ent_route ); i++ ){
57 ent_route *route = mdl_arritm( &world->ent_route, i );
58 route->active_checkpoint = 0xffffffff;
59 }
60
61 for( u32 i=0; i<mdl_arrcount( &world->ent_gate ); i++ ){
62 ent_gate *rg = mdl_arritm( &world->ent_gate, i );
63 rg->timing_version = 0;
64 rg->timing_time = 0.0;
65 }
66
67 world_global.current_run_version += 4;
68 world_global.last_use = 0.0;
69 }
70
71 VG_STATIC void world_routes_time_lap( world_instance *world, ent_route *route )
72 {
73 vg_info( "------- time lap %s -------\n",
74 mdl_pstr(&world->meta,route->pstr_name) );
75
76 double total_time = 0.0;
77 u32 last_version;
78 int validated = 1;
79
80 for( u32 i=0; i<route->checkpoints_count; i++ ){
81 u32 cpid = route->checkpoints_start+(i+route->active_checkpoint);
82 cpid = cpid % route->checkpoints_count;
83
84 ent_checkpoint *cp = mdl_arritm( &world->ent_checkpoint, cpid );
85 ent_gate *rg = mdl_arritm( &world->ent_gate, cp->gate_index );
86 rg = mdl_arritm( &world->ent_gate, rg->target );
87
88 if( i == 0 )
89 total_time = rg->timing_time;
90 else{
91 if( last_version+1 != rg->timing_version )
92 validated = 0;
93 }
94
95 last_version = rg->timing_version;
96 vg_info( "%u %f\n", rg->timing_version, rg->timing_time );
97 }
98
99 vg_info( "%u %f\n", world_global.current_run_version, world_global.time );
100
101 if( validated && (world_global.current_run_version == last_version+1)){
102 total_time = world_global.time - total_time;
103 world_routes_local_set_record( world, route, total_time );
104 }
105 vg_info( "----------------------------\n" );
106 }
107
108 /*
109 * When going through a gate this is called for bookkeeping purposes
110 */
111 VG_STATIC void world_routes_activate_entry_gate( world_instance *world,
112 ent_gate *rg )
113 {
114 ent_gate *dest = mdl_arritm( &world->ent_gate, rg->target );
115
116 world_global.last_use = world_global.time;
117
118 for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
119 ent_route *route = mdl_arritm( &world->ent_route, i );
120
121 u32 active_prev = route->active_checkpoint;
122 route->active_checkpoint = 0xffffffff;
123
124 for( u32 j=0; j<4; j++ ){
125 if( dest->routes[j] == i ){
126 for( u32 k=0; k<route->checkpoints_count; k++ ){
127 ent_checkpoint *cp = mdl_arritm( &world->ent_checkpoint,
128 route->checkpoints_start+k );
129
130 ent_gate *gk = mdl_arritm( &world->ent_gate, cp->gate_index );
131 if( gk == rg ){
132 route->active_checkpoint = k;
133 world_routes_time_lap( world, route );
134 break;
135 }
136 }
137 break;
138 }
139 }
140 }
141
142 dest->timing_version = world_global.current_run_version;
143 dest->timing_time = world_global.time;
144
145 world_global.current_run_version ++;
146 }
147
148 /* draw lines along the paths */
149 VG_STATIC void world_routes_debug( world_instance *world )
150 {
151 for( u32 i=0; i<mdl_arrcount(&world->ent_route_node); i++ ){
152 ent_route_node *rn = mdl_arritm(&world->ent_route_node,i);
153 vg_line_pt3( rn->co, 0.25f, VG__WHITE );
154 }
155
156 for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
157 ent_route *route = mdl_arritm(&world->ent_route, i);
158
159 u32 colours[] = { 0xfff58142, 0xff42cbf5, 0xff42f56c, 0xfff542b3,
160 0xff5442f5 };
161
162 u32 cc = 0xffcccccc;
163 if( route->active_checkpoint != 0xffffffff ){
164 cc = colours[i%vg_list_size(colours)];
165 }
166
167 for( int i=0; i<route->checkpoints_count; i++ ){
168 int i0 = route->checkpoints_start+i,
169 i1 = route->checkpoints_start+((i+1)%route->checkpoints_count);
170
171 ent_checkpoint *c0 = mdl_arritm(&world->ent_checkpoint, i0),
172 *c1 = mdl_arritm(&world->ent_checkpoint, i1);
173
174 ent_gate *start_gate = mdl_arritm( &world->ent_gate, c0->gate_index );
175 ent_gate *end_gate = mdl_arritm( &world->ent_gate, c1->gate_index );
176
177 v3f p0, p1;
178 v3_copy( start_gate->co[1], p0 );
179
180 for( int j=0; j<c0->path_count; j ++ ){
181 ent_path_index *index = mdl_arritm( &world->ent_path_index,
182 c0->path_start+j );
183
184 ent_route_node *rn = mdl_arritm( &world->ent_route_node,
185 index->index );
186
187 v3_copy( rn->co, p1 );
188 vg_line( p0, p1, cc );
189 v3_copy( p1, p0 );
190 }
191
192 v3_copy( end_gate->co[0], p1 );
193 vg_line( p0, p1, cc );
194 }
195 }
196 }
197
198 VG_STATIC void world_routes_place_curve( world_instance *world,
199 v4f h[4], v3f n0, v3f n2 )
200 {
201 float t;
202 v3f p, pd;
203 int last_valid;
204
205 float total_length = 0.0f,
206 travel_length = 0.0;
207
208 v3f last;
209 v3_copy( h[0], last );
210 for( int it=0; it<128; it ++ ){
211 t = (float)(it+1) * (1.0f/128.0f);
212 eval_bezier3( h[0], h[1], h[2], t, p );
213 total_length += v3_dist( p, last );
214 v3_copy( p, last );
215 }
216
217 float patch_size = 4.0f,
218 patch_count = ceilf( total_length / patch_size );
219
220 t = 0.0f;
221 v3_copy( h[0], last );
222
223 for( int it=0; it<128; it ++ ){
224 float const k_sample_dist = 0.0025f,
225 k_line_width = 1.5f;
226
227 eval_bezier3( h[0], h[1], h[2], t, p );
228 eval_bezier3( h[0], h[1], h[2], t+k_sample_dist, pd );
229
230 travel_length += v3_dist( p, last );
231
232 float mod = k_sample_dist / v3_dist( p, pd );
233
234 v3f v0,up, right;
235
236 v3_muls( n0, -(1.0f-t), up );
237 v3_muladds( up, n2, -t, up );
238 v3_normalize( up );
239
240 v3_sub( pd,p,v0 );
241 v3_cross( up, v0, right );
242 v3_normalize( right );
243
244 float cur_x = (1.0f-t)*h[0][3] + t*h[2][3];
245
246 v3f sc, sa, sb, down;
247 v3_muladds( p, right, cur_x * k_line_width, sc );
248 v3_muladds( sc, up, 1.5f, sc );
249 v3_muladds( sc, right, k_line_width*0.95f, sa );
250 v3_muladds( sc, right, 0.0f, sb );
251 v3_muls( up, -1.0f, down );
252
253 ray_hit ha, hb;
254 ha.dist = 8.0f;
255 hb.dist = 8.0f;
256 if( ray_world( world, sa, down, &ha ) &&
257 ray_world( world, sb, down, &hb ))
258 {
259 scene_vert va, vb;
260
261 v3_muladds( ha.pos, up, 0.06f, va.co );
262 v3_muladds( hb.pos, up, 0.06f, vb.co );
263
264 scene_vert_pack_norm( &va, up );
265 scene_vert_pack_norm( &vb, up );
266
267 float t1 = (travel_length / total_length) * patch_count;
268 va.uv[0] = t1;
269 va.uv[1] = 0.0f;
270 vb.uv[0] = t1;
271 vb.uv[1] = 1.0f;
272
273 scene_push_vert( world->scene_lines, &va );
274 scene_push_vert( world->scene_lines, &vb );
275
276 if( last_valid ){
277 /* Connect them with triangles */
278 scene_push_tri( world->scene_lines, (u32[3]){
279 last_valid+0-2, last_valid+1-2, last_valid+2-2} );
280 scene_push_tri( world->scene_lines, (u32[3]){
281 last_valid+1-2, last_valid+3-2, last_valid+2-2} );
282 }
283
284 last_valid = world->scene_lines->vertex_count;
285 }
286 else
287 last_valid = 0;
288
289 if( t == 1.0f )
290 return;
291
292 t += 1.0f*mod;
293 if( t > 1.0f )
294 t = 1.0f;
295
296 v3_copy( p, last );
297 }
298 }
299
300 VG_STATIC void world_routes_create_mesh( world_instance *world, u32 route_id )
301 {
302 ent_route *route = mdl_arritm( &world->ent_route, route_id );
303 u32 last_valid = 0;
304
305 for( int i=0; i<route->checkpoints_count; i++ ){
306 int i0 = route->checkpoints_start+i,
307 i1 = route->checkpoints_start+((i+1)%route->checkpoints_count);
308
309 ent_checkpoint *c0 = mdl_arritm(&world->ent_checkpoint, i0),
310 *c1 = mdl_arritm(&world->ent_checkpoint, i1);
311
312 ent_gate *start_gate = mdl_arritm( &world->ent_gate, c0->gate_index );
313 start_gate = mdl_arritm( &world->ent_gate, start_gate->target );
314
315 ent_gate *end_gate = mdl_arritm( &world->ent_gate, c1->gate_index );
316
317 v4f p[3];
318
319 v3_add( (v3f){0.0f,0.1f,0.0f}, start_gate->co[0], p[0] );
320 p[0][3] = start_gate->ref_count;
321 p[0][3] -= (float)start_gate->ref_total * 0.5f;
322 start_gate->ref_count ++;
323
324 if( !c0->path_count )
325 continue;
326
327 /* this is so that we get nice flow through the gates */
328 v3f temp_alignments[2];
329 ent_gate *both[] = { start_gate, end_gate };
330
331 for( int j=0; j<2; j++ ){
332 int pi = c0->path_start + ((j==1)? c0->path_count-1: 0);
333
334 ent_path_index *index = mdl_arritm( &world->ent_path_index, pi );
335 ent_route_node *rn = mdl_arritm( &world->ent_route_node,
336 index->index );
337 v3f v0;
338 v3_sub( rn->co, both[j]->co[0], v0 );
339 float d = v3_dot( v0, both[j]->to_world[2] );
340
341 v3_muladds( both[j]->co[0], both[j]->to_world[2], d,
342 temp_alignments[j] );
343 v3_add( (v3f){0.0f,0.1f,0.0f}, temp_alignments[j], temp_alignments[j]);
344 }
345
346
347 for( int j=0; j<c0->path_count; j ++ ){
348 ent_path_index *index = mdl_arritm( &world->ent_path_index,
349 c0->path_start+j );
350 ent_route_node *rn = mdl_arritm( &world->ent_route_node,
351 index->index );
352 if( j==0 || j==c0->path_count-1 )
353 if( j == 0 )
354 v3_copy( temp_alignments[0], p[1] );
355 else
356 v3_copy( temp_alignments[1], p[1] );
357 else
358 v3_copy( rn->co, p[1] );
359
360 p[1][3] = rn->ref_count;
361 p[1][3] -= (float)rn->ref_total * 0.5f;
362 rn->ref_count ++;
363
364 if( j+1 < c0->path_count ){
365 index = mdl_arritm( &world->ent_path_index,
366 c0->path_start+j+1 );
367 rn = mdl_arritm( &world->ent_route_node, index->index );
368
369 if( j+1 == c0->path_count-1 )
370 v3_lerp( p[1], temp_alignments[1], 0.5f, p[2] );
371 else
372 v3_lerp( p[1], rn->co, 0.5f, p[2] );
373
374 p[2][3] = rn->ref_count;
375 p[2][3] -= (float)rn->ref_total * 0.5f;
376 }
377 else{
378 v3_copy( end_gate->co[0], p[2] );
379 v3_add( (v3f){0.0f,0.1f,0.0f}, p[2], p[2] );
380 p[2][3] = end_gate->ref_count;
381 p[2][3] -= (float)end_gate->ref_total * 0.5f;
382 end_gate->ref_count ++;
383 }
384
385 /* p0,p1,p2 bezier patch is complete
386 * --------------------------------------*/
387 v3f surf0, surf2, n0, n2;
388
389 if( bh_closest_point( world->geo_bh, p[0], surf0, 5.0f ) == -1 )
390 v3_add( (v3f){0.0f,-0.1f,0.0f}, p[0], surf0 );
391
392 if( bh_closest_point( world->geo_bh, p[2], surf2, 5.0f ) == -1 )
393 v3_add( (v3f){0.0f,-0.1f,0.0f}, p[2], surf2 );
394
395 v3_sub( surf0, p[0], n0 );
396 v3_sub( surf2, p[2], n2 );
397 v3_normalize( n0 );
398 v3_normalize( n2 );
399
400 world_routes_place_curve( world, p, n0, n2 );
401
402 /* --- */
403 v4_copy( p[2], p[0] );
404 }
405 }
406
407 scene_copy_slice( world->scene_lines, &route->sm );
408 }
409
410 /*
411 * Create the strips of colour that run through the world along course paths
412 */
413 VG_STATIC void world_routes_generate( world_instance *world )
414 {
415 vg_info( "Generating route meshes\n" );
416 world->scene_lines = scene_init( world_global.generic_heap, 200000, 300000 );
417
418 for( u32 i=0; i<mdl_arrcount(&world->ent_gate); i++ ){
419 ent_gate *gate = mdl_arritm( &world->ent_gate, i );
420 gate->ref_count = 0;
421 gate->ref_total = 0;
422 }
423
424 for( u32 i=0; i<mdl_arrcount(&world->ent_route_node); i++ ){
425 ent_route_node *rn = mdl_arritm( &world->ent_route, i );
426 rn->ref_count = 0;
427 rn->ref_total = 0;
428 }
429
430 for( u32 k=0; k<mdl_arrcount(&world->ent_route); k++ ){
431 ent_route *route = mdl_arritm( &world->ent_route, k );
432
433 for( int i=0; i<route->checkpoints_count; i++ ){
434 int i0 = route->checkpoints_start+i,
435 i1 = route->checkpoints_start+((i+1)%route->checkpoints_count);
436
437 ent_checkpoint *c0 = mdl_arritm(&world->ent_checkpoint, i0),
438 *c1 = mdl_arritm(&world->ent_checkpoint, i1);
439
440 ent_gate *start_gate = mdl_arritm( &world->ent_gate, c0->gate_index );
441 start_gate = mdl_arritm( &world->ent_gate, start_gate->target );
442
443 ent_gate *end_gate = mdl_arritm( &world->ent_gate, c1->gate_index );
444 start_gate->ref_total ++;
445
446 if( !c0->path_count )
447 continue;
448
449 for( int j=0; j<c0->path_count; j ++ ){
450 ent_path_index *index = mdl_arritm( &world->ent_path_index,
451 c0->path_start+j );
452 ent_route_node *rn = mdl_arritm( &world->ent_route_node,
453 index->index );
454 rn->ref_total ++;
455
456 if( j+1 < c0->path_count ){
457 }
458 else{
459 end_gate->ref_total ++;
460 }
461 }
462 }
463 }
464
465 for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ )
466 world_routes_create_mesh( world, i );
467
468 vg_acquire_thread_sync();
469 {
470 scene_upload( world->scene_lines, &world->mesh_route_lines );
471 }
472 vg_release_thread_sync();
473 vg_linear_del( world_global.generic_heap, world->scene_lines );
474
475 world_routes_clear( world );
476 }
477
478 /* load all routes from model header */
479 VG_STATIC void world_routes_ent_init( world_instance *world )
480 {
481 vg_info( "Initializing routes\n" );
482
483 for( u32 i=0; i<mdl_arrcount(&world->ent_gate); i++ ){
484 ent_gate *gate = mdl_arritm( &world->ent_gate, i );
485 for( u32 j=0; j<4; j++ ){
486 gate->routes[j] = 0xffff;
487 }
488 }
489
490 for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
491 ent_route *route = mdl_arritm(&world->ent_route,i);
492 mdl_transform_m4x3( &route->transform, route->board_transform );
493
494 route->official_track_id = 0xffffffff;
495 for( u32 j=0; j<vg_list_size(track_infos); j ++ ){
496 if( !strcmp(track_infos[j].name,
497 mdl_pstr(&world->meta,route->pstr_name))){
498 route->official_track_id = j;
499 }
500 }
501
502 for( u32 j=0; j<route->checkpoints_count; j++ ){
503 u32 id = route->checkpoints_start + j;
504 ent_checkpoint *cp = mdl_arritm(&world->ent_checkpoint,id);
505
506 ent_gate *gate = mdl_arritm( &world->ent_gate, cp->gate_index );
507
508 for( u32 k=0; k<4; k++ ){
509 if( gate->routes[k] == 0xffff ){
510 gate->routes[k] = i;
511 break;
512 }
513 }
514
515 if( gate->type == k_gate_type_teleport ){
516 gate = mdl_arritm(&world->ent_gate, gate->target );
517
518 for( u32 k=0; k<4; k++ ){
519 if( gate->routes[k] == 0xffff ){
520 gate->routes[k] = i;
521 break;
522 }
523 }
524 }
525 }
526 }
527
528 world_routes_clear( world );
529 }
530
531 /*
532 * -----------------------------------------------------------------------------
533 * Events
534 * -----------------------------------------------------------------------------
535 */
536
537 VG_STATIC void world_routes_init(void)
538 {
539 world_global.current_run_version = 200;
540 world_global.time = RESET_MAX_TIME*2.0;
541 world_global.last_use = 0.0;
542
543 shader_scene_route_register();
544 shader_routeui_register();
545 }
546
547 VG_STATIC void world_routes_update( world_instance *world )
548 {
549 world_global.time += vg.time_delta;
550
551 for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
552 ent_route *route = mdl_arritm( &world->ent_route, i );
553
554 int target = route->active_checkpoint == 0xffffffff? 0: 1;
555 route->factive = vg_lerpf( route->factive, target, 0.6f*vg.time_delta );
556 }
557 }
558
559 VG_STATIC void bind_terrain_noise(void);
560 VG_STATIC void world_bind_light_array( world_instance *world,
561 GLuint shader, GLuint location,
562 int slot );
563 VG_STATIC void world_bind_light_index( world_instance *world,
564 GLuint shader, GLuint location,
565 int slot );
566
567 VG_STATIC void render_world_routes( world_instance *world, camera *cam )
568 {
569 m4x3f identity_matrix;
570 m4x3_identity( identity_matrix );
571
572 shader_scene_route_use();
573 shader_scene_route_uTexGarbage(0);
574 world_link_lighting_ub( world, _shader_scene_route.id );
575 world_bind_position_texture( world, _shader_scene_route.id,
576 _uniform_scene_route_g_world_depth, 2 );
577 world_bind_light_array( world, _shader_scene_route.id,
578 _uniform_scene_route_uLightsArray, 3 );
579 world_bind_light_index( world, _shader_scene_route.id,
580 _uniform_scene_route_uLightsIndex, 4 );
581 bind_terrain_noise();
582
583 shader_scene_route_uPv( cam->mtx.pv );
584 shader_scene_route_uPvmPrev( cam->mtx_prev.pv );
585 shader_scene_route_uMdl( identity_matrix );
586 shader_scene_route_uCamera( cam->transform[3] );
587 shader_scene_route_uBoard0( TEMP_BOARD_0 );
588 shader_scene_route_uBoard1( TEMP_BOARD_1 );
589
590 mesh_bind( &world->mesh_route_lines );
591
592 for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
593 ent_route *route = mdl_arritm( &world->ent_route, i );
594
595 v4f colour;
596 v3_lerp( (v3f){0.7f,0.7f,0.7f}, route->colour, route->factive, colour );
597 colour[3] = route->factive*0.2f;
598
599 shader_scene_route_uColour( colour );
600 mdl_draw_submesh( &route->sm );
601 }
602
603 shader_model_gate_use();
604 shader_model_gate_uPv( cam->mtx.pv );
605 shader_model_gate_uCam( cam->pos );
606 shader_model_gate_uTime( vg.time*0.25f );
607 shader_model_gate_uInvRes( (v2f){
608 1.0f / (float)vg.window_x,
609 1.0f / (float)vg.window_y });
610
611 mesh_bind( &world_global.mesh_gate );
612
613 /* skip writing into the motion vectors for this */
614 glDrawBuffers( 1, (GLenum[]){ GL_COLOR_ATTACHMENT0 } );
615
616 for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
617 ent_route *route = mdl_arritm( &world->ent_route, i );
618
619 if( route->active_checkpoint != 0xffffffff ){
620 v4f colour;
621 float brightness = 0.3f + world->ub_lighting.g_day_phase;
622 v3_muls( route->colour, brightness, colour );
623 colour[3] = 1.0f-route->factive;
624
625 shader_model_gate_uColour( colour );
626
627 u32 next = route->checkpoints_start +
628 (route->active_checkpoint+1) % route->checkpoints_count;
629
630 ent_checkpoint *cp = mdl_arritm( &world->ent_checkpoint, next );
631 ent_gate *gate = mdl_arritm( &world->ent_gate, cp->gate_index );
632 shader_model_gate_uMdl( gate->to_world );
633
634 for( u32 j=0; j<4; j++ ){
635 if( gate->routes[j] == i ){
636 mdl_draw_submesh( &world_global.sm_gate_marker[j] );
637 break;
638 }
639 }
640 }
641 }
642 glDrawBuffers( 2, (GLenum[]){ GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 } );
643 }
644
645 #endif /* ROUTES_H */