2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
9 #include "world_gate.h"
11 #include "shaders/vblend.h"
12 #include "shaders/route.h"
13 #include "shaders/routeui.h"
16 enum route_special_type
18 k_route_special_type_gate
= 1,
19 k_route_special_type_collector
= 2
22 static void debug_sbpath( struct route_node
*rna
, struct route_node
*rnb
,
23 u32 colour
, float xoffset
)
25 v3f p0
, h0
, p1
, h1
, l
, p
;
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
);
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
);
39 for( int i
=0; i
<5; i
++ )
41 float t
= (float)(i
+1)/5.0f
;
42 eval_bezier_time( p0
, p1
, h0
, h1
, t
, p
);
43 vg_line( p
, l
, colour
);
49 * Get a list of node ids in stack, and return how many there is
51 static u32
world_routes_get_path( u32 starter
, u32 stack
[64] )
59 int loop_complete
= 0;
63 if( stack_i
[si
-1] == 2 )
69 struct route_node
*rn
= &world_routes
.nodes
[stack
[si
-1]];
70 u32 nextid
= rn
->next
[stack_i
[si
-1]];
73 if( nextid
!= 0xffffffff )
75 if( nextid
== stack
[0] )
82 for( int sj
=0; sj
<si
; sj
++ )
84 if( stack
[sj
] == nextid
)
108 * Free a segment from the UI bar to be reused later
110 static void world_routes_ui_popfirst( u32 route
)
112 struct route
*pr
= &world_routes
.routes
[route
];
114 if( pr
->ui
.segment_count
)
116 pr
->ui
.segment_start
++;
118 if( pr
->ui
.segment_start
== 32 )
119 pr
->ui
.segment_start
= 0;
121 pr
->ui
.segment_count
--;
126 * Reset ui bar completely
128 static void world_routes_ui_clear( u32 route
)
130 struct route
*pr
= &world_routes
.routes
[route
];
131 pr
->ui
.segment_start
= (pr
->ui
.segment_start
+ pr
->ui
.segment_count
) %
133 pr
->ui
.segment_count
= 0;
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.
140 static void world_routes_ui_split_indices( u32 s0
, u32 count
, u32
*c0
, u32
*c1
)
142 *c0
= (VG_MIN( s0
+count
, k_route_ui_max_indices
)) - s0
;
147 * Place a set of indices into gpu array automatically splits
150 static void world_routes_ui_set_indices( struct route
*pr
,
151 u16
*indices
, u32 count
)
154 world_routes_ui_split_indices( pr
->ui
.indices_head
, count
, &c0
, &c1
);
156 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER
, pr
->ui
.ebo
);
160 glBufferSubData( GL_ELEMENT_ARRAY_BUFFER
, pr
->ui
.indices_head
*sizeof(u16
),
161 c0
*sizeof(u16
), indices
);
166 glBufferSubData( GL_ELEMENT_ARRAY_BUFFER
, 0, c1
*sizeof(u16
), indices
+c0
);
167 pr
->ui
.indices_head
= c1
;
170 pr
->ui
.indices_head
+= c0
;
174 * Place a set of vertices into gpu array
176 static u32
world_routes_ui_set_verts( struct route
*pr
, v2f
*verts
, u32 count
)
178 if( pr
->ui
.vertex_head
+ count
>= k_route_ui_max_verts
)
179 pr
->ui
.vertex_head
= 0;
181 u32 vert_start
= pr
->ui
.vertex_head
;
182 pr
->ui
.vertex_head
+= count
;
184 glBindBuffer( GL_ARRAY_BUFFER
, pr
->ui
.vbo
);
185 glBufferSubData( GL_ARRAY_BUFFER
, (GLintptr
)(vert_start
*sizeof(v2f
)),
186 sizeof(v2f
)*count
, verts
);
192 * Update the last (count) vertices positions, does not add any.
193 * Data must already be written to, and not cross either array boundaries.
195 static u32
world_routes_ui_update_verts( struct route
*pr
,
196 v2f
*verts
, u32 count
)
198 u32 vert_start
= pr
->ui
.vertex_head
-count
;
200 glBindBuffer( GL_ARRAY_BUFFER
, pr
->ui
.vbo
);
201 glBufferSubData( GL_ARRAY_BUFFER
, (GLintptr
)(vert_start
*sizeof(v2f
)),
202 sizeof(v2f
)*count
, verts
);
208 * Current/active segment of this UI bar
210 static struct route_ui_segment
*world_routes_ui_curseg( struct route
*pr
)
212 u32 index
= (pr
->ui
.segment_start
+pr
->ui
.segment_count
-1)%k_max_ui_segments
;
213 return &pr
->ui
.segments
[ index
];
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)
220 static void world_routes_ui_newseg( u32 route
)
222 struct route
*pr
= &world_routes
.routes
[route
];
224 pr
->ui
.last_notch
= 0.0;
226 glBindVertexArray( pr
->ui
.vao
);
227 if( pr
->ui
.segment_count
)
229 float const k_gap_width
= 1.0f
;
231 struct route_ui_segment
*cseg
= world_routes_ui_curseg(pr
);
234 verts
[0][0] = cseg
->length
-k_gap_width
;
236 verts
[1][0] = cseg
->length
-k_gap_width
;
239 world_routes_ui_update_verts( pr
, verts
, 2 );
242 pr
->ui
.segment_count
++;
243 struct route_ui_segment
*segment
= world_routes_ui_curseg(pr
);
255 u32 vert_start
= world_routes_ui_set_verts( pr
, verts
, 4 );
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;
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;
271 world_routes_ui_set_indices( pr
, indices
, 6 );
275 * Extend the end of the bar
277 static void world_routes_ui_updatetime( u32 route
, float time
)
279 struct route
*pr
= &world_routes
.routes
[route
];
287 u32 vert_start
= pr
->ui
.vertex_head
-2;
289 glBindVertexArray( pr
->ui
.vao
);
290 world_routes_ui_update_verts( pr
, verts
, 2 );
292 struct route_ui_segment
*cseg
= world_routes_ui_curseg(pr
);
297 * Create a notch in the bar, used when a reset is triggered by the user
299 static void world_routes_ui_notch( u32 route
, float time
)
301 return; /* FIXME: Temporarily disabled */
303 struct route
*pr
= &world_routes
.routes
[route
];
305 if( (time
- pr
->ui
.last_notch
) > 1.0 )
307 struct route_ui_segment
*segment
= world_routes_ui_curseg(pr
);
308 if( segment
->notches
== k_max_ui_splits_per_segment
)
315 float const k_notch_width
= 1.0f
;
317 float xa
= time
-k_notch_width
,
318 xb
= time
-k_notch_width
* 0.5f
,
329 verts
[3][1] = -0.25f
;
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 );
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;
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;
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;
367 world_routes_ui_set_indices( pr
, indices
, 18 );
369 pr
->ui
.last_notch
= time
;
371 segment
->vertex_count
+= 6;
372 segment
->index_count
+= 18;
376 static void world_routes_ui_draw_segment( struct route_ui_segment
*segment
)
379 world_routes_ui_split_indices( segment
->index_start
,
380 segment
->index_count
, &c0
, &c1
);
382 glDrawElements( GL_TRIANGLES
, c0
, GL_UNSIGNED_SHORT
,
383 (void *)(segment
->index_start
*sizeof(u16
)));
385 glDrawElements( GL_TRIANGLES
, c1
, GL_UNSIGNED_SHORT
, (void *)(0) );
389 * Draws full bar at Y offset(offset).
391 static void world_routes_ui_draw( u32 route
, v4f colour
, float offset
)
393 float const k_bar_height
= 0.05f
,
394 k_bar_scale_x
= 0.005f
;
396 struct route
*pr
= &world_routes
.routes
[route
];
398 float cx
= pr
->ui
.xpos
;
400 shader_routeui_use();
401 glBindVertexArray( pr
->ui
.vao
);
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
);
406 float fade_block_size
= 0.0f
,
407 main_block_size
= 0.0f
;
409 for( u32 i
=0; i
<pr
->ui
.fade_count
; i
++ )
411 u32 j
= (pr
->ui
.fade_start
+ i
) % k_max_ui_segments
;
412 struct route_ui_segment
*segment
= &pr
->ui
.segments
[j
];
414 fade_block_size
+= segment
->length
;
417 cx
-= fade_block_size
* fade_amt
;
420 v4_copy( colour
, fade_colour
);
421 fade_colour
[3] *= 1.0f
-fade_amt
;
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
);
431 float height
= pr
->factive
*k_bar_height
* timer_scale
,
432 base
= -1.0f
+ (offset
+0.5f
)*k_bar_height
* timer_scale
;
434 shader_routeui_uColour( fade_colour
);
435 for( u32 i
=0; i
<pr
->ui
.fade_count
; i
++ )
437 u32 j
= (pr
->ui
.fade_start
+ i
) % k_max_ui_segments
;
438 struct route_ui_segment
*segment
= &pr
->ui
.segments
[j
];
440 shader_routeui_uOffset( (v4f
){ cx
*k_bar_scale_x
, base
,
441 k_bar_scale_x
, height
} );
443 world_routes_ui_draw_segment( segment
);
444 cx
+= segment
->length
;
450 shader_routeui_uColour( colour
);
451 for( u32 i
=0; i
<pr
->ui
.segment_count
; i
++ )
453 u32 j
= (pr
->ui
.segment_start
+ i
) % k_max_ui_segments
;
454 struct route_ui_segment
*segment
= &pr
->ui
.segments
[j
];
456 shader_routeui_uOffset( (v4f
){ cx
*k_bar_scale_x
, base
,
457 k_bar_scale_x
, height
} );
459 world_routes_ui_draw_segment( segment
);
460 cx
+= segment
->length
;
462 main_block_size
+= segment
->length
;
465 pr
->ui
.xpos
= vg_lerpf( pr
->ui
.xpos
, -main_block_size
* 0.5f
, 0.03f
);
468 static void world_routes_local_set_record( u32 route
, double lap_time
)
470 vg_success( " NEW LAP TIME: %f\n", lap_time
);
472 struct route
*pr
= &world_routes
.routes
[route
];
474 if( pr
->track_id
!= 0xffffffff )
476 double time_centiseconds
= lap_time
* 100.0;
477 if( time_centiseconds
> (float)0xfffe )
480 highscore_record temp
;
481 temp
.trackid
= pr
->track_id
;
482 temp
.datetime
= time(NULL
);
485 temp
.time
= time_centiseconds
;
487 highscores_push_record( &temp
);
489 struct track_info
*pti
= &track_infos
[ pr
->track_id
];
492 if( pti
->achievement_id
)
494 steam_set_achievement( pti
->achievement_id
);
495 steam_store_achievements();
500 vg_warn( "There is no associated track for this record...\n" );
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)
510 static void world_routes_verify_run( u32 route
)
512 struct route
*pr
= &world_routes
.routes
[route
];
515 u32 si
= world_routes_get_path( world_routes
.routes
[route
].start
, stack
);
518 * we only care about gates that ref gates, so shuffle down the array
520 struct route_timing
*timings
[64];
521 u32 sj
= 0, maxv
= 0, begin
= 0;
522 for( u32 i
=0; i
<si
; i
++ )
524 struct route_node
*inode
= &world_routes
.nodes
[stack
[i
]];
526 if( inode
->special_type
== k_route_special_type_collector
)
528 timings
[sj
++] = &world_routes
.collectors
[ inode
->special_id
].timing
;
530 else if( inode
->special_type
== k_route_special_type_gate
)
532 timings
[sj
++] = &world_routes
.gates
[inode
->special_id
].timing
;
536 for( u32 i
=0; i
<sj
; i
++ )
538 if( timings
[i
]->version
> maxv
)
540 maxv
= timings
[i
]->version
;
545 vg_info( "== begin verification (%u) ==\n", route
);
546 vg_info( " current version: %u\n", world_routes
.current_run_version
);
549 if( timings
[begin
]->version
== world_routes
.current_run_version
)
552 int valid_segment_count
= 0;
554 double lap_time
= 0.0;
556 for( u32 i
=0; i
<sj
; i
++ )
558 u32 j
= (sj
+begin
-i
-1) % sj
,
565 /* j1v should equal jv+1 */
566 if( timings
[j1
]->version
== timings
[j
]->version
+1 )
568 diff
= timings
[j1
]->time
- timings
[j
]->time
;
571 if( verified
&& diff
> 0.0 ) valid_segment_count
++;
578 vg_success( " [ %u %f ] %f\n", timings
[j1
]->time
,
579 timings
[j1
]->version
, diff
);
581 vg_warn( " [ %u %f ]\n", timings
[j1
]->time
, timings
[j1
]->version
);
584 pr
->ui
.fade_start
= pr
->ui
.segment_start
;
585 pr
->ui
.fade_count
= 0;
586 pr
->ui
.fade_timer_start
= world_routes
.time
;
588 int orig_seg_count
= pr
->ui
.segment_count
;
590 world_routes_ui_newseg( route
);
594 world_routes_local_set_record( route
, lap_time
);
595 world_routes_ui_popfirst(route
);
596 pr
->ui
.fade_count
++;
599 vg_info( " ctime: %f\n", lap_time
);
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
++ )
605 world_routes_ui_popfirst(route
);
606 pr
->ui
.fade_count
++;
609 world_routes
.routes
[route
].latest_pass
= world_routes
.time
;
613 * When going through a gate this is called for bookkeeping purposes
615 static void world_routes_activate_gate( u32 id
)
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]];
621 world_routes
.last_use
= world_routes
.time
;
623 struct route_collector
*rc
= &world_routes
.collectors
[ pdest
->special_id
];
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
++ )
630 struct route
*route
= &world_routes
.routes
[i
];
632 int was_active
= route
->active
;
635 for( u32 j
=0; j
<pdest
->ref_count
; j
++ )
637 if( pdest
->route_ids
[j
] == i
)
639 world_routes_verify_run( i
);
645 if( was_active
&& !route
->active
)
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
);
652 vg_success( "CLEARING -> %u %u \n", route
->ui
.fade_start
,
653 route
->ui
.fade_count
);
657 world_routes
.current_run_version
++;
659 rc
->timing
.version
= world_routes
.current_run_version
;
660 rc
->timing
.time
= world_routes
.time
;
661 world_routes
.current_run_version
++;
665 * Notify the UI system that we've reset the player
667 static void world_routes_notify_reset(void)
669 world_routes
.rewind_from
= world_routes
.time
;
670 world_routes
.rewind_to
= world_routes
.last_use
;
673 for( int i
=0; i
<r
->route_count
; i
++ )
675 struct route
*route
= &r
->routes
[i
];
678 world_routes_ui_notch( i
, r
->time
- route
->latest_pass
);
683 /* Rewind between the saved points in time */
684 static void world_routes_rollback_time( double t
)
687 vg_lerp( world_routes
.rewind_to
, world_routes
.rewind_from
, t
);
690 /* draw lines along the paths */
691 static void world_routes_debug(void)
694 for( int i
=0; i
<world_routes
.node_count
; i
++ )
696 struct route_node
*rn
= &world_routes
.nodes
[i
];
697 vg_line_pt3( rn
->co
, 1.0f
, rn
->special_type
? 0xffffff00: 0xff00b2ff );
700 for( int i
=0; i
<world_routes
.route_count
; i
++ )
702 struct route
*route
= &world_routes
.routes
[i
];
705 u32 si
= world_routes_get_path( route
->start
, stack
);
707 u32 colours
[] = { 0xfff58142, 0xff42cbf5, 0xff42f56c, 0xfff542b3,
710 u32 cc
= colours
[i
%vg_list_size(colours
)];
712 for( int sj
=0; sj
<si
; sj
++ )
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
);
722 for( int i
=0; i
<world_routes
.node_count
; i
++ )
724 struct route_node
*ri
= &world_routes
.nodes
[i
],
727 for( int j
=0; j
<2; j
++ )
729 if( ri
->next
[j
] != 0xffffffff )
731 rj
= &world_routes
.nodes
[ri
->next
[j
]];
732 vg_line( ri
->co
, rj
->co
, 0x20ffffff );
738 static void world_id_fixup( u32
*uid
, mdl_header
*mdl
)
741 *uid
= mdl_node_from_id( mdl
, *uid
)->sub_uid
;
746 static void world_routes_create_mesh( u32 route_id
)
748 struct route
*route
= &world_routes
.routes
[ route_id
];
751 u32 si
= world_routes_get_path( route
->start
, stack
);
755 for( int sj
=0; sj
<si
; sj
++ )
759 struct route_node
*rnj
= &world_routes
.nodes
[ stack
[sj
] ],
760 *rnk
= &world_routes
.nodes
[ stack
[sk
] ],
763 if( rnj
->special_type
&& rnk
->special_type
)
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
;
772 if( rnk
->special_type
)
774 rnl
= &world_routes
.nodes
[ rnk
->next
[0] ];
775 base_x1
= (float)rnl
->ref_count
*-0.5f
+ (float)rnl
->current_refs
;
783 v3f p0
, h0
, p1
, h1
, p
, pd
;
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
);
793 for( int it
=0; it
<256; it
++ )
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
);
799 float mod
= k_sample_dist
/ v3_dist( p
, pd
);
802 v3_muls( rnj
->up
, 1.0f
-t
, up
);
803 v3_muladds( up
, rnk
->up
, t
, up
);
806 v3_cross( up
, v0
, right
);
807 v3_normalize( right
);
809 float cur_x
= (1.0f
-t
)*base_x0
+ t
*base_x1
;
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
);
821 if( ray_world( sa
, down
, &ha
) &&
822 ray_world( sb
, down
, &hb
))
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
);
833 scene_push_vert( &world_routes
.scene_lines
, &va
);
834 scene_push_vert( &world_routes
.scene_lines
, &vb
);
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} );
845 last_valid
= world_routes
.scene_lines
.vertex_count
;
854 /* TODO special case for end of loop, need to add triangles
855 * between first and last rungs */
860 rnj
->current_refs
++;
863 scene_copy_slice( &world_routes
.scene_lines
, &route
->sm
);
867 * Create the strips of colour that run through the world along course paths
869 static int world_routes_create_all_meshes(void)
871 vg_info( "Generating route meshes\n" );
873 scene_init( &world_routes
.scene_lines
);
875 for( u32 i
=0; i
<world_routes
.route_count
; i
++ )
876 world_routes_create_mesh( i
);
878 vg_acquire_thread_sync();
880 scene_upload( &world_routes
.scene_lines
);
883 for( int i
=0; i
<world_routes
.route_count
; i
++ )
886 struct route
*route
= &world_routes
.routes
[i
];
888 glGenVertexArrays( 1, &route
->ui
.vao
);
889 glGenBuffers( 1, &route
->ui
.vbo
);
890 glGenBuffers( 1, &route
->ui
.ebo
);
891 glBindVertexArray( route
->ui
.vao
);
893 size_t stride
= sizeof(v2f
);
895 glBindBuffer( GL_ARRAY_BUFFER
, route
->ui
.vbo
);
896 glBufferData( GL_ARRAY_BUFFER
, k_route_ui_max_verts
*stride
,
897 NULL
, GL_DYNAMIC_DRAW
);
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
,
905 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
, stride
, (void *)0 );
906 glEnableVertexAttribArray( 0 );
910 vg_release_thread_sync();
912 scene_free_offline_buffers( &world_routes
.scene_lines
);
917 static void world_routes_loadfrom( mdl_header
*mdl
)
919 vg_info( "Initializing routes\n" );
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;
931 /* TODO Break this up */
932 for( int i
=0; i
<mdl
->node_count
; i
++ )
934 mdl_node
*pnode
= mdl_node_from_id(mdl
,i
);
937 if( pnode
->classtype
== k_classtype_route_node
||
938 pnode
->classtype
== k_classtype_gate
)
940 mdl_node_transform( pnode
, transform
);
941 pnode
->sub_uid
= world_routes
.node_count
;
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
) );
948 struct route_node
*rn
= &world_routes
.nodes
[world_routes
.node_count
];
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
);
957 rn
->current_refs
= 0;
958 rn
->special_type
= 0;
961 if( pnode
->classtype
== k_classtype_gate
)
963 struct classtype_gate
*inf
= mdl_get_entdata( mdl
, pnode
);
965 /* H is later scaled based on link distance */
966 v3_normalize( rn
->h
);
967 rn
->next
[0] = inf
->target
;
973 mdl_node
*pother
= mdl_node_from_id( mdl
, inf
->target
);
975 if( pother
->classtype
== k_classtype_gate
)
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
) );
982 struct route_gate
*rg
=
983 &world_routes
.gates
[world_routes
.gate_count
];
985 rg
->node_id
= world_routes
.node_count
;
986 rg
->timing
.time
= 0.0;
987 rg
->timing
.version
= 0;
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
);
995 gate_transform_update( &rg
->gate
);
996 rn
->special_type
= k_route_special_type_gate
;
997 rn
->special_id
= world_routes
.gate_count
;
999 world_routes
.gate_count
++;
1003 if( rn
->special_type
== 0 )
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
));
1011 struct route_collector
*rc
=
1012 &world_routes
.collectors
[world_routes
.collector_count
];
1013 rc
->timing
.time
= 0.0;
1014 rc
->timing
.version
= 0;
1016 rn
->special_type
= k_route_special_type_collector
;
1017 rn
->special_id
= world_routes
.collector_count
;
1019 world_routes
.collector_count
++;
1024 struct classtype_route_node
*inf
= mdl_get_entdata( mdl
, pnode
);
1025 rn
->next
[0] = inf
->target
;
1026 rn
->next
[1] = inf
->target1
;
1029 world_routes
.node_count
++;
1031 else if( pnode
->classtype
== k_classtype_route
)
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
) );
1039 struct route
*route
= &world_routes
.routes
[world_routes
.route_count
];
1040 memset( route
, 0, sizeof(struct route
) );
1042 v3_copy( inf
->colour
, route
->colour
);
1043 route
->colour
[3] = 1.0f
;
1046 route
->track_id
= 0xffffffff;
1047 for( u32 j
=0; j
<vg_list_size(track_infos
); j
++ )
1049 if( !strcmp( mdl_pstr(mdl
,pnode
->pstr_name
), track_infos
[j
].name
))
1051 route
->track_id
= j
;
1056 route
->start
= inf
->id_start
;
1058 route
->factive
= 0.0f
;
1059 mdl_node_transform( pnode
, route
->scoreboard_transform
);
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;
1070 world_routes
.route_count
++;
1075 * Apply correct system-local ids
1077 for( int i
=0; i
<world_routes
.node_count
; i
++ )
1079 struct route_node
*rn
= &world_routes
.nodes
[i
];
1081 for( int j
=0; j
<2; j
++ )
1082 world_id_fixup( &rn
->next
[j
], mdl
);
1085 for( int i
=0; i
<world_routes
.route_count
; i
++ )
1087 struct route
*route
= &world_routes
.routes
[i
];
1088 world_id_fixup( &route
->start
, mdl
);
1094 for( int i
=0; i
<world_routes
.route_count
; i
++ )
1096 struct route
*route
= &world_routes
.routes
[i
];
1099 u32 si
= world_routes_get_path( route
->start
, stack
);
1101 for( int sj
=0; sj
<si
; sj
++ )
1103 struct route_node
*rn
= &world_routes
.nodes
[ stack
[sj
] ];
1104 rn
->route_ids
[ rn
->ref_count
++ ] = i
;
1106 if( rn
->ref_count
> 4 )
1107 vg_warn( "Too many references on route node %i\n", i
);
1111 world_routes_create_all_meshes();
1115 * -----------------------------------------------------------------------------
1117 * -----------------------------------------------------------------------------
1120 static void world_routes_init(void)
1122 world_routes
.current_run_version
= 2;
1123 world_routes
.time
= RESET_MAX_TIME
*2.0;
1124 world_routes
.last_use
= 0.0;
1126 shader_route_register();
1127 shader_routeui_register();
1130 static void world_routes_free(void*_
)
1132 vg_free( world_routes
.nodes
);
1133 vg_free( world_routes
.routes
);
1134 vg_free( world_routes
.gates
);
1137 static void world_routes_update(void)
1139 world_routes
.time
+= vg
.time_delta
;
1141 for( int i
=0; i
<world_routes
.route_count
; i
++ )
1143 struct route
*route
= &world_routes
.routes
[i
];
1144 route
->factive
= vg_lerpf( route
->factive
, route
->active
,
1145 0.6f
*vg
.time_delta
);
1149 world_routes_ui_updatetime(i
, world_routes
.time
- route
->latest_pass
);
1154 static void bind_terrain_textures(void);
1155 static void render_world_routes( m4x4f projection
, v3f camera
)
1157 m4x3f identity_matrix
;
1158 m4x3_identity( identity_matrix
);
1161 shader_route_uTexGarbage(0);
1162 shader_link_standard_ub( _shader_route
.id
, 2 );
1163 bind_terrain_textures();
1165 shader_route_uPv( projection
);
1166 shader_route_uMdl( identity_matrix
);
1167 shader_route_uCamera( camera
);
1169 scene_bind( &world_routes
.scene_lines
);
1171 for( int i
=0; i
<world_routes
.route_count
; i
++ )
1173 struct route
*route
= &world_routes
.routes
[i
];
1176 v3_lerp( (v3f
){0.7f
,0.7f
,0.7f
}, route
->colour
, route
->factive
, colour
);
1179 shader_route_uColour( colour
);
1180 mdl_draw_submesh( &route
->sm
);
1184 static void render_world_routes_ui(void)
1187 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1188 glBlendEquation(GL_FUNC_ADD
);
1190 float active_offset
= 0.0f
;
1191 for( int i
=0; i
<world_routes
.route_count
; i
++ )
1193 struct route
*route
= &world_routes
.routes
[i
];
1194 world_routes_ui_draw( i
, route
->colour
, active_offset
);
1195 active_offset
+= route
->factive
;
1198 glDisable(GL_BLEND
);
1201 #endif /* ROUTES_H */