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