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