2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
10 #include "world_gate.h"
13 #include "shaders/vblend.h"
16 #include "shaders/scene_route.h"
17 #include "shaders/routeui.h"
20 enum route_special_type
22 k_route_special_type_none
= 0,
23 k_route_special_type_gate
= 1,
24 k_route_special_type_collector
= 2
27 VG_STATIC
void debug_sbpath( struct route_node
*rna
, struct route_node
*rnb
,
28 u32 colour
, float xoffset
)
30 v3f p0
, h0
, p1
, h1
, l
, p
;
32 v3_copy( rna
->co
, p0
);
33 v3_muladds( rna
->co
, rna
->h
, 1.0f
, h0
);
34 v3_copy( rnb
->co
, p1
);
35 v3_muladds( rnb
->co
, rnb
->h
, -1.0f
, h1
);
37 v3_muladds( p0
, rna
->right
, xoffset
, p0
);
38 v3_muladds( h0
, rna
->right
, xoffset
, h0
);
39 v3_muladds( p1
, rnb
->right
, xoffset
, p1
);
40 v3_muladds( h1
, rnb
->right
, xoffset
, h1
);
44 for( int i
=0; i
<5; i
++ )
46 float t
= (float)(i
+1)/5.0f
;
47 eval_bezier_time( p0
, p1
, h0
, h1
, t
, p
);
48 vg_line( p
, l
, colour
);
54 * Get a list of node ids in stack, and return how many there is
56 VG_STATIC u32
world_routes_get_path( world_instance
*world
,
57 u32 starter
, u32 stack
[64] )
65 int loop_complete
= 0;
69 if( stack_i
[si
-1] == 2 )
75 struct route_node
*rn
= &world
->nodes
[stack
[si
-1]];
76 u32 nextid
= rn
->next
[stack_i
[si
-1]];
79 if( nextid
!= 0xffffffff )
81 if( nextid
== stack
[0] )
88 for( int sj
=0; sj
<si
; sj
++ )
90 if( stack
[sj
] == nextid
)
114 * Free a segment from the UI bar to be reused later
116 VG_STATIC
void world_routes_ui_popfirst( struct route_ui_bar
*pui
)
118 if( pui
->segment_count
)
120 pui
->segment_start
++;
122 if( pui
->segment_start
== 32 )
123 pui
->segment_start
= 0;
125 pui
->segment_count
--;
130 * Reset ui bar completely
132 VG_STATIC
void world_routes_ui_clear( struct route_ui_bar
*pui
)
134 pui
->segment_start
= (pui
->segment_start
+ pui
->segment_count
) %
136 pui
->segment_count
= 0;
140 * Break a index range into two pieces over the edge of the maximum it can
141 * store. s1 is 0 always, so its a ring buffer.
143 VG_STATIC
void world_routes_ui_split_indices( u32 s0
, u32 count
,
146 *c0
= (VG_MIN( s0
+count
, k_route_ui_max_indices
)) - s0
;
151 * Place a set of indices into gpu array automatically splits
154 VG_STATIC
void world_routes_ui_set_indices( struct route_ui_bar
*pui
,
155 u16
*indices
, u32 count
)
158 world_routes_ui_split_indices( pui
->indices_head
, count
, &c0
, &c1
);
160 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER
, pui
->ebo
);
164 glBufferSubData( GL_ELEMENT_ARRAY_BUFFER
, pui
->indices_head
*sizeof(u16
),
165 c0
*sizeof(u16
), indices
);
170 glBufferSubData( GL_ELEMENT_ARRAY_BUFFER
, 0, c1
*sizeof(u16
), indices
+c0
);
171 pui
->indices_head
= c1
;
174 pui
->indices_head
+= c0
;
178 * Place a set of vertices into gpu array
180 VG_STATIC u32
world_routes_ui_set_verts( struct route_ui_bar
*pui
,
181 v2f
*verts
, u32 count
)
183 if( pui
->vertex_head
+ count
>= k_route_ui_max_verts
)
184 pui
->vertex_head
= 0;
186 u32 vert_start
= pui
->vertex_head
;
187 pui
->vertex_head
+= count
;
189 glBindBuffer( GL_ARRAY_BUFFER
, pui
->vbo
);
190 glBufferSubData( GL_ARRAY_BUFFER
, (GLintptr
)(vert_start
*sizeof(v2f
)),
191 sizeof(v2f
)*count
, verts
);
197 * Update the last (count) vertices positions, does not add any.
198 * Data must already be written to, and not cross either array boundaries.
200 VG_STATIC u32
world_routes_ui_update_verts( struct route_ui_bar
*pui
,
201 v2f
*verts
, u32 count
)
203 u32 vert_start
= pui
->vertex_head
-count
;
205 glBindBuffer( GL_ARRAY_BUFFER
, pui
->vbo
);
206 glBufferSubData( GL_ARRAY_BUFFER
, (GLintptr
)(vert_start
*sizeof(v2f
)),
207 sizeof(v2f
)*count
, verts
);
213 * Current/active segment of this UI bar
215 VG_STATIC
struct route_ui_segment
*world_routes_ui_curseg(
216 struct route_ui_bar
*pui
)
218 u32 index
= (pui
->segment_start
+pui
->segment_count
-1)%k_max_ui_segments
;
219 return &pui
->segments
[ index
];
223 * Start a new segment in the UI bar, will create a split on the last one if
224 * there is one active currently. (api)
226 VG_STATIC
void world_routes_ui_newseg( u32 route
)
228 struct route_ui_bar
*pui
= &world_global
.ui_bars
[route
];
230 glBindVertexArray( pui
->vao
);
231 if( pui
->segment_count
)
233 float const k_gap_width
= 1.0f
;
235 struct route_ui_segment
*cseg
= world_routes_ui_curseg( pui
);
238 verts
[0][0] = cseg
->length
-k_gap_width
;
240 verts
[1][0] = cseg
->length
-k_gap_width
;
243 world_routes_ui_update_verts( pui
, verts
, 2 );
246 pui
->segment_count
++;
247 struct route_ui_segment
*segment
= world_routes_ui_curseg( pui
);
259 u32 vert_start
= world_routes_ui_set_verts( pui
, verts
, 4 );
262 indices
[0] = vert_start
+ 0;
263 indices
[1] = vert_start
+ 1;
264 indices
[2] = vert_start
+ 3;
265 indices
[3] = vert_start
+ 0;
266 indices
[4] = vert_start
+ 3;
267 indices
[5] = vert_start
+ 2;
269 segment
->vertex_start
= vert_start
;
270 segment
->vertex_count
= 4;
271 segment
->index_start
= pui
->indices_head
;
272 segment
->index_count
= 6;
273 segment
->notches
= 0;
275 world_routes_ui_set_indices( pui
, indices
, 6 );
279 * Extend the end of the bar
281 VG_STATIC
void world_routes_ui_updatetime( u32 route
, float time
)
283 struct route_ui_bar
*pui
= &world_global
.ui_bars
[route
];
291 u32 vert_start
= pui
->vertex_head
-2;
293 glBindVertexArray( pui
->vao
);
294 world_routes_ui_update_verts( pui
, verts
, 2 );
296 struct route_ui_segment
*cseg
= world_routes_ui_curseg( pui
);
300 VG_STATIC
void world_routes_ui_draw_segment( struct route_ui_segment
*segment
)
303 world_routes_ui_split_indices( segment
->index_start
,
304 segment
->index_count
, &c0
, &c1
);
306 glDrawElements( GL_TRIANGLES
, c0
, GL_UNSIGNED_SHORT
,
307 (void *)(segment
->index_start
*sizeof(u16
)));
309 glDrawElements( GL_TRIANGLES
, c1
, GL_UNSIGNED_SHORT
, (void *)(0) );
313 * Draws full bar at Y offset(offset).
315 VG_STATIC
void world_routes_ui_draw( world_instance
*world
,
316 u32 route
, v4f colour
, float offset
)
318 float const k_bar_height
= 0.05f
,
319 k_bar_scale_x
= 0.005f
;
321 /* FIXME(10) ID mishmatch */
322 struct route
*pr
= &world
->routes
[route
];
323 struct route_ui_bar
*pui
= &world_global
.ui_bars
[route
];
325 float cx
= pui
->xpos
;
327 shader_routeui_use();
328 glBindVertexArray( pui
->vao
);
330 float fade_amt
= world_global
.time
- pui
->fade_timer_start
;
331 fade_amt
= vg_clampf( fade_amt
/ 1.0f
, 0.0f
, 1.0f
);
333 float fade_block_size
= 0.0f
,
334 main_block_size
= 0.0f
;
336 for( u32 i
=0; i
<pui
->fade_count
; i
++ )
338 u32 j
= (pui
->fade_start
+ i
) % k_max_ui_segments
;
339 struct route_ui_segment
*segment
= &pui
->segments
[j
];
341 fade_block_size
+= segment
->length
;
344 cx
-= fade_block_size
* fade_amt
;
347 v4_copy( colour
, fade_colour
);
348 fade_colour
[3] *= 1.0f
-fade_amt
;
351 float timer_delta
= (world_global
.time
- world_global
.last_use
) * (1.0/45.0),
352 timer_scale
= 1.0f
- vg_minf( timer_delta
, 1.0f
);
358 float height
= pr
->factive
*k_bar_height
* timer_scale
,
359 base
= -1.0f
+ (offset
+0.5f
)*k_bar_height
* timer_scale
;
361 shader_routeui_uColour( fade_colour
);
362 for( u32 i
=0; i
<pui
->fade_count
; i
++ )
364 u32 j
= (pui
->fade_start
+ i
) % k_max_ui_segments
;
365 struct route_ui_segment
*segment
= &pui
->segments
[j
];
367 shader_routeui_uOffset( (v4f
){ cx
*k_bar_scale_x
, base
,
368 k_bar_scale_x
, height
} );
370 world_routes_ui_draw_segment( segment
);
371 cx
+= segment
->length
;
377 shader_routeui_uColour( colour
);
378 for( u32 i
=0; i
<pui
->segment_count
; i
++ )
380 u32 j
= (pui
->segment_start
+ i
) % k_max_ui_segments
;
381 struct route_ui_segment
*segment
= &pui
->segments
[j
];
383 shader_routeui_uOffset( (v4f
){ cx
*k_bar_scale_x
, base
,
384 k_bar_scale_x
, height
} );
386 world_routes_ui_draw_segment( segment
);
387 cx
+= segment
->length
;
389 main_block_size
+= segment
->length
;
392 pui
->xpos
= vg_lerpf( pui
->xpos
, -main_block_size
* 0.5f
, 0.03f
);
395 VG_STATIC
void world_routes_local_set_record( world_instance
*world
,
396 u32 route
, double lap_time
)
398 vg_success( " NEW LAP TIME: %f\n", lap_time
);
400 /* FIXME(10): ID mishmatch */
401 struct route
*pr
= &world
->routes
[route
];
403 if( pr
->track_id
!= 0xffffffff )
405 double time_centiseconds
= lap_time
* 100.0;
406 if( time_centiseconds
> (float)0xfffe )
409 highscore_record temp
;
410 temp
.trackid
= pr
->track_id
;
411 temp
.datetime
= time(NULL
);
414 temp
.time
= time_centiseconds
;
416 highscores_push_record( &temp
);
418 struct track_info
*pti
= &track_infos
[ pr
->track_id
];
421 if( pti
->achievement_id
)
423 steam_set_achievement( pti
->achievement_id
);
424 steam_store_achievements();
429 vg_warn( "There is no associated track for this record...\n" );
434 * Will scan the whole run for two things;
435 * 1: we set a new record for the total, complete loop around the course
436 * 2: the time of each segment will be recorded into the data buffer
437 * (not implemented: TODO)
439 VG_STATIC
void world_routes_verify_run( world_instance
*world
, u32 route
)
441 /* FIXME(10): ID mishmatch */
442 struct route
*pr
= &world
->routes
[route
];
443 struct route_ui_bar
*pui
= &world_global
.ui_bars
[route
];
446 u32 si
= world_routes_get_path( world
, world
->routes
[route
].start
, stack
);
449 * we only care about gates that ref gates, so shuffle down the array
451 struct route_timing
*timings
[64];
452 u32 sj
= 0, maxv
= 0, begin
= 0;
453 for( u32 i
=0; i
<si
; i
++ )
455 struct route_node
*inode
= &world
->nodes
[stack
[i
]];
457 if( inode
->special_type
== k_route_special_type_collector
)
459 timings
[sj
++] = &world
->collectors
[ inode
->special_id
].timing
;
461 else if( inode
->special_type
== k_route_special_type_gate
)
463 timings
[sj
++] = &world
->gates
[inode
->special_id
].timing
;
467 for( u32 i
=0; i
<sj
; i
++ )
469 if( timings
[i
]->version
> maxv
)
471 maxv
= timings
[i
]->version
;
476 vg_info( "== begin verification (%u) ==\n", route
);
477 vg_info( " current version: %u\n", world_global
.current_run_version
);
480 if( timings
[begin
]->version
== world_global
.current_run_version
)
483 int valid_segment_count
= 0;
485 double lap_time
= 0.0;
487 for( u32 i
=0; i
<sj
; i
++ )
489 u32 j
= (sj
+begin
-i
-1) % sj
,
496 /* j1v should equal jv+1 */
497 if( timings
[j1
]->version
== timings
[j
]->version
+1 )
499 diff
= timings
[j1
]->time
- timings
[j
]->time
;
502 if( verified
&& diff
> 0.0 ) valid_segment_count
++;
509 vg_success( " [ %u %f ] %f\n", timings
[j1
]->time
,
510 timings
[j1
]->version
, diff
);
512 vg_warn( " [ %u %f ]\n", timings
[j1
]->time
, timings
[j1
]->version
);
515 pui
->fade_start
= pui
->segment_start
;
517 pui
->fade_timer_start
= world_global
.time
;
519 int orig_seg_count
= pui
->segment_count
;
521 world_routes_ui_newseg( route
);
525 world_routes_local_set_record( world
, route
, lap_time
);
526 world_routes_ui_popfirst( pui
);
530 vg_info( " ctime: %f\n", lap_time
);
532 /* remove any excess we had from previous runs */
533 int to_remove
= orig_seg_count
-valid_segment_count
;
534 for( int i
=0; i
<to_remove
; i
++ )
536 world_routes_ui_popfirst( pui
);
540 world
->routes
[route
].latest_pass
= world_global
.time
;
543 VG_STATIC
void world_routes_clear( world_instance
*world
)
545 for( u32 i
=0; i
<world
->route_count
; i
++ )
547 struct route
*route
= &world
->routes
[i
];
550 world_global
.current_run_version
+= 4;
551 world_global
.last_use
= 0.0;
555 * When going through a gate this is called for bookkeeping purposes
557 VG_STATIC
void world_routes_activate_gate( world_instance
*world
, u32 id
)
559 struct route_gate
*rg
= &world
->gates
[id
];
560 struct route_node
*pnode
= &world
->nodes
[rg
->node_id
],
561 *pdest
= &world
->nodes
[pnode
->next
[0]];
563 world_global
.last_use
= world_global
.time
;
565 struct route_collector
*rc
= &world
->collectors
[ pdest
->special_id
];
567 world_global
.active_gate
= id
;
568 rg
->timing
.version
= world_global
.current_run_version
;
569 rg
->timing
.time
= world_global
.time
;
571 for( u32 i
=0; i
<world
->route_count
; i
++ )
573 struct route
*route
= &world
->routes
[i
];
575 int was_active
= route
->active
;
578 for( u32 j
=0; j
<pdest
->ref_count
; j
++ )
580 if( pdest
->route_ids
[j
] == i
)
582 world_routes_verify_run( world
, i
);
588 if( was_active
&& !route
->active
)
590 struct route_ui_bar
*pui
= &world_global
.ui_bars
[i
];
591 pui
->fade_start
= pui
->segment_start
;
592 pui
->fade_count
= pui
->segment_count
;
593 pui
->fade_timer_start
= world_global
.time
;
595 world_routes_ui_clear( pui
);
596 vg_success( "CLEARING -> %u %u \n", pui
->fade_start
,
601 world_global
.current_run_version
++;
603 rc
->timing
.version
= world_global
.current_run_version
;
604 rc
->timing
.time
= world_global
.time
;
605 world_global
.current_run_version
++;
609 * Notify the UI system that we've reset the player
611 VG_STATIC
void world_routes_notify_reset(void)
613 world_global
.rewind_from
= world_global
.time
;
614 world_global
.rewind_to
= world_global
.last_use
;
617 /* Rewind between the saved points in time */
618 VG_STATIC
void world_routes_rollback_time( double t
)
620 world_global
.time
= vg_lerp( world_global
.rewind_to
,
621 world_global
.rewind_from
, t
);
624 /* draw lines along the paths */
625 VG_STATIC
void world_routes_debug( world_instance
*world
)
627 for( int i
=0; i
<world
->node_count
; i
++ )
629 struct route_node
*rn
= &world
->nodes
[i
];
630 vg_line_pt3( rn
->co
, 1.0f
, rn
->special_type
? 0xffffff00: 0xff00b2ff );
633 for( int i
=0; i
<world
->route_count
; i
++ )
635 struct route
*route
= &world
->routes
[i
];
638 u32 si
= world_routes_get_path( world
, route
->start
, stack
);
640 u32 colours
[] = { 0xfff58142, 0xff42cbf5, 0xff42f56c, 0xfff542b3,
643 u32 cc
= colours
[i
%vg_list_size(colours
)];
645 for( int sj
=0; sj
<si
; sj
++ )
649 struct route_node
*pj
= &world
->nodes
[stack
[sj
]],
650 *pk
= &world
->nodes
[stack
[sk
]];
651 debug_sbpath( pj
, pk
, cc
, (float)i
);
655 for( int i
=0; i
<world
->node_count
; i
++ )
657 struct route_node
*ri
= &world
->nodes
[i
],
660 for( int j
=0; j
<2; j
++ )
662 if( ri
->next
[j
] != 0xffffffff )
664 rj
= &world
->nodes
[ri
->next
[j
]];
665 vg_line( ri
->co
, rj
->co
, 0x20ffffff );
671 VG_STATIC
void world_routes_create_mesh( world_instance
*world
, u32 route_id
)
673 struct route
*route
= &world
->routes
[ route_id
];
676 u32 si
= world_routes_get_path( world
, route
->start
, stack
);
680 for( int sj
=0; sj
<si
; sj
++ )
684 struct route_node
*rnj
= &world
->nodes
[ stack
[sj
] ],
685 *rnk
= &world
->nodes
[ stack
[sk
] ],
688 if( rnj
->special_type
&& rnk
->special_type
)
694 float base_x0
= (float)rnj
->ref_count
*-0.5f
+ (float)rnj
->current_refs
,
695 base_x1
= (float)rnk
->ref_count
*-0.5f
+ (float)rnk
->current_refs
;
697 if( rnk
->special_type
)
699 rnl
= &world
->nodes
[ rnk
->next
[0] ];
700 base_x1
= (float)rnl
->ref_count
*-0.5f
+ (float)rnl
->current_refs
;
708 v3f p0
, h0
, p1
, h1
, p
, pd
;
710 v3_copy( rnj
->co
, p0
);
711 v3_muladds( rnj
->co
, rnj
->h
, 1.0f
, h0
);
712 v3_copy( rnk
->co
, p1
);
713 v3_muladds( rnk
->co
, rnk
->h
, -1.0f
, h1
);
718 for( int it
=0; it
<256; it
++ )
720 float const k_sample_dist
= 0.02f
;
721 eval_bezier_time( p0
,p1
,h0
,h1
, t
,p
);
722 eval_bezier_time( p0
,p1
,h0
,h1
, t
+k_sample_dist
,pd
);
724 float mod
= k_sample_dist
/ v3_dist( p
, pd
);
727 v3_muls( rnj
->up
, 1.0f
-t
, up
);
728 v3_muladds( up
, rnk
->up
, t
, up
);
731 v3_cross( up
, v0
, right
);
732 v3_normalize( right
);
734 float cur_x
= (1.0f
-t
)*base_x0
+ t
*base_x1
;
736 v3f sc
, sa
, sb
, down
;
737 v3_muladds( p
, right
, cur_x
, sc
);
738 v3_muladds( sc
, up
, 1.5f
, sc
);
739 v3_muladds( sc
, right
, 0.45f
, sa
);
740 v3_muladds( sc
, right
, -0.45f
, sb
);
741 v3_muls( up
, -1.0f
, down
);
746 if( ray_world( world
, sa
, down
, &ha
) &&
747 ray_world( world
, sb
, down
, &hb
))
751 v3_muladds( ha
.pos
, up
, 0.06f
, va
.co
);
752 v3_muladds( hb
.pos
, up
, 0.06f
, vb
.co
);
754 scene_vert_pack_norm( &va
, up
);
755 scene_vert_pack_norm( &vb
, up
);
759 scene_push_vert( world
->scene_lines
, &va
);
760 scene_push_vert( world
->scene_lines
, &vb
);
764 /* Connect them with triangles */
765 scene_push_tri( world
->scene_lines
, (u32
[3]){
766 last_valid
+0-2, last_valid
+1-2, last_valid
+2-2} );
767 scene_push_tri( world
->scene_lines
, (u32
[3]){
768 last_valid
+1-2, last_valid
+3-2, last_valid
+2-2} );
771 last_valid
= world
->scene_lines
->vertex_count
;
780 /* TODO special case for end of loop, need to add triangles
781 * between first and last rungs */
786 rnj
->current_refs
++;
789 scene_copy_slice( world
->scene_lines
, &route
->sm
);
792 VG_STATIC
void world_scene_compute_light_clusters( world_instance
*world
,
795 * Create the strips of colour that run through the world along course paths
797 VG_STATIC
void world_routes_generate( world_instance
*world
)
799 vg_info( "Generating route meshes\n" );
800 world
->scene_lines
= scene_init( world_global
.generic_heap
, 200000, 300000 );
802 for( u32 i
=0; i
<world
->route_count
; i
++ )
803 world_routes_create_mesh( world
, i
);
805 world_scene_compute_light_clusters( world
, world
->scene_lines
);
807 vg_acquire_thread_sync();
809 scene_upload( world
->scene_lines
, &world
->mesh_route_lines
);
811 vg_release_thread_sync();
812 vg_linear_del( world_global
.generic_heap
, world
->scene_lines
);
815 /* determine if special type is required for this gate */
816 VG_STATIC
enum route_special_type
world_route_node_type( world_instance
*world
,
819 if( pnode
->classtype
== k_classtype_gate
)
821 struct classtype_gate
*inf
= mdl_get_entdata( world
->meta
, pnode
);
825 mdl_node
*pother
= mdl_node_from_id( world
->meta
, inf
->target
);
827 if( pother
->classtype
== k_classtype_gate
)
829 return k_route_special_type_gate
;
833 return k_route_special_type_collector
;
836 return k_route_special_type_none
;
839 /* count entities and allocate correct amount of memory in advance */
840 VG_STATIC
void world_routes_allocate( world_instance
*world
)
842 vg_info( "Allocating routes\n" );
850 for( int i
=0; i
<world
->meta
->info
.node_count
; i
++ )
852 mdl_node
*pnode
= mdl_node_from_id( world
->meta
, i
);
854 if( pnode
->classtype
== k_classtype_route_node
||
855 pnode
->classtype
== k_classtype_gate
)
857 pnode
->sub_uid
= node_count
;
859 enum route_special_type type
= world_route_node_type( world
, pnode
);
861 if( type
== k_route_special_type_gate
)
863 else if( type
== k_route_special_type_collector
)
868 else if( pnode
->classtype
== k_classtype_route
)
875 u32 node_size
= node_count
* sizeof(struct route_node
),
876 route_size
= route_count
* sizeof(struct route
),
877 gate_size
= gate_count
* sizeof(struct route_gate
),
878 collector_size
= collector_count
* sizeof(struct route_collector
);
880 world
->nodes
= vg_linear_alloc( world_global
.generic_heap
, node_size
);
881 world
->routes
= vg_linear_alloc( world_global
.generic_heap
, route_size
);
882 world
->gates
= vg_linear_alloc( world_global
.generic_heap
, gate_size
);
883 world
->collectors
= vg_linear_alloc( world_global
.generic_heap
,
887 /* create node from mdl node */
888 VG_STATIC
struct route_node
*world_routes_create_node( world_instance
*world
,
891 struct route_node
*rn
= &world
->nodes
[ world
->node_count
++ ];
894 mdl_node_transform( pnode
, transform
);
896 v3_copy( transform
[3], rn
->co
);
897 v3_copy( transform
[0], rn
->right
);
898 v3_copy( transform
[1], rn
->up
);
899 v3_muls( transform
[2], -1.0f
, rn
->h
);
900 v3_normalize( rn
->right
);
901 v3_normalize( rn
->up
);
903 rn
->next
[0] = 0xffffffff;
904 rn
->next
[1] = 0xffffffff;
906 rn
->special_type
= 0;
908 rn
->current_refs
= 0;
914 /* retrieve the correct node id from mdl subuid */
915 VG_STATIC u32
world_routes_get_subuid( world_instance
*world
, u32 target
)
920 return mdl_node_from_id( world
->meta
, target
)->sub_uid
;
924 VG_STATIC
void world_id_fixup( u32
*uid
, mdl_context
*mdl
)
927 *uid
= mdl_node_from_id( mdl
, *uid
)->sub_uid
;
933 /* process gate attachement onto node */
934 VG_STATIC
void world_routes_process_gate( world_instance
*world
,
935 struct route_node
*rn
,
938 struct classtype_gate
*inf
= mdl_get_entdata( world
->meta
, pnode
);
940 /* H is later scaled based on link distance */
941 v3_normalize( rn
->h
);
943 rn
->next
[0] = world_routes_get_subuid( world
, inf
->target
);
944 rn
->next
[1] = 0xffffffff;
945 rn
->special_type
= world_route_node_type( world
, pnode
);
947 /* process gate type */
948 if( rn
->special_type
== k_route_special_type_gate
)
950 mdl_node
*pother
= mdl_node_from_id( world
->meta
, inf
->target
);
952 struct route_gate
*rg
= &world
->gates
[ world
->gate_count
];
954 rg
->node_id
= world
->node_count
-1;
955 rg
->timing
.time
= 0.0;
956 rg
->timing
.version
= 0;
958 v3_copy( pnode
->co
, rg
->gate
.co
[0] );
959 v3_copy( pother
->co
, rg
->gate
.co
[1] );
960 v4_copy( pnode
->q
, rg
->gate
.q
[0] );
961 v4_copy( pother
->q
, rg
->gate
.q
[1] );
962 v2_copy( inf
->dims
, rg
->gate
.dims
);
964 gate_transform_update( &rg
->gate
);
965 rn
->special_id
= world
->gate_count
;
967 world
->gate_count
++;
970 /* process collector type */
971 else if( rn
->special_type
== k_route_special_type_collector
)
973 struct route_collector
*rc
=
974 &world
->collectors
[ world
->collector_count
];
976 rc
->timing
.time
= 0.0;
977 rc
->timing
.version
= 0;
979 rn
->special_id
= world
->collector_count
;
980 world
->collector_count
++;
983 vg_fatal_exit_loop( "Invalid state" );
986 /* create route from node description */
987 VG_STATIC
void world_routes_create_route( world_instance
*world
,
990 mdl_context
*mdl
= world
->meta
;
992 struct classtype_route
*inf
= mdl_get_entdata( mdl
, pnode
);
993 struct route
*route
= &world
->routes
[ world
->route_count
];
994 memset( route
, 0, sizeof(struct route
) );
996 v3_copy( inf
->colour
, route
->colour
);
997 route
->colour
[3] = 1.0f
;
998 route
->track_id
= 0xffffffff;
1000 for( u32 j
=0; j
<vg_list_size(track_infos
); j
++ )
1002 if( !strcmp( mdl_pstr(mdl
,pnode
->pstr_name
), track_infos
[j
].name
))
1004 route
->track_id
= j
;
1009 route
->start
= world_routes_get_subuid( world
, inf
->id_start
);
1011 route
->factive
= 0.0f
;
1012 mdl_node_transform( pnode
, route
->scoreboard_transform
);
1014 struct route_ui_bar
*pui
= &world_global
.ui_bars
[ world
->route_count
];
1015 pui
->indices_head
= k_route_ui_max_indices
- 9;
1016 pui
->vertex_head
= k_route_ui_max_verts
- 200;
1017 pui
->segment_start
= 0;
1018 pui
->segment_count
= 0;
1019 pui
->fade_start
= 0;
1020 pui
->fade_count
= 0;
1021 pui
->fade_timer_start
= 0.0;
1023 world
->route_count
++;
1026 /* load all routes from model header */
1027 VG_STATIC
void world_routes_process( world_instance
*world
)
1029 vg_info( "Initializing routes\n" );
1030 mdl_context
*mdl
= world
->meta
;
1032 for( int i
=0; i
<mdl
->info
.node_count
; i
++ )
1034 mdl_node
*pnode
= mdl_node_from_id(mdl
,i
);
1036 if( pnode
->classtype
== k_classtype_route_node
||
1037 pnode
->classtype
== k_classtype_gate
)
1039 struct route_node
*rn
= world_routes_create_node( world
, pnode
);
1041 if( pnode
->classtype
== k_classtype_gate
)
1043 world_routes_process_gate( world
, rn
, pnode
);
1047 struct classtype_route_node
*inf
= mdl_get_entdata( mdl
, pnode
);
1048 rn
->next
[0] = world_routes_get_subuid( world
, inf
->target
);
1049 rn
->next
[1] = world_routes_get_subuid( world
, inf
->target1
);
1052 else if( pnode
->classtype
== k_classtype_route
)
1054 world_routes_create_route( world
, pnode
);
1061 for( int i
=0; i
<world
->route_count
; i
++ )
1063 struct route
*route
= &world
->routes
[i
];
1066 u32 si
= world_routes_get_path( world
, route
->start
, stack
);
1068 for( int sj
=0; sj
<si
; sj
++ )
1070 struct route_node
*rn
= &world
->nodes
[ stack
[sj
] ];
1071 rn
->route_ids
[ rn
->ref_count
++ ] = i
;
1073 if( rn
->ref_count
> 4 )
1074 vg_warn( "Too many references on route node %i\n", i
);
1080 * -----------------------------------------------------------------------------
1082 * -----------------------------------------------------------------------------
1085 VG_STATIC
void world_routes_init(void)
1087 world_global
.current_run_version
= 2;
1088 world_global
.time
= RESET_MAX_TIME
*2.0;
1089 world_global
.last_use
= 0.0;
1091 shader_scene_route_register();
1092 shader_routeui_register();
1094 vg_acquire_thread_sync();
1097 for( int i
=0; i
<vg_list_size(world_global
.ui_bars
); i
++ )
1100 struct route_ui_bar
*pui
= &world_global
.ui_bars
[i
];
1102 glGenVertexArrays( 1, &pui
->vao
);
1103 glGenBuffers( 1, &pui
->vbo
);
1104 glGenBuffers( 1, &pui
->ebo
);
1105 glBindVertexArray( pui
->vao
);
1107 size_t stride
= sizeof(v2f
);
1109 glBindBuffer( GL_ARRAY_BUFFER
, pui
->vbo
);
1110 glBufferData( GL_ARRAY_BUFFER
, k_route_ui_max_verts
*stride
,
1111 NULL
, GL_DYNAMIC_DRAW
);
1113 glBindVertexArray( pui
->vao
);
1114 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER
, pui
->ebo
);
1115 glBufferData( GL_ELEMENT_ARRAY_BUFFER
,
1116 k_route_ui_max_indices
*sizeof(u16
), NULL
,
1119 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
, stride
, (void *)0 );
1120 glEnableVertexAttribArray( 0 );
1124 vg_release_thread_sync();
1127 VG_STATIC
void world_routes_update( world_instance
*world
)
1129 world_global
.time
+= vg
.time_delta
;
1131 for( int i
=0; i
<world
->route_count
; i
++ )
1133 struct route
*route
= &world
->routes
[i
];
1134 route
->factive
= vg_lerpf( route
->factive
, route
->active
,
1135 0.6f
*vg
.time_delta
);
1139 world_routes_ui_updatetime(i
, world_global
.time
- route
->latest_pass
);
1144 VG_STATIC
void bind_terrain_noise(void);
1145 VG_STATIC
void world_bind_light_array( world_instance
*world
,
1146 GLuint shader
, GLuint location
,
1149 VG_STATIC
void render_world_routes( world_instance
*world
, camera
*cam
)
1151 m4x3f identity_matrix
;
1152 m4x3_identity( identity_matrix
);
1154 shader_scene_route_use();
1155 shader_scene_route_uTexGarbage(0);
1156 world_link_lighting_ub( world
, _shader_scene_route
.id
);
1157 world_bind_position_texture( world
, _shader_scene_route
.id
,
1158 _uniform_scene_route_g_world_depth
, 2 );
1159 world_bind_light_array( world
, _shader_scene_route
.id
,
1160 _uniform_scene_route_uLightsArray
, 3 );
1161 bind_terrain_noise();
1163 shader_scene_route_uPv( cam
->mtx
.pv
);
1164 shader_scene_route_uPvmPrev( cam
->mtx_prev
.pv
);
1165 shader_scene_route_uMdl( identity_matrix
);
1166 shader_scene_route_uCamera( cam
->transform
[3] );
1167 shader_scene_route_uBoard0( TEMP_BOARD_0
);
1168 shader_scene_route_uBoard1( TEMP_BOARD_1
);
1170 mesh_bind( &world
->mesh_route_lines
);
1172 for( int i
=0; i
<world
->route_count
; i
++ )
1174 struct route
*route
= &world
->routes
[i
];
1177 v3_lerp( (v3f
){0.7f
,0.7f
,0.7f
}, route
->colour
, route
->factive
, colour
);
1180 shader_scene_route_uColour( colour
);
1181 mdl_draw_submesh( &route
->sm
);
1185 VG_STATIC
void render_world_routes_ui( world_instance
*world
)
1188 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1189 glBlendEquation(GL_FUNC_ADD
);
1191 float active_offset
= 0.0f
;
1192 for( int i
=0; i
<world
->route_count
; i
++ )
1194 struct route
*route
= &world
->routes
[i
];
1195 world_routes_ui_draw( world
, i
, route
->colour
, active_offset
);
1196 active_offset
+= route
->factive
;
1199 glDisable(GL_BLEND
);
1202 #endif /* ROUTES_H */