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