random
[carveJwlIkooP6JGAAIwe30JlM.git] / world.h
1 /*
2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #include "common.h"
6
7 VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit );
8
9 #ifndef WORLD_H
10 #define WORLD_H
11
12 #include "vg/vg_loader.h"
13
14 #include "network.h"
15 #include "network_msg.h"
16 #include "scene.h"
17 #include "render.h"
18 #include "rigidbody.h"
19 #include "bvh.h"
20 #include "model.h"
21
22 #include "shaders/terrain.h"
23 #include "shaders/sky.h"
24 #include "shaders/standard.h"
25 #include "shaders/vblend.h"
26 #include "shaders/gpos.h"
27 #include "shaders/blitcolour.h"
28 #include "shaders/alphatest.h"
29
30 typedef struct teleport_gate teleport_gate;
31
32 enum { k_max_ui_segments = 8 };
33
34 enum { k_max_ui_elements = k_max_ui_segments };
35 enum { k_max_element_verts = 10 };
36 enum { k_max_element_indices = 20 };
37
38 enum { k_route_ui_max_verts = k_max_ui_elements*k_max_element_verts };
39 enum { k_route_ui_max_indices = k_max_ui_elements*k_max_element_indices };
40
41 enum logic_type
42 {
43 k_logic_type_relay = 1,
44 k_logic_type_chance = 2,
45 k_logic_type_achievement = 3
46 };
47
48 enum geo_type
49 {
50 k_geo_type_solid = 0,
51 k_geo_type_nonsolid = 1,
52 k_geo_type_water = 2
53 };
54
55 VG_STATIC struct gworld
56 {
57 /*
58 * Allocated as system memory
59 * --------------------------------------------------------------------------
60 */
61
62 /* rendering */
63 glmesh skydome;
64 mdl_submesh dome_upper, dome_lower;
65
66 glmesh mesh_gate_surface;
67
68 double sky_time, sky_rate, sky_target_rate;
69
70 /* water rendering */
71 struct
72 {
73 struct framebuffer fbreflect, fbdepth;
74
75 boxf depthbounds;
76 int depth_computed;
77
78 float height;
79 int enabled;
80 v4f plane;
81 }
82 water;
83
84 /* split flap display */
85 struct
86 {
87 mdl_submesh *sm_module, *sm_card;
88 glmesh mesh_base, mesh_display;
89
90 u32 w, h;
91 float *buffer;
92 }
93 sfd;
94
95 /* timing bars, fixed maximum amount */
96 struct route_ui_bar
97 {
98 GLuint vao, vbo, ebo;
99
100 u32 indices_head;
101 u32 vertex_head;
102
103 struct route_ui_segment
104 {
105 float length;
106 u32 vertex_start, vertex_count,
107 index_start, index_count, notches;
108 }
109 segments[k_max_ui_segments];
110
111 u32 segment_start, segment_count, fade_start, fade_count;
112 double fade_timer_start;
113 float xpos;
114 }
115 ui_bars[16];
116
117 v3f render_gate_pos;
118 int active_route_board;
119 int in_trigger;
120
121 /* This is a small flag we use to changelevel.
122 * It will not be cleared until all sounds stop playing
123 */
124 int switching_to_new_world;
125 char world_name[ 64 ];
126
127 /*
128 * Dynamically allocated when world_load is called.
129 *
130 * the following arrays index somewhere into this linear
131 * allocator
132 *
133 * (world_gen.h)
134 * --------------------------------------------------------------------------
135 */
136 void *dynamic_vgl,
137 *audio_vgl; /* sub buffer of the audio buffer */
138
139 /*
140 * Main world .mdl
141 */
142 mdl_context *meta;
143
144 /*
145 * Materials / textures
146 */
147
148 GLuint *textures;
149 u32 texture_count;
150
151 struct world_material
152 {
153 mdl_material info;
154 mdl_submesh sm_geo,
155 sm_no_collide;
156 }
157 * materials;
158 u32 material_count;
159
160 /*
161 * Named safe places to respawn
162 */
163 struct respawn_point
164 {
165 v3f co;
166 v4f q;
167 const char *name;
168 }
169 * spawns;
170 u32 spawn_count;
171
172 /*
173 * Audio player entities
174 */
175 struct world_audio_thing
176 {
177 v3f pos;
178 float volume;
179 u32 flags;
180
181 audio_player player;
182 audio_clip temp_embedded_clip;
183 }
184 * audio_things;
185 u32 audio_things_count;
186
187 /*
188 * Relays
189 */
190 struct logic_relay
191 {
192 v3f pos;
193
194 struct relay_target
195 {
196 u32 sub_id;
197 enum classtype classtype;
198 }
199 targets[4];
200 u32 target_count;
201 }
202 * logic_relays;
203 u32 relay_count;
204
205 /*
206 * Box trigger entities
207 */
208 struct trigger_zone
209 {
210 m4x3f transform, inv_transform;
211
212 struct relay_target target;
213 }
214 * triggers;
215 u32 trigger_count;
216
217 /*
218 * Achievements
219 */
220 struct logic_achievement
221 {
222 v3f pos;
223 const char *achievement_id;
224 u32 achieved;
225 }
226 * logic_achievements;
227 u32 achievement_count;
228
229
230 /*
231 * Routes (world_routes.h)
232 * --------------------------------------------------------------------------
233 */
234 struct route_node
235 {
236 v3f co, right, up, h;
237 u32 next[2];
238
239 u32 special_type, special_id, current_refs, ref_count;
240 u32 route_ids[4]; /* Gates can be linked into up to four routes */
241 }
242 *nodes;
243 u32 node_count;
244
245 struct route
246 {
247 u32 track_id;
248 v4f colour;
249
250 u32 start;
251 mdl_submesh sm;
252
253 int active;
254 float factive;
255
256 double best_lap, latest_pass; /* Session */
257
258 m4x3f scoreboard_transform;
259 }
260 *routes;
261 u32 route_count;
262
263 struct route_gate
264 {
265 struct teleport_gate
266 {
267 v3f co[2];
268 v4f q[2];
269 v2f dims;
270
271 m4x3f to_world, recv_to_world, transport;
272 }
273 gate;
274
275 u32 node_id;
276
277 struct route_timing
278 {
279 u32 version; /* Incremented on every teleport */
280 double time;
281 }
282 timing;
283 }
284 *gates;
285 u32 gate_count;
286
287 struct route_collector
288 {
289 struct route_timing timing;
290 }
291 *collectors;
292 u32 collector_count;
293
294
295 /* logic
296 * ----------------------------------------------------
297 */
298
299 u32 active_gate,
300 current_run_version;
301 double time, rewind_from, rewind_to, last_use;
302
303 /* world geometry */
304 scene *scene_geo,
305 *scene_no_collide,
306 *scene_lines;
307
308 /* spacial mappings */
309 bh_tree *audio_bh,
310 *trigger_bh,
311 *geo_bh;
312
313 /* graphics */
314 glmesh mesh_route_lines;
315
316 glmesh mesh_geo,
317 mesh_no_collide,
318 mesh_water;
319
320 mdl_submesh sm_foliage_main;
321 rigidbody rb_geo; /* todo.. ... */
322 }
323 world;
324
325
326 /*
327 * API
328 */
329
330 VG_STATIC int ray_hit_is_ramp( ray_hit *hit );
331 VG_STATIC struct world_material *ray_hit_material( ray_hit *hit );
332 VG_STATIC void ray_world_get_tri( ray_hit *hit, v3f tri[3] );
333 VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit );
334
335 /*
336 * Submodules
337 */
338
339 #include "world_routes.h"
340 #include "world_sfd.h"
341 #include "world_render.h"
342 #include "world_water.h"
343 #include "world_gen.h"
344 #include "world_gate.h"
345
346 /*
347 * -----------------------------------------------------------------------------
348 * Events
349 * -----------------------------------------------------------------------------
350 */
351
352 VG_STATIC int world_stop_sound( int argc, const char *argv[] )
353 {
354 /*
355 * None of our world audio runs as one shots, they always have a player.
356 * Therefore it is safe to delete clip data after the players are
357 * disconnected
358 */
359 audio_lock();
360 for( int i=0; i<world.audio_things_count; i++ )
361 {
362 struct world_audio_thing *at = &world.audio_things[i];
363
364 if( audio_player_is_playing( &at->player ) )
365 {
366 u32 cflags = audio_player_get_flags( &at->player );
367 audio_player_set_flags( &at->player, cflags | AUDIO_FLAG_KILL );
368 }
369 }
370 audio_unlock();
371
372 return 0;
373 }
374
375 VG_STATIC int world_change_world( int argc, const char *argv[] )
376 {
377 if( argc == 0 )
378 {
379 vg_info( "%s\n", world.world_name );
380 return 0;
381 }
382 else
383 {
384 vg_info( "Switching world...\n" );
385 strcpy( world.world_name, argv[0] );
386 world.switching_to_new_world = 1;
387 world_stop_sound( 0, NULL );
388 }
389
390 return 0;
391 }
392
393 VG_STATIC void world_init(void)
394 {
395 vg_var_push( (struct vg_var){
396 .name = "water_enable",
397 .data = &world.water.enabled,
398 .data_type = k_var_dtype_i32,
399 .opt_i32 = { .min=0, .max=1, .clamp=1 },
400 .persistent = 0
401 });
402
403 vg_function_push( (struct vg_cmd)
404 {
405 .name = "world_stop_sound",
406 .function = world_stop_sound
407 });
408
409 vg_function_push( (struct vg_cmd)
410 {
411 .name = "world",
412 .function = world_change_world
413 });
414
415 world.sky_rate = 1.0;
416 world.sky_target_rate = 1.0;
417
418 shader_terrain_register();
419 shader_sky_register();
420 shader_gpos_register();
421 shader_blitcolour_register();
422 shader_alphatest_register();
423
424 vg_info( "Loading world resources\n" );
425
426 vg_linear_clear( vg_mem.scratch );
427 mdl_context *msky = mdl_load_full( vg_mem.scratch, "models/rs_skydome.mdl" );
428
429 mdl_node *nupper = mdl_node_from_name( msky, "dome_complete" );
430 world.dome_upper = *mdl_node_submesh( msky, nupper, 0 );
431
432 vg_acquire_thread_sync();
433 {
434 mdl_unpack_glmesh( msky, &world.skydome );
435 }
436 vg_release_thread_sync();
437
438 /* Other systems */
439 vg_info( "Loading other world systems\n" );
440
441 vg_loader_step( world_render_init, NULL );
442 vg_loader_step( world_sfd_init, NULL );
443 vg_loader_step( world_water_init, NULL );
444 vg_loader_step( world_gates_init, NULL );
445 vg_loader_step( world_routes_init, NULL );
446
447 /* Allocate dynamic world memory arena */
448 u32 max_size = 76*1024*1024;
449 world.dynamic_vgl = vg_create_linear_allocator( vg_mem.rtmemory, max_size,
450 VG_MEMORY_SYSTEM );
451 }
452
453 VG_STATIC void world_audio_init(void)
454 {
455 u32 size = vg_linear_remaining( vg_audio.audio_pool )
456 - sizeof(vg_linear_allocator);
457
458 world.audio_vgl = vg_create_linear_allocator( vg_audio.audio_pool,
459 size, VG_MEMORY_SYSTEM );
460 }
461
462 VG_STATIC void world_trigger_achievement( u32 uid )
463 {
464 struct logic_achievement *ach = &world.logic_achievements[ uid ];
465
466 if( ach->achieved )
467 return;
468
469 steam_set_achievement( ach->achievement_id );
470 steam_store_achievements();
471
472 ach->achieved = 1;
473 }
474
475 VG_STATIC void world_run_relay( struct relay_target *rt );
476 VG_STATIC void world_trigger_relay( u32 uid )
477 {
478 struct logic_relay *relay = &world.logic_relays[ uid ];
479
480 for( int i=0; i<relay->target_count; i++ )
481 {
482 world_run_relay( &relay->targets[i] );
483 }
484 }
485
486 VG_STATIC void world_trigger_audio( u32 uid )
487 {
488 struct world_audio_thing *wat = &world.audio_things[ uid ];
489
490 audio_lock();
491 audio_player_playclip( &wat->player,
492 &wat->temp_embedded_clip );
493 audio_unlock();
494 }
495
496 VG_STATIC void world_run_relay( struct relay_target *rt )
497 {
498 struct entity_instruction
499 {
500 enum classtype classtype;
501 void (*p_trigger)( u32 uid );
502 }
503 entity_instructions[] =
504 {
505 { k_classtype_logic_achievement, world_trigger_achievement },
506 { k_classtype_logic_relay, world_trigger_relay },
507 { k_classtype_audio, world_trigger_audio }
508 };
509
510 for( int i=0; i<vg_list_size(entity_instructions); i++ )
511 {
512 struct entity_instruction *instr = &entity_instructions[i];
513
514 if( instr->classtype == rt->classtype )
515 {
516 instr->p_trigger( rt->sub_id );
517 return;
518 }
519 }
520
521 vg_error( "Don't know how to trigger classtype %d\n", rt->classtype );
522 }
523
524 VG_STATIC void world_update( v3f pos )
525 {
526 if( world.switching_to_new_world )
527 {
528 int all_stopped = 1;
529
530 audio_lock();
531 for( int i=0; i<world.audio_things_count; i++ )
532 {
533 struct world_audio_thing *at = &world.audio_things[i];
534
535 if( audio_player_is_playing( &at->player ) )
536 {
537 all_stopped = 0;
538 break;
539 }
540 }
541 audio_unlock();
542
543 if( all_stopped )
544 {
545 world.switching_to_new_world = 0;
546 world_unload();
547 vg_loader_start( world_load );
548 return;
549 }
550 }
551
552 world.sky_time += world.sky_rate * vg.time_delta;
553 world.sky_rate = vg_lerp( world.sky_rate, world.sky_target_rate,
554 vg.time_delta * 5.0 );
555
556 world_routes_update();
557 #if 0
558 world_routes_debug();
559 #endif
560
561 if( world.route_count > 0 )
562 {
563 int closest = 0;
564 float min_dist = INFINITY;
565
566 for( int i=0; i<world.route_count; i++ )
567 {
568 float d = v3_dist2( world.routes[i].scoreboard_transform[3], pos );
569
570 if( d < min_dist )
571 {
572 min_dist = d;
573 closest = i;
574 }
575 }
576
577 if( (world.active_route_board != closest) || network_scores_updated )
578 {
579 network_scores_updated = 0;
580 world.active_route_board = closest;
581
582 struct route *route = &world.routes[closest];
583
584 u32 id = route->track_id;
585
586 if( id != 0xffffffff )
587 {
588 struct netmsg_board *local_board =
589 &scoreboard_client_data.boards[id];
590
591 for( int i=0; i<13; i++ )
592 {
593 sfd_encode( i, &local_board->data[27*i] );
594 }
595 }
596 }
597 }
598
599 int in_trigger = 0;
600 for( int i=0; i<world.trigger_count; i++ )
601 {
602 struct trigger_zone *zone = &world.triggers[i];
603
604 v3f local;
605 m4x3_mulv( zone->inv_transform, pos, local );
606
607 if( (fabsf(local[0]) <= 1.0f) &&
608 (fabsf(local[1]) <= 1.0f) &&
609 (fabsf(local[2]) <= 1.0f) )
610 {
611 in_trigger = 1;
612
613 if( !world.in_trigger )
614 {
615 world_run_relay( &zone->target );
616 }
617 }
618
619 vg_line_boxf_transformed( zone->transform, (boxf){{-1.0f,-1.0f,-1.0f},
620 { 1.0f, 1.0f, 1.0f}},
621 0xff00ff00 );
622 }
623
624 world.in_trigger = in_trigger;
625 sfd_update();
626 }
627
628 /*
629 * -----------------------------------------------------------------------------
630 * API implementation
631 * -----------------------------------------------------------------------------
632 */
633
634 VG_STATIC void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
635 {
636 for( int i=0; i<3; i++ )
637 v3_copy( world.scene_geo->arrvertices[ hit->tri[i] ].co, tri[i] );
638 }
639
640 VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit )
641 {
642 return scene_raycast( world.scene_geo, world.geo_bh, pos, dir, hit );
643 }
644
645 /*
646 * Cast a sphere from a to b and see what time it hits
647 */
648 VG_STATIC int spherecast_world( v3f pa, v3f pb, float r, float *t, v3f n )
649 {
650 bh_iter it;
651 bh_iter_init( 0, &it );
652
653 boxf region;
654 box_init_inf( region );
655 box_addpt( region, pa );
656 box_addpt( region, pb );
657
658 v3_add( (v3f){ r, r, r}, region[1], region[1] );
659 v3_add( (v3f){-r,-r,-r}, region[0], region[0] );
660
661 v3f dir;
662 v3_sub( pb, pa, dir );
663
664 v3f dir_inv;
665 dir_inv[0] = 1.0f/dir[0];
666 dir_inv[1] = 1.0f/dir[1];
667 dir_inv[2] = 1.0f/dir[2];
668
669 int hit = -1;
670 float min_t = 1.0f;
671
672 int idx;
673 while( bh_next( world.geo_bh, &it, region, &idx ) )
674 {
675 u32 *ptri = &world.scene_geo->arrindices[ idx*3 ];
676 v3f tri[3];
677
678 boxf box;
679 box_init_inf( box );
680
681 for( int j=0; j<3; j++ )
682 {
683 v3_copy( world.scene_geo->arrvertices[ptri[j]].co, tri[j] );
684 box_addpt( box, tri[j] );
685 }
686
687 v3_add( (v3f){ r, r, r}, box[1], box[1] );
688 v3_add( (v3f){-r,-r,-r}, box[0], box[0] );
689
690 if( !ray_aabb1( box, pa, dir_inv, 1.0f ) )
691 continue;
692
693 float t;
694 v3f n1;
695 if( spherecast_triangle( tri, pa, dir, r, &t, n1 ) )
696 {
697 if( t < min_t )
698 {
699 min_t = t;
700 hit = idx;
701 v3_copy( n1, n );
702 }
703 }
704 }
705
706 *t = min_t;
707 return hit;
708 }
709
710 VG_STATIC struct world_material *world_tri_index_material( u32 index )
711 {
712 for( int i=1; i<world.material_count; i++ )
713 {
714 struct world_material *mat = &world.materials[i];
715
716 if( (index >= mat->sm_geo.vertex_start) &&
717 (index < mat->sm_geo.vertex_start+mat->sm_geo.vertex_count ) )
718 {
719 return mat;
720 }
721 }
722
723 /* error material */
724 return &world.materials[0];
725 }
726
727 VG_STATIC struct world_material *world_contact_material( rb_ct *ct )
728 {
729 return world_tri_index_material( ct->element_id );
730 }
731
732 VG_STATIC struct world_material *ray_hit_material( ray_hit *hit )
733 {
734 return world_tri_index_material( hit->tri[0] );
735 }
736
737 #endif /* WORLD_H */