moved some stuff
[carveJwlIkooP6JGAAIwe30JlM.git] / world_routes.h
1 /*
2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #ifndef ROUTES_H
6 #define ROUTES_H
7
8 #include "world.h"
9 #include "world_gate.h"
10
11 #include "shaders/vblend.h"
12 #include "shaders/route.h"
13 #include "shaders/routeui.h"
14
15
16 enum route_special_type
17 {
18 k_route_special_type_gate = 1,
19 k_route_special_type_collector = 2
20 };
21
22 static void debug_sbpath( struct route_node *rna, struct route_node *rnb,
23 u32 colour, float xoffset )
24 {
25 v3f p0, h0, p1, h1, l, p;
26
27 v3_copy( rna->co, p0 );
28 v3_muladds( rna->co, rna->h, 1.0f, h0 );
29 v3_copy( rnb->co, p1 );
30 v3_muladds( rnb->co, rnb->h, -1.0f, h1 );
31
32 v3_muladds( p0, rna->right, xoffset, p0 );
33 v3_muladds( h0, rna->right, xoffset, h0 );
34 v3_muladds( p1, rnb->right, xoffset, p1 );
35 v3_muladds( h1, rnb->right, xoffset, h1 );
36
37 v3_copy( p0, l );
38
39 for( int i=0; i<5; i++ )
40 {
41 float t = (float)(i+1)/5.0f;
42 eval_bezier_time( p0, p1, h0, h1, t, p );
43 vg_line( p, l, colour );
44 v3_copy( p, l );
45 }
46 }
47
48 /*
49 * Get a list of node ids in stack, and return how many there is
50 */
51 static u32 world_routes_get_path( u32 starter, u32 stack[64] )
52 {
53 u32 stack_i[64];
54
55 stack[0] = starter;
56 stack_i[0] = 0;
57
58 u32 si = 1;
59 int loop_complete = 0;
60
61 while( si )
62 {
63 if( stack_i[si-1] == 2 )
64 {
65 si --;
66 continue;
67 }
68
69 struct route_node *rn = &world_routes.nodes[stack[si-1]];
70 u32 nextid = rn->next[stack_i[si-1]];
71 stack_i[si-1] ++;
72
73 if( nextid != 0xffffffff )
74 {
75 if( nextid == stack[0] )
76 {
77 loop_complete = 1;
78 break;
79 }
80
81 int valid = 1;
82 for( int sj=0; sj<si; sj++ )
83 {
84 if( stack[sj] == nextid )
85 {
86 valid = 0;
87 break;
88 }
89 }
90
91 if( valid )
92 {
93 stack_i[si] = 0;
94 stack[si] = nextid;
95 si ++;
96 continue;
97 }
98 }
99 }
100
101 if( loop_complete )
102 return si;
103
104 return 0;
105 }
106
107 /*
108 * Free a segment from the UI bar to be reused later
109 */
110 static void world_routes_ui_popfirst( u32 route )
111 {
112 struct route *pr = &world_routes.routes[route];
113
114 if( pr->ui.segment_count )
115 {
116 pr->ui.segment_start ++;
117
118 if( pr->ui.segment_start == 32 )
119 pr->ui.segment_start = 0;
120
121 pr->ui.segment_count --;
122 }
123 }
124
125 /*
126 * Reset ui bar completely
127 */
128 static void world_routes_ui_clear( u32 route )
129 {
130 struct route *pr = &world_routes.routes[route];
131 pr->ui.segment_start = (pr->ui.segment_start + pr->ui.segment_count) %
132 k_max_ui_segments;
133 pr->ui.segment_count = 0;
134 }
135
136 /*
137 * Break a index range into two pieces over the edge of the maximum it can
138 * store. s1 is 0 always, so its a ring buffer.
139 */
140 static void world_routes_ui_split_indices( u32 s0, u32 count, u32 *c0, u32 *c1 )
141 {
142 *c0 = (VG_MIN( s0+count, k_route_ui_max_indices )) - s0;
143 *c1 = count-(*c0);
144 }
145
146 /*
147 * Place a set of indices into gpu array automatically splits
148 * across bounds
149 */
150 static void world_routes_ui_set_indices( struct route *pr,
151 u16 *indices, u32 count )
152 {
153 u32 c0, c1;
154 world_routes_ui_split_indices( pr->ui.indices_head, count, &c0, &c1 );
155
156 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, pr->ui.ebo );
157
158 if( c0 )
159 {
160 glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, pr->ui.indices_head*sizeof(u16),
161 c0*sizeof(u16), indices );
162 }
163
164 if( c1 )
165 {
166 glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, 0, c1*sizeof(u16), indices+c0 );
167 pr->ui.indices_head = c1;
168 }
169 else
170 pr->ui.indices_head += c0;
171 }
172
173 /*
174 * Place a set of vertices into gpu array
175 */
176 static u32 world_routes_ui_set_verts( struct route *pr, v2f *verts, u32 count )
177 {
178 if( pr->ui.vertex_head + count >= k_route_ui_max_verts )
179 pr->ui.vertex_head = 0;
180
181 u32 vert_start = pr->ui.vertex_head;
182 pr->ui.vertex_head += count;
183
184 glBindBuffer( GL_ARRAY_BUFFER, pr->ui.vbo );
185 glBufferSubData( GL_ARRAY_BUFFER, (GLintptr)(vert_start*sizeof(v2f)),
186 sizeof(v2f)*count, verts );
187
188 return vert_start;
189 }
190
191 /*
192 * Update the last (count) vertices positions, does not add any.
193 * Data must already be written to, and not cross either array boundaries.
194 */
195 static u32 world_routes_ui_update_verts( struct route *pr,
196 v2f *verts, u32 count )
197 {
198 u32 vert_start = pr->ui.vertex_head-count;
199
200 glBindBuffer( GL_ARRAY_BUFFER, pr->ui.vbo );
201 glBufferSubData( GL_ARRAY_BUFFER, (GLintptr)(vert_start*sizeof(v2f)),
202 sizeof(v2f)*count, verts );
203
204 return vert_start;
205 }
206
207 /*
208 * Current/active segment of this UI bar
209 */
210 static struct route_ui_segment *world_routes_ui_curseg( struct route *pr )
211 {
212 u32 index = (pr->ui.segment_start+pr->ui.segment_count-1)%k_max_ui_segments;
213 return &pr->ui.segments[ index ];
214 }
215
216 /*
217 * Start a new segment in the UI bar, will create a split on the last one if
218 * there is one active currently. (api)
219 */
220 static void world_routes_ui_newseg( u32 route )
221 {
222 struct route *pr = &world_routes.routes[route];
223
224 pr->ui.last_notch = 0.0;
225
226 glBindVertexArray( pr->ui.vao );
227 if( pr->ui.segment_count )
228 {
229 float const k_gap_width = 1.0f;
230
231 struct route_ui_segment *cseg = world_routes_ui_curseg(pr);
232
233 v2f verts[2];
234 verts[0][0] = cseg->length-k_gap_width;
235 verts[0][1] = 0.5f;
236 verts[1][0] = cseg->length-k_gap_width;
237 verts[1][1] = -0.5f;
238
239 world_routes_ui_update_verts( pr, verts, 2 );
240 }
241
242 pr->ui.segment_count ++;
243 struct route_ui_segment *segment = world_routes_ui_curseg(pr);
244
245 v2f verts[4];
246 verts[0][0] = 0.0f;
247 verts[0][1] = 0.5f;
248 verts[1][0] = 0.0f;
249 verts[1][1] = -0.5f;
250 verts[2][0] = 0.0f;
251 verts[2][1] = 0.5f;
252 verts[3][0] = 0.0f;
253 verts[3][1] = -0.5f;
254
255 u32 vert_start = world_routes_ui_set_verts( pr, verts, 4 );
256
257 u16 indices[6];
258 indices[0] = vert_start + 0;
259 indices[1] = vert_start + 1;
260 indices[2] = vert_start + 3;
261 indices[3] = vert_start + 0;
262 indices[4] = vert_start + 3;
263 indices[5] = vert_start + 2;
264
265 segment->vertex_start = vert_start;
266 segment->vertex_count = 4;
267 segment->index_start = pr->ui.indices_head;
268 segment->index_count = 6;
269 segment->notches = 0;
270
271 world_routes_ui_set_indices( pr, indices, 6 );
272 }
273
274 /*
275 * Extend the end of the bar
276 */
277 static void world_routes_ui_updatetime( u32 route, float time )
278 {
279 struct route *pr = &world_routes.routes[route];
280
281 v2f verts[2];
282 verts[0][0] = time;
283 verts[0][1] = 0.5f;
284 verts[1][0] = time;
285 verts[1][1] = -0.5f;
286
287 u32 vert_start = pr->ui.vertex_head-2;
288
289 glBindVertexArray( pr->ui.vao );
290 world_routes_ui_update_verts( pr, verts, 2 );
291
292 struct route_ui_segment *cseg = world_routes_ui_curseg(pr);
293 cseg->length = time;
294 }
295
296 /*
297 * Create a notch in the bar, used when a reset is triggered by the user
298 */
299 static void world_routes_ui_notch( u32 route, float time )
300 {
301 return; /* FIXME: Temporarily disabled */
302
303 struct route *pr = &world_routes.routes[route];
304
305 if( (time - pr->ui.last_notch) > 1.0 )
306 {
307 struct route_ui_segment *segment = world_routes_ui_curseg(pr);
308 if( segment->notches == k_max_ui_splits_per_segment )
309 return;
310
311 segment->notches ++;
312
313 v2f verts[8];
314
315 float const k_notch_width = 1.0f;
316
317 float xa = time-k_notch_width,
318 xb = time-k_notch_width * 0.5f,
319 xc = time;
320
321 verts[0][0] = xa;
322 verts[0][1] = 0.5f;
323 verts[1][0] = xa;
324 verts[1][1] = -0.5f;
325
326 verts[2][0] = xb;
327 verts[2][1] = 0.25f;
328 verts[3][0] = xb;
329 verts[3][1] = -0.25f;
330
331 verts[4][0] = xc;
332 verts[4][1] = 0.5f;
333 verts[5][0] = xc;
334 verts[5][1] = -0.5f;
335
336 verts[6][0] = xc;
337 verts[6][1] = 0.5f;
338 verts[7][0] = xc;
339 verts[7][1] = -0.5f;
340
341 glBindVertexArray( pr->ui.vao );
342 u32 vert_start_mod = world_routes_ui_update_verts( pr, verts, 2 ),
343 vert_start_new = world_routes_ui_set_verts( pr, verts+2, 6 );
344
345 u16 indices[18];
346 indices[ 0] = vert_start_mod+1;
347 indices[ 1] = vert_start_new+0;
348 indices[ 2] = vert_start_mod+0;
349 indices[ 3] = vert_start_mod+1;
350 indices[ 4] = vert_start_new+1;
351 indices[ 5] = vert_start_new+0;
352
353 indices[ 6] = vert_start_new+0;
354 indices[ 7] = vert_start_new+1;
355 indices[ 8] = vert_start_new+3;
356 indices[ 9] = vert_start_new+0;
357 indices[10] = vert_start_new+3;
358 indices[11] = vert_start_new+2;
359
360 indices[12] = vert_start_new+3;
361 indices[13] = vert_start_new+4;
362 indices[14] = vert_start_new+2;
363 indices[15] = vert_start_new+3;
364 indices[16] = vert_start_new+5;
365 indices[17] = vert_start_new+4;
366
367 world_routes_ui_set_indices( pr, indices, 18 );
368
369 pr->ui.last_notch = time;
370
371 segment->vertex_count += 6;
372 segment->index_count += 18;
373 }
374 }
375
376 static void world_routes_ui_draw_segment( struct route_ui_segment *segment )
377 {
378 u32 c0, c1;
379 world_routes_ui_split_indices( segment->index_start,
380 segment->index_count, &c0, &c1 );
381 if( c0 )
382 glDrawElements( GL_TRIANGLES, c0, GL_UNSIGNED_SHORT,
383 (void *)(segment->index_start*sizeof(u16)));
384 if( c1 )
385 glDrawElements( GL_TRIANGLES, c1, GL_UNSIGNED_SHORT, (void *)(0) );
386 }
387
388 /*
389 * Draws full bar at Y offset(offset).
390 */
391 static void world_routes_ui_draw( u32 route, v4f colour, float offset )
392 {
393 float const k_bar_height = 0.05f,
394 k_bar_scale_x = 0.005f;
395
396 struct route *pr = &world_routes.routes[route];
397
398 float cx = pr->ui.xpos;
399
400 shader_routeui_use();
401 glBindVertexArray( pr->ui.vao );
402
403 float fade_amt = world_routes.time - pr->ui.fade_timer_start;
404 fade_amt = vg_clampf( fade_amt / 1.0f, 0.0f, 1.0f );
405
406 float fade_block_size = 0.0f,
407 main_block_size = 0.0f;
408
409 for( u32 i=0; i<pr->ui.fade_count; i++ )
410 {
411 u32 j = (pr->ui.fade_start + i) % k_max_ui_segments;
412 struct route_ui_segment *segment = &pr->ui.segments[j];
413
414 fade_block_size += segment->length;
415 }
416
417 cx -= fade_block_size * fade_amt;
418
419 v4f fade_colour;
420 v4_copy( colour, fade_colour );
421 fade_colour[3] *= 1.0f-fade_amt;
422
423 /* 1 minute timer */
424 float timer_delta = (world_routes.time - world_routes.last_use) * (1.0/45.0),
425 timer_scale = 1.0f - vg_minf( timer_delta, 1.0f );
426
427 /*
428 * Draw fadeout bar
429 */
430
431 float height = pr->factive*k_bar_height * timer_scale,
432 base = -1.0f + (offset+0.5f)*k_bar_height * timer_scale;
433
434 shader_routeui_uColour( fade_colour );
435 for( u32 i=0; i<pr->ui.fade_count; i++ )
436 {
437 u32 j = (pr->ui.fade_start + i) % k_max_ui_segments;
438 struct route_ui_segment *segment = &pr->ui.segments[j];
439
440 shader_routeui_uOffset( (v4f){ cx*k_bar_scale_x, base,
441 k_bar_scale_x, height } );
442
443 world_routes_ui_draw_segment( segment );
444 cx += segment->length;
445 }
446
447 /*
448 * Draw main bar
449 */
450 shader_routeui_uColour( colour );
451 for( u32 i=0; i<pr->ui.segment_count; i++ )
452 {
453 u32 j = (pr->ui.segment_start + i) % k_max_ui_segments;
454 struct route_ui_segment *segment = &pr->ui.segments[j];
455
456 shader_routeui_uOffset( (v4f){ cx*k_bar_scale_x, base,
457 k_bar_scale_x, height } );
458
459 world_routes_ui_draw_segment( segment );
460 cx += segment->length;
461
462 main_block_size += segment->length;
463 }
464
465 pr->ui.xpos = vg_lerpf( pr->ui.xpos, -main_block_size * 0.5f, 0.03f );
466 }
467
468 static void world_routes_local_set_record( u32 route, double lap_time )
469 {
470 vg_success( " NEW LAP TIME: %f\n", lap_time );
471
472 struct route *pr = &world_routes.routes[route];
473
474 if( pr->track_id != 0xffffffff )
475 {
476 double time_centiseconds = lap_time * 100.0;
477 if( time_centiseconds > (float)0xfffe )
478 return;
479
480 highscore_record temp;
481 temp.trackid = pr->track_id;
482 temp.datetime = time(NULL);
483 temp.playerid = 0;
484 temp.points = 0;
485 temp.time = time_centiseconds;
486
487 highscores_push_record( &temp );
488
489 struct track_info *pti = &track_infos[ pr->track_id ];
490 pti->push = 1;
491
492 if( pti->achievement_id )
493 {
494 steam_set_achievement( pti->achievement_id );
495 steam_store_achievements();
496 }
497 }
498 else
499 {
500 vg_warn( "There is no associated track for this record...\n" );
501 }
502 }
503
504 /*
505 * Will scan the whole run for two things;
506 * 1: we set a new record for the total, complete loop around the course
507 * 2: the time of each segment will be recorded into the data buffer
508 * (not implemented: TODO)
509 */
510 static void world_routes_verify_run( u32 route )
511 {
512 struct route *pr = &world_routes.routes[route];
513
514 u32 stack[64];
515 u32 si = world_routes_get_path( world_routes.routes[route].start, stack );
516
517 /*
518 * we only care about gates that ref gates, so shuffle down the array
519 */
520 struct route_timing *timings[64];
521 u32 sj = 0, maxv = 0, begin = 0;
522 for( u32 i=0; i<si; i++ )
523 {
524 struct route_node *inode = &world_routes.nodes[stack[i]];
525
526 if( inode->special_type == k_route_special_type_collector )
527 {
528 timings[sj ++] = &world_routes.collectors[ inode->special_id ].timing;
529 }
530 else if( inode->special_type == k_route_special_type_gate )
531 {
532 timings[sj ++] = &world_routes.gates[inode->special_id].timing;
533 }
534 }
535
536 for( u32 i=0; i<sj; i++ )
537 {
538 if( timings[i]->version > maxv )
539 {
540 maxv = timings[i]->version;
541 begin = i;
542 }
543 }
544
545 vg_info( "== begin verification (%u) ==\n", route );
546 vg_info( " current version: %u\n", world_routes.current_run_version );
547
548 int verified = 0;
549 if( timings[begin]->version == world_routes.current_run_version )
550 verified = 1;
551
552 int valid_segment_count = 0;
553
554 double lap_time = 0.0;
555
556 for( u32 i=0; i<sj; i++ )
557 {
558 u32 j = (sj+begin-i-1) % sj,
559 j1 = (j+1) % sj;
560
561 double diff = 0.0;
562
563 if( i<sj-1 )
564 {
565 /* j1v should equal jv+1 */
566 if( timings[j1]->version == timings[j]->version+1 )
567 {
568 diff = timings[j1]->time - timings[j]->time;
569 lap_time += diff;
570
571 if( verified && diff > 0.0 ) valid_segment_count ++;
572 }
573 else
574 verified = 0;
575 }
576
577 if( verified )
578 vg_success( " [ %u %f ] %f\n", timings[j1]->time,
579 timings[j1]->version, diff );
580 else
581 vg_warn( " [ %u %f ]\n", timings[j1]->time, timings[j1]->version );
582 }
583
584 pr->ui.fade_start = pr->ui.segment_start;
585 pr->ui.fade_count = 0;
586 pr->ui.fade_timer_start = world_routes.time;
587
588 int orig_seg_count = pr->ui.segment_count;
589
590 world_routes_ui_newseg( route );
591
592 if( verified )
593 {
594 world_routes_local_set_record( route, lap_time );
595 world_routes_ui_popfirst(route);
596 pr->ui.fade_count ++;
597 }
598 else
599 vg_info( " ctime: %f\n", lap_time );
600
601 /* remove any excess we had from previous runs */
602 int to_remove = orig_seg_count-valid_segment_count;
603 for( int i=0; i<to_remove; i++ )
604 {
605 world_routes_ui_popfirst(route);
606 pr->ui.fade_count ++;
607 }
608
609 world_routes.routes[route].latest_pass = world_routes.time;
610 }
611
612 /*
613 * When going through a gate this is called for bookkeeping purposes
614 */
615 static void world_routes_activate_gate( u32 id )
616 {
617 struct route_gate *rg = &world_routes.gates[id];
618 struct route_node *pnode = &world_routes.nodes[rg->node_id],
619 *pdest = &world_routes.nodes[pnode->next[0]];
620
621 world_routes.last_use = world_routes.time;
622
623 struct route_collector *rc = &world_routes.collectors[ pdest->special_id ];
624
625 world_routes.active_gate = id;
626 rg->timing.version = world_routes.current_run_version;
627 rg->timing.time = world_routes.time;
628 for( u32 i=0; i<world_routes.route_count; i++ )
629 {
630 struct route *route = &world_routes.routes[i];
631
632 int was_active = route->active;
633
634 route->active = 0;
635 for( u32 j=0; j<pdest->ref_count; j++ )
636 {
637 if( pdest->route_ids[j] == i )
638 {
639 world_routes_verify_run( i );
640 route->active = 1;
641 break;
642 }
643 }
644
645 if( was_active && !route->active )
646 {
647 route->ui.fade_start = route->ui.segment_start;
648 route->ui.fade_count = route->ui.segment_count;
649 route->ui.fade_timer_start = world_routes.time;
650 world_routes_ui_clear(i);
651
652 vg_success( "CLEARING -> %u %u \n", route->ui.fade_start,
653 route->ui.fade_count );
654 }
655 }
656
657 world_routes.current_run_version ++;
658
659 rc->timing.version = world_routes.current_run_version;
660 rc->timing.time = world_routes.time;
661 world_routes.current_run_version ++;
662 }
663
664 /*
665 * Notify the UI system that we've reset the player
666 */
667 static void world_routes_notify_reset(void)
668 {
669 world_routes.rewind_from = world_routes.time;
670 world_routes.rewind_to = world_routes.last_use;
671
672 #if 0
673 for( int i=0; i<r->route_count; i++ )
674 {
675 struct route *route = &r->routes[i];
676
677 if( route->active )
678 world_routes_ui_notch( i, r->time - route->latest_pass );
679 }
680 #endif
681 }
682
683 /* Rewind between the saved points in time */
684 static void world_routes_rollback_time( double t )
685 {
686 world_routes.time =
687 vg_lerp( world_routes.rewind_to, world_routes.rewind_from, t );
688 }
689
690 /* draw lines along the paths */
691 static void world_routes_debug(void)
692 {
693
694 for( int i=0; i<world_routes.node_count; i++ )
695 {
696 struct route_node *rn = &world_routes.nodes[i];
697 vg_line_pt3( rn->co, 1.0f, rn->special_type? 0xffffff00: 0xff00b2ff );
698 }
699
700 for( int i=0; i<world_routes.route_count; i++ )
701 {
702 struct route *route = &world_routes.routes[i];
703
704 u32 stack[64];
705 u32 si = world_routes_get_path( route->start, stack );
706
707 u32 colours[] = { 0xfff58142, 0xff42cbf5, 0xff42f56c, 0xfff542b3,
708 0xff5442f5 };
709
710 u32 cc = colours[i%vg_list_size(colours)];
711
712 for( int sj=0; sj<si; sj++ )
713 {
714 int sk = (sj+1)%si;
715
716 struct route_node *pj = &world_routes.nodes[stack[sj]],
717 *pk = &world_routes.nodes[stack[sk]];
718 debug_sbpath( pj, pk, cc, (float)i );
719 }
720 }
721
722 for( int i=0; i<world_routes.node_count; i++ )
723 {
724 struct route_node *ri = &world_routes.nodes[i],
725 *rj = NULL;
726
727 for( int j=0; j<2; j++ )
728 {
729 if( ri->next[j] != 0xffffffff )
730 {
731 rj = &world_routes.nodes[ri->next[j]];
732 vg_line( ri->co, rj->co, 0x20ffffff );
733 }
734 }
735 }
736 }
737
738 static void world_id_fixup( u32 *uid, mdl_header *mdl )
739 {
740 if( *uid )
741 *uid = mdl_node_from_id( mdl, *uid )->sub_uid;
742 else
743 *uid = 0xffffffff;
744 }
745
746 static void world_routes_create_mesh( u32 route_id )
747 {
748 struct route *route = &world_routes.routes[ route_id ];
749
750 u32 stack[64];
751 u32 si = world_routes_get_path( route->start, stack );
752
753 u32 last_valid = 0;
754
755 for( int sj=0; sj<si; sj++ )
756 {
757 int sk=(sj+1)%si;
758
759 struct route_node *rnj = &world_routes.nodes[ stack[sj] ],
760 *rnk = &world_routes.nodes[ stack[sk] ],
761 *rnl;
762
763 if( rnj->special_type && rnk->special_type )
764 {
765 last_valid = 0;
766 continue;
767 }
768
769 float base_x0 = (float)rnj->ref_count*-0.5f + (float)rnj->current_refs,
770 base_x1 = (float)rnk->ref_count*-0.5f + (float)rnk->current_refs;
771
772 if( rnk->special_type )
773 {
774 rnl = &world_routes.nodes[ rnk->next[0] ];
775 base_x1 = (float)rnl->ref_count*-0.5f + (float)rnl->current_refs;
776 }
777
778 if( sk == 0 )
779 {
780 base_x1 -= 1.0f;
781 }
782
783 v3f p0, h0, p1, h1, p, pd;
784
785 v3_copy( rnj->co, p0 );
786 v3_muladds( rnj->co, rnj->h, 1.0f, h0 );
787 v3_copy( rnk->co, p1 );
788 v3_muladds( rnk->co, rnk->h, -1.0f, h1 );
789
790 float t=0.0f;
791 int it = 0;
792
793 for( int it=0; it<256; it ++ )
794 {
795 float const k_sample_dist = 0.02f;
796 eval_bezier_time( p0,p1,h0,h1, t,p );
797 eval_bezier_time( p0,p1,h0,h1, t+k_sample_dist,pd );
798
799 float mod = k_sample_dist / v3_dist( p, pd );
800
801 v3f v0,up, right;
802 v3_muls( rnj->up, 1.0f-t, up );
803 v3_muladds( up, rnk->up, t, up );
804
805 v3_sub( pd,p,v0 );
806 v3_cross( up, v0, right );
807 v3_normalize( right );
808
809 float cur_x = (1.0f-t)*base_x0 + t*base_x1;
810
811 v3f sc, sa, sb, down;
812 v3_muladds( p, right, cur_x, sc );
813 v3_muladds( sc, up, 1.5f, sc );
814 v3_muladds( sc, right, 0.45f, sa );
815 v3_muladds( sc, right, -0.45f, sb );
816 v3_muls( up, -1.0f, down );
817
818 ray_hit ha, hb;
819 ha.dist = 8.0f;
820 hb.dist = 8.0f;
821 if( ray_world( sa, down, &ha ) &&
822 ray_world( sb, down, &hb ))
823 {
824 mdl_vert va, vb;
825
826 v3_muladds( ha.pos, up, 0.06f, va.co );
827 v3_muladds( hb.pos, up, 0.06f, vb.co );
828 v3_copy( up, va.norm );
829 v3_copy( up, vb.norm );
830 v2_zero( va.uv );
831 v2_zero( vb.uv );
832
833 scene_push_vert( &world_routes.scene_lines, &va );
834 scene_push_vert( &world_routes.scene_lines, &vb );
835
836 if( last_valid )
837 {
838 /* Connect them with triangles */
839 scene_push_tri( &world_routes.scene_lines, (u32[3]){
840 last_valid+0-2, last_valid+1-2, last_valid+2-2} );
841 scene_push_tri( &world_routes.scene_lines, (u32[3]){
842 last_valid+1-2, last_valid+3-2, last_valid+2-2} );
843 }
844
845 last_valid = world_routes.scene_lines.vertex_count;
846 }
847 else
848 last_valid = 0;
849
850 t += 1.0f*mod;
851
852 if( t >= 1.0f )
853 {
854 /* TODO special case for end of loop, need to add triangles
855 * between first and last rungs */
856 break;
857 }
858 }
859
860 rnj->current_refs ++;
861 }
862
863 scene_copy_slice( &world_routes.scene_lines, &route->sm );
864 }
865
866 /*
867 * Create the strips of colour that run through the world along course paths
868 */
869 static int world_routes_create_all_meshes(void)
870 {
871 vg_info( "Generating route meshes\n" );
872
873 scene_init( &world_routes.scene_lines );
874
875 for( u32 i=0; i<world_routes.route_count; i++ )
876 world_routes_create_mesh( i );
877
878 vg_acquire_thread_sync();
879 {
880 scene_upload( &world_routes.scene_lines );
881
882 /* UI buffers */
883 for( int i=0; i<world_routes.route_count; i++ )
884 {
885 /* OpenGL strips */
886 struct route *route = &world_routes.routes[i];
887
888 glGenVertexArrays( 1, &route->ui.vao );
889 glGenBuffers( 1, &route->ui.vbo );
890 glGenBuffers( 1, &route->ui.ebo );
891 glBindVertexArray( route->ui.vao );
892
893 size_t stride = sizeof(v2f);
894
895 glBindBuffer( GL_ARRAY_BUFFER, route->ui.vbo );
896 glBufferData( GL_ARRAY_BUFFER, k_route_ui_max_verts*stride,
897 NULL, GL_DYNAMIC_DRAW );
898
899 glBindVertexArray( route->ui.vao );
900 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, route->ui.ebo );
901 glBufferData( GL_ELEMENT_ARRAY_BUFFER,
902 k_route_ui_max_indices*sizeof(u16), NULL,
903 GL_DYNAMIC_DRAW );
904
905 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, stride, (void *)0 );
906 glEnableVertexAttribArray( 0 );
907 VG_CHECK_GL_ERR();
908 }
909 }
910 vg_release_thread_sync();
911
912 scene_free_offline_buffers( &world_routes.scene_lines );
913 return 1;
914 }
915
916
917 static void world_routes_loadfrom( mdl_header *mdl )
918 {
919 vg_info( "Initializing routes\n" );
920
921 world_routes.nodes = NULL;
922 world_routes.node_count = 0;
923 world_routes.node_cap = 0;
924 world_routes.routes = NULL;
925 world_routes.route_count = 0;
926 world_routes.route_cap = 0;
927 world_routes.gates = NULL;
928 world_routes.gate_count = 0;
929 world_routes.gate_cap = 0;
930
931 /* TODO Break this up */
932 for( int i=0; i<mdl->node_count; i++ )
933 {
934 mdl_node *pnode = mdl_node_from_id(mdl,i);
935 m4x3f transform;
936
937 if( pnode->classtype == k_classtype_route_node ||
938 pnode->classtype == k_classtype_gate )
939 {
940 mdl_node_transform( pnode, transform );
941 pnode->sub_uid = world_routes.node_count;
942
943 world_routes.nodes = buffer_reserve( world_routes.nodes,
944 world_routes.node_count,
945 &world_routes.node_cap, 1,
946 sizeof( struct route_node ) );
947
948 struct route_node *rn = &world_routes.nodes[world_routes.node_count];
949
950 v3_copy( transform[0], rn->right );
951 v3_normalize( rn->right );
952 v3_copy( transform[1], rn->up );
953 v3_normalize( rn->up );
954 v3_muls( transform[2], -1.0f, rn->h );
955 v3_copy( transform[3], rn->co );
956 rn->ref_count = 0;
957 rn->current_refs = 0;
958 rn->special_type = 0;
959 rn->special_id = 0;
960
961 if( pnode->classtype == k_classtype_gate )
962 {
963 struct classtype_gate *inf = mdl_get_entdata( mdl, pnode );
964
965 /* H is later scaled based on link distance */
966 v3_normalize( rn->h );
967 rn->next[0] = inf->target;
968 rn->next[1] = 0;
969
970 /* TODO */
971 if( inf->target )
972 {
973 mdl_node *pother = mdl_node_from_id( mdl, inf->target );
974
975 if( pother->classtype == k_classtype_gate )
976 {
977 world_routes.gates = buffer_reserve( world_routes.gates,
978 world_routes.gate_count,
979 &world_routes.gate_cap,
980 1, sizeof( struct route_gate ) );
981
982 struct route_gate *rg =
983 &world_routes.gates[world_routes.gate_count];
984
985 rg->node_id = world_routes.node_count;
986 rg->timing.time = 0.0;
987 rg->timing.version = 0;
988
989 v3_copy( pnode->co, rg->gate.co[0] );
990 v3_copy( pother->co, rg->gate.co[1] );
991 v4_copy( pnode->q, rg->gate.q[0] );
992 v4_copy( pother->q, rg->gate.q[1] );
993 v2_copy( inf->dims, rg->gate.dims );
994
995 gate_transform_update( &rg->gate );
996 rn->special_type = k_route_special_type_gate;
997 rn->special_id = world_routes.gate_count;
998
999 world_routes.gate_count ++;
1000 }
1001 }
1002
1003 if( rn->special_type == 0 )
1004 {
1005 world_routes.collectors = buffer_reserve(
1006 world_routes.collectors,
1007 world_routes.collector_count,
1008 &world_routes.collector_cap,
1009 1, sizeof( struct route_collector ));
1010
1011 struct route_collector *rc =
1012 &world_routes.collectors[world_routes.collector_count];
1013 rc->timing.time = 0.0;
1014 rc->timing.version = 0;
1015
1016 rn->special_type = k_route_special_type_collector;
1017 rn->special_id = world_routes.collector_count;
1018
1019 world_routes.collector_count ++;
1020 }
1021 }
1022 else
1023 {
1024 struct classtype_route_node *inf = mdl_get_entdata( mdl, pnode );
1025 rn->next[0] = inf->target;
1026 rn->next[1] = inf->target1;
1027 }
1028
1029 world_routes.node_count ++;
1030 }
1031 else if( pnode->classtype == k_classtype_route )
1032 {
1033 struct classtype_route *inf = mdl_get_entdata( mdl, pnode );
1034 world_routes.routes = buffer_reserve( world_routes.routes,
1035 world_routes.route_count,
1036 &world_routes.route_cap,
1037 1, sizeof( struct route ) );
1038
1039 struct route *route = &world_routes.routes[world_routes.route_count];
1040 memset( route, 0, sizeof(struct route) );
1041
1042 v3_copy( inf->colour, route->colour );
1043 route->colour[3] = 1.0f;
1044
1045
1046 route->track_id = 0xffffffff;
1047 for( u32 j=0; j<vg_list_size(track_infos); j++ )
1048 {
1049 if( !strcmp( mdl_pstr(mdl,pnode->pstr_name), track_infos[j].name ))
1050 {
1051 route->track_id = j;
1052 break;
1053 }
1054 }
1055
1056 route->start = inf->id_start;
1057 route->active = 0;
1058 route->factive = 0.0f;
1059 mdl_node_transform( pnode, route->scoreboard_transform );
1060
1061 route->ui.indices_head = k_route_ui_max_indices - 9;
1062 route->ui.vertex_head = k_route_ui_max_verts - 200;
1063 route->ui.segment_start = 0;
1064 route->ui.segment_count = 0;
1065 route->ui.last_notch = 0.0;
1066 route->ui.fade_start = 0;
1067 route->ui.fade_count = 0;
1068 route->ui.fade_timer_start = 0.0;
1069
1070 world_routes.route_count ++;
1071 }
1072 }
1073
1074 /*
1075 * Apply correct system-local ids
1076 */
1077 for( int i=0; i<world_routes.node_count; i++ )
1078 {
1079 struct route_node *rn = &world_routes.nodes[i];
1080
1081 for( int j=0; j<2; j++ )
1082 world_id_fixup( &rn->next[j], mdl );
1083 }
1084
1085 for( int i=0; i<world_routes.route_count; i++ )
1086 {
1087 struct route *route = &world_routes.routes[i];
1088 world_id_fixup( &route->start, mdl );
1089 }
1090
1091 /*
1092 * Gather references
1093 */
1094 for( int i=0; i<world_routes.route_count; i++ )
1095 {
1096 struct route *route = &world_routes.routes[i];
1097
1098 u32 stack[64];
1099 u32 si = world_routes_get_path( route->start, stack );
1100
1101 for( int sj=0; sj<si; sj++ )
1102 {
1103 struct route_node *rn = &world_routes.nodes[ stack[sj] ];
1104 rn->route_ids[ rn->ref_count ++ ] = i;
1105
1106 if( rn->ref_count > 4 )
1107 vg_warn( "Too many references on route node %i\n", i );
1108 }
1109 }
1110
1111 world_routes_create_all_meshes();
1112 }
1113
1114 /*
1115 * -----------------------------------------------------------------------------
1116 * Events
1117 * -----------------------------------------------------------------------------
1118 */
1119
1120 static void world_routes_init(void)
1121 {
1122 world_routes.current_run_version = 2;
1123 world_routes.time = RESET_MAX_TIME*2.0;
1124 world_routes.last_use = 0.0;
1125
1126 shader_route_register();
1127 shader_routeui_register();
1128 }
1129
1130 static void world_routes_free(void*_)
1131 {
1132 vg_free( world_routes.nodes );
1133 vg_free( world_routes.routes );
1134 vg_free( world_routes.gates );
1135 }
1136
1137 static void world_routes_update(void)
1138 {
1139 world_routes.time += vg.time_delta;
1140
1141 for( int i=0; i<world_routes.route_count; i++ )
1142 {
1143 struct route *route = &world_routes.routes[i];
1144 route->factive = vg_lerpf( route->factive, route->active,
1145 0.6f*vg.time_delta );
1146
1147 if( route->active )
1148 {
1149 world_routes_ui_updatetime(i, world_routes.time - route->latest_pass );
1150 }
1151 }
1152 }
1153
1154 static void bind_terrain_textures(void);
1155 static void render_world_routes( m4x4f projection, v3f camera )
1156 {
1157 m4x3f identity_matrix;
1158 m4x3_identity( identity_matrix );
1159
1160 shader_route_use();
1161 shader_route_uTexGarbage(0);
1162 shader_link_standard_ub( _shader_route.id, 2 );
1163 bind_terrain_textures();
1164
1165 shader_route_uPv( projection );
1166 shader_route_uMdl( identity_matrix );
1167 shader_route_uCamera( camera );
1168
1169 scene_bind( &world_routes.scene_lines );
1170
1171 for( int i=0; i<world_routes.route_count; i++ )
1172 {
1173 struct route *route = &world_routes.routes[i];
1174
1175 v4f colour;
1176 v3_lerp( (v3f){0.7f,0.7f,0.7f}, route->colour, route->factive, colour );
1177 colour[3] = 1.0f;
1178
1179 shader_route_uColour( colour );
1180 mdl_draw_submesh( &route->sm );
1181 }
1182 }
1183
1184 static void render_world_routes_ui(void)
1185 {
1186 glEnable(GL_BLEND);
1187 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1188 glBlendEquation(GL_FUNC_ADD);
1189
1190 float active_offset = 0.0f;
1191 for( int i=0; i<world_routes.route_count; i++ )
1192 {
1193 struct route *route = &world_routes.routes[i];
1194 world_routes_ui_draw( i, route->colour, active_offset );
1195 active_offset += route->factive;
1196 }
1197
1198 glDisable(GL_BLEND);
1199 }
1200
1201 #endif /* ROUTES_H */