a change to rigidbody semantics
[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 #include "entity.h"
22 #include "font.h"
23
24 #include "shaders/scene_standard.h"
25 #include "shaders/scene_standard_alphatest.h"
26 #include "shaders/scene_vertex_blend.h"
27 #include "shaders/scene_terrain.h"
28 #include "shaders/scene_depth.h"
29 #include "shaders/scene_position.h"
30
31 #include "shaders/model_sky.h"
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 static const float k_light_cube_size = 8.0f;
57
58 struct world_instance {
59 /* Fixed items
60 * -------------------------------------------------------
61 */
62
63 char world_name[ 64 ];
64
65 struct{
66 boxf depthbounds;
67 int depth_computed;
68
69 float height;
70 int enabled;
71 v4f plane;
72 }
73 water;
74
75 /* STD140 */
76 struct ub_world_lighting{
77 v4f g_cube_min,
78 g_cube_inv_range;
79
80 v4f g_water_plane,
81 g_depth_bounds;
82
83 v4f g_daysky_colour;
84 v4f g_nightsky_colour;
85 v4f g_sunset_colour;
86 v4f g_ambient_colour;
87 v4f g_sunset_ambient;
88 v4f g_sun_colour;
89 v4f g_sun_dir;
90
91 float g_water_fog;
92 float g_time;
93 float g_realtime;
94 float g_shadow_length;
95 float g_shadow_spread;
96
97 float g_time_of_day;
98 float g_day_phase;
99 float g_sunset_phase;
100
101 int g_light_preview;
102 int g_shadow_samples;
103
104 int g_debug_indices;
105 int g_debug_complexity;
106 }
107 ub_lighting;
108 GLuint ubo_lighting;
109 int ubo_bind_point;
110
111 GLuint tbo_light_entities,
112 tex_light_entities,
113 tex_light_cubes;
114
115 float probabilities[3];
116
117 v3i light_cubes;
118
119 struct framebuffer heightmap;
120
121 /*
122 * Dynamically allocated when world_load is called.
123 *
124 * the following arrays index somewhere into this linear
125 * allocator
126 *
127 * (world_gen.h)
128 * --------------------------------------------------------------------------
129 */
130
131 /*
132 * Main world .mdl
133 */
134 mdl_context meta;
135
136 GLuint *textures;
137 u32 texture_count;
138
139 struct world_surface{
140 mdl_material info;
141 mdl_submesh sm_geo,
142 sm_no_collide;
143 }
144 * surfaces;
145 u32 surface_count;
146
147 mdl_array_ptr ent_spawn,
148 ent_gate,
149 ent_light,
150 ent_route_node,
151 ent_path_index,
152 ent_checkpoint,
153 ent_route,
154 ent_water,
155
156 ent_audio_clip,
157 ent_audio,
158 ent_volume;
159
160 ent_gate *rendering_gate;
161
162 /* logic
163 * ----------------------------------------------------
164 */
165
166 /* world geometry */
167 scene *scene_geo,
168 *scene_no_collide,
169 *scene_lines;
170
171 /* spacial mappings */
172 bh_tree *audio_bh,
173 *volume_bh,
174 *geo_bh;
175
176 /* graphics */
177 glmesh mesh_route_lines;
178 glmesh mesh_geo,
179 mesh_no_collide,
180 mesh_water;
181
182 rb_object rb_geo;
183 };
184
185 VG_STATIC struct world_global{
186 /*
187 * Allocated as system memory
188 * --------------------------------------------------------------------------
189 */
190 void *generic_heap;
191
192 /* rendering */
193 glmesh skydome;
194 glmesh mesh_gate;
195 mdl_submesh sm_gate_surface,
196 sm_gate_marker[4];
197
198 double sky_time, sky_rate, sky_target_rate;
199
200 u32 current_run_version;
201 double time, rewind_from, rewind_to, last_use;
202
203 /* water rendering */
204 struct{
205 struct framebuffer fbreflect, fbdepth;
206 }
207 water;
208
209 /* split flap display */
210 struct{
211 glmesh mesh_base, mesh_display;
212 mdl_submesh sm_base;
213 u32 active_route_board;
214
215 u32 w, h;
216 float *buffer;
217 }
218 sfd;
219
220 v3f render_gate_pos;
221 int in_volume;
222
223 int switching_to_new_world;
224
225 world_instance worlds[4];
226 u32 world_count;
227 u32 active_world;
228
229 /* text particles */
230 font3d font;
231
232 struct timer_text{
233 char text[8];
234 m4x3f transform;
235 ent_gate *gate;
236 ent_route *route;
237 }
238 timer_texts[4];
239 u32 timer_text_count;
240
241 struct text_particle{
242 rigidbody *rb;
243 ent_glyph *glyph;
244 }
245 text_particles[6*4];
246 u32 text_particle_count;
247
248 }
249 world_global;
250
251 VG_STATIC world_instance *get_active_world( void )
252 {
253 return &world_global.worlds[ world_global.active_world ];
254 }
255
256 /*
257 * API
258 */
259
260 VG_STATIC
261 int ray_hit_is_ramp( world_instance *world, ray_hit *hit );
262
263 VG_STATIC
264 struct world_surface *ray_hit_surface( world_instance *world, ray_hit *hit );
265
266 VG_STATIC
267 void ray_world_get_tri( world_instance *world, ray_hit *hit, v3f tri[3] );
268
269 VG_STATIC
270 int ray_world( world_instance *world, v3f pos, v3f dir, ray_hit *hit );
271
272 /*
273 * Submodules
274 */
275
276 #include "world_routes.h"
277 #include "world_sfd.h"
278 #include "world_render.h"
279 #include "world_water.h"
280 #include "world_volumes.h"
281 #include "world_gen.h"
282 #include "world_gate.h"
283
284 /*
285 * -----------------------------------------------------------------------------
286 * Events
287 * -----------------------------------------------------------------------------
288 */
289
290 VG_STATIC int world_stop_sound( int argc, const char *argv[] )
291 {
292 world_instance *world = get_active_world();
293 return 0;
294 }
295
296 VG_STATIC void world_init(void)
297 {
298 world_global.sky_rate = 1.0;
299 world_global.sky_target_rate = 1.0;
300
301 shader_scene_standard_register();
302 shader_scene_standard_alphatest_register();
303 shader_scene_vertex_blend_register();
304 shader_scene_terrain_register();
305 shader_scene_depth_register();
306 shader_scene_position_register();
307
308 shader_model_sky_register();
309
310 vg_info( "Loading world resources\n" );
311
312 vg_linear_clear( vg_mem.scratch );
313
314 mdl_context msky;
315 mdl_open( &msky, "models/rs_skydome.mdl", vg_mem.scratch );
316 mdl_load_metadata_block( &msky, vg_mem.scratch );
317 mdl_load_mesh_block( &msky, vg_mem.scratch );
318 mdl_close( &msky );
319
320 vg_acquire_thread_sync();
321 {
322 mdl_unpack_glmesh( &msky, &world_global.skydome );
323 }
324 vg_release_thread_sync();
325
326 /* Other systems */
327 vg_info( "Loading other world systems\n" );
328
329 vg_loader_step( world_render_init, NULL );
330 vg_loader_step( world_sfd_init, NULL );
331 vg_loader_step( world_water_init, NULL );
332 vg_loader_step( world_gates_init, NULL );
333 vg_loader_step( world_routes_init, NULL );
334
335 /* Allocate dynamic world memory arena */
336 u32 max_size = 76*1024*1024;
337 world_global.generic_heap = vg_create_linear_allocator( vg_mem.rtmemory,
338 max_size,
339 VG_MEMORY_SYSTEM );
340 }
341
342 typedef struct ent_call ent_call;
343 struct ent_call{
344 ent_index ent;
345 u32 function;
346 void *data;
347 };
348
349 VG_STATIC void entity_call( world_instance *world, ent_call *call );
350
351 VG_STATIC void ent_volume_call( world_instance *world, ent_call *call )
352 {
353 ent_volume *volume = mdl_arritm( &world->ent_volume, call->ent.index );
354 if( !volume->target.type ) return;
355
356 if( call->function == k_ent_function_trigger ){
357 call->ent = volume->target;
358
359 if( volume->type == k_volume_subtype_particle ){
360 float *co = alloca( sizeof(float)*3 );
361 co[0] = vg_randf()*2.0f-1.0f;
362 co[1] = vg_randf()*2.0f-1.0f;
363 co[2] = vg_randf()*2.0f-1.0f;
364 m4x3_mulv( volume->to_world, co, co );
365
366 call->function = k_ent_function_particle_spawn;
367 call->data = co;
368 entity_call( world, call );
369 }
370 else
371 entity_call( world, call );
372 }
373 }
374
375 VG_STATIC void ent_audio_call( world_instance *world, ent_call *call )
376 {
377 ent_audio *audio = mdl_arritm( &world->ent_audio, call->ent.index );
378
379 v3f sound_co;
380
381 if( call->function == k_ent_function_particle_spawn ){
382 v3_copy( call->data, sound_co );
383 }
384 else if( call->function == k_ent_function_trigger ){
385 v3_copy( audio->transform.co, sound_co );
386 }
387 else
388 vg_fatal_exit_loop( "ent_audio_call (invalid function id)" );
389
390 float chance = vg_randf()*100.0f,
391 bar = 0.0f;
392
393 for( u32 i=0; i<audio->clip_count; i++ ){
394 ent_audio_clip *clip = mdl_arritm( &world->ent_audio_clip,
395 audio->clip_start+i );
396
397 float mod = world->probabilities[ audio->probability_curve ],
398 p = clip->probability * mod;
399
400 bar += p;
401
402 if( chance < bar ){
403
404 audio_lock();
405
406 if( audio->behaviour == k_channel_behaviour_unlimited ){
407 audio_oneshot_3d( &clip->clip, sound_co,
408 audio->transform.s[0],
409 audio->volume );
410 }
411 else if( audio->behaviour == k_channel_behaviour_discard_if_full ){
412 audio_channel *ch =
413 audio_get_group_idle_channel( audio->group,
414 audio->max_channels );
415
416 if( ch ){
417 audio_channel_init( ch, &clip->clip, audio->flags );
418 audio_channel_group( ch, audio->group );
419 audio_channel_set_spacial( ch, sound_co, audio->transform.s[0] );
420 audio_channel_edit_volume( ch, audio->volume, 1 );
421 ch = audio_relinquish_channel( ch );
422 }
423 }
424 else if( audio->behaviour == k_channel_behaviour_crossfade_if_full){
425 audio_channel *ch =
426 audio_get_group_idle_channel( audio->group,
427 audio->max_channels );
428
429 /* group is full */
430 if( !ch ){
431 audio_channel *existing =
432 audio_get_group_first_active_channel( audio->group );
433
434 if( existing ){
435 if( existing->source == &clip->clip ){
436 audio_unlock();
437 return;
438 }
439
440 existing->group = 0;
441 existing = audio_channel_fadeout(existing, audio->crossfade);
442 }
443
444 ch = audio_get_first_idle_channel();
445 }
446
447 if( ch ){
448 audio_channel_init( ch, &clip->clip, audio->flags );
449 audio_channel_group( ch, audio->group );
450 audio_channel_fadein( ch, audio->crossfade );
451 ch = audio_relinquish_channel( ch );
452 }
453 }
454
455 audio_unlock();
456 return;
457 }
458 }
459 }
460
461 VG_STATIC void entity_call( world_instance *world, ent_call *call )
462 {
463 if( call->ent.type == k_ent_volume ){
464 ent_volume_call( world, call );
465 } else if( call->ent.type == k_ent_audio ){
466 ent_audio_call( world, call );
467 }
468 }
469
470 VG_STATIC void world_update( world_instance *world, v3f pos )
471 {
472 /* TEMP!!!!!! */
473 static double g_time = 0.0;
474 g_time += vg.time_delta * (1.0/(k_day_length*60.0));
475
476
477 struct ub_world_lighting *state = &world->ub_lighting;
478
479 state->g_time = g_time;
480 state->g_realtime = vg.time;
481 state->g_debug_indices = k_debug_light_indices;
482 state->g_light_preview = k_light_preview;
483 state->g_debug_complexity = k_debug_light_complexity;
484
485 state->g_time_of_day = vg_fractf( g_time );
486 state->g_day_phase = cosf( state->g_time_of_day * VG_PIf * 2.0f );
487 state->g_sunset_phase= cosf( state->g_time_of_day * VG_PIf * 4.0f + VG_PIf );
488
489 state->g_day_phase = state->g_day_phase * 0.5f + 0.5f;
490 state->g_sunset_phase = powf( state->g_sunset_phase * 0.5f + 0.5f, 6.0f );
491
492 float a = state->g_time_of_day * VG_PIf * 2.0f;
493 state->g_sun_dir[0] = sinf( a );
494 state->g_sun_dir[1] = cosf( a );
495 state->g_sun_dir[2] = 0.2f;
496 v3_normalize( state->g_sun_dir );
497
498
499 world->probabilities[ k_probability_curve_constant ] = 1.0f;
500
501 float dp = state->g_day_phase;
502
503 world->probabilities[ k_probability_curve_wildlife_day ] =
504 (dp*dp*0.8f+state->g_sunset_phase)*0.8f;
505 world->probabilities[ k_probability_curve_wildlife_night ] =
506 1.0f-powf(fabsf((state->g_time_of_day-0.5f)*5.0f),5.0f);
507
508
509 glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting );
510 glBufferSubData( GL_UNIFORM_BUFFER, 0,
511 sizeof(struct ub_world_lighting), &world->ub_lighting );
512 /* TEMP!!!!!! */
513
514 world_global.sky_time += world_global.sky_rate * vg.time_delta;
515 world_global.sky_rate = vg_lerp( world_global.sky_rate,
516 world_global.sky_target_rate,
517 vg.time_delta * 5.0 );
518
519 world_routes_update_timer_texts( world );
520 world_routes_update( world );
521 //world_routes_debug( world );
522
523 /* ---- SFD ------------ */
524
525 if( mdl_arrcount( &world->ent_route ) ){
526 u32 closest = 0;
527 float min_dist = INFINITY;
528
529 for( u32 i=0; i<mdl_arrcount( &world->ent_route ); i++ ){
530 ent_route *route = mdl_arritm( &world->ent_route, i );
531 float dist = v3_dist2( route->board_transform[3], pos );
532
533 if( dist < min_dist ){
534 min_dist = dist;
535 closest = i;
536 }
537 }
538
539 if( (world_global.sfd.active_route_board != closest)
540 || network_scores_updated )
541 {
542 network_scores_updated = 0;
543 world_global.sfd.active_route_board = closest;
544
545 ent_route *route = mdl_arritm( &world->ent_route, closest );
546 u32 id = route->official_track_id;
547
548 if( id != 0xffffffff ){
549 struct netmsg_board *local_board =
550 &scoreboard_client_data.boards[id];
551
552 for( int i=0; i<13; i++ ){
553 sfd_encode( i, &local_board->data[27*i] );
554 }
555 }else{
556 sfd_encode( 0, mdl_pstr( &world->meta, route->pstr_name ) );
557 sfd_encode( 1, "No data" );
558 }
559 }
560 }
561 sfd_update();
562
563
564
565 static float random_accum = 0.0f;
566 random_accum += vg.time_delta;
567
568 u32 random_ticks = 0;
569
570 while( random_accum > 0.1f ){
571 random_accum -= 0.1f;
572 random_ticks ++;
573 }
574
575 float radius = 25.0f;
576 boxf volume_proximity;
577 v3_add( pos, (v3f){ radius, radius, radius }, volume_proximity[1] );
578 v3_sub( pos, (v3f){ radius, radius, radius }, volume_proximity[0] );
579
580 bh_iter it;
581 bh_iter_init( 0, &it );
582 int idx;
583
584 int in_volume = 0;
585
586 while( bh_next( world->volume_bh, &it, volume_proximity, &idx ) ){
587 ent_volume *volume = mdl_arritm( &world->ent_volume, idx );
588
589 boxf cube = {{-1.0f,-1.0f,-1.0f},{1.0f,1.0f,1.0f}};
590
591 if( volume->type == k_volume_subtype_trigger ){
592 v3f local;
593 m4x3_mulv( volume->to_local, pos, local );
594
595 if( (fabsf(local[0]) <= 1.0f) &&
596 (fabsf(local[1]) <= 1.0f) &&
597 (fabsf(local[2]) <= 1.0f) )
598 {
599 in_volume = 1;
600 vg_line_boxf_transformed( volume->to_world, cube, 0xff00ff00 );
601
602 if( !world_global.in_volume ){
603 ent_call basecall;
604 basecall.ent.index = idx;
605 basecall.ent.type = k_ent_volume;
606 basecall.function = k_ent_function_trigger;
607 basecall.data = NULL;
608
609 entity_call( world, &basecall );
610 }
611 }
612 else
613 vg_line_boxf_transformed( volume->to_world, cube, 0xff0000ff );
614 }
615 else if( volume->type == k_volume_subtype_particle ){
616 vg_line_boxf_transformed( volume->to_world, cube, 0xff00c0ff );
617
618 for( int j=0; j<random_ticks; j++ ){
619 ent_call basecall;
620 basecall.ent.index = idx;
621 basecall.ent.type = k_ent_volume;
622 basecall.function = k_ent_function_trigger;
623 basecall.data = NULL;
624
625 entity_call( world, &basecall );
626 }
627 }
628 }
629 world_global.in_volume = in_volume;
630
631 #if 0
632 if( k_debug_light_indices )
633 {
634 for( int i=0; i<world->light_count; i++ ){
635 struct world_light *light = &world->lights[i];
636 struct classtype_world_light *inf = light->inf;
637
638 u32 colour = 0xff000000;
639 u8 r = inf->colour[0] * 255.0f,
640 g = inf->colour[1] * 255.0f,
641 b = inf->colour[2] * 255.0f;
642
643 colour |= r;
644 colour |= g << 8;
645 colour |= b << 16;
646
647 vg_line_pt3( light->node->co, 0.25f, colour );
648 }
649 }
650
651 #endif
652
653 #if 0
654
655 /* process soundscape transactions */
656 audio_lock();
657 for( int i=0; i<world->soundscape_count; i++ )
658 {
659 struct soundscape *s = &world->soundscapes[i];
660 s->usage_count = 0;
661
662 for( int j=0; j<s->max_instances; j++ )
663 {
664 if( s->channels[j] )
665 {
666 if( audio_channel_finished(s->channels[j]) )
667 s->channels[j] = audio_relinquish_channel( s->channels[j] );
668 else
669 s->usage_count ++;
670 }
671 }
672 }
673 audio_unlock();
674 #endif
675 }
676
677 /*
678 * -----------------------------------------------------------------------------
679 * API implementation
680 * -----------------------------------------------------------------------------
681 */
682
683 VG_STATIC void ray_world_get_tri( world_instance *world,
684 ray_hit *hit, v3f tri[3] )
685 {
686 for( int i=0; i<3; i++ )
687 v3_copy( world->scene_geo->arrvertices[ hit->tri[i] ].co, tri[i] );
688 }
689
690 VG_STATIC int ray_world( world_instance *world,
691 v3f pos, v3f dir, ray_hit *hit )
692 {
693 return scene_raycast( world->scene_geo, world->geo_bh, pos, dir, hit );
694 }
695
696 /*
697 * Cast a sphere from a to b and see what time it hits
698 */
699 VG_STATIC int spherecast_world( world_instance *world,
700 v3f pa, v3f pb, float r, float *t, v3f n )
701 {
702 bh_iter it;
703 bh_iter_init( 0, &it );
704
705 boxf region;
706 box_init_inf( region );
707 box_addpt( region, pa );
708 box_addpt( region, pb );
709
710 v3_add( (v3f){ r, r, r}, region[1], region[1] );
711 v3_add( (v3f){-r,-r,-r}, region[0], region[0] );
712
713 v3f dir;
714 v3_sub( pb, pa, dir );
715
716 v3f dir_inv;
717 dir_inv[0] = 1.0f/dir[0];
718 dir_inv[1] = 1.0f/dir[1];
719 dir_inv[2] = 1.0f/dir[2];
720
721 int hit = -1;
722 float min_t = 1.0f;
723
724 int idx;
725 while( bh_next( world->geo_bh, &it, region, &idx ) ){
726 u32 *ptri = &world->scene_geo->arrindices[ idx*3 ];
727 v3f tri[3];
728
729 boxf box;
730 box_init_inf( box );
731
732 for( int j=0; j<3; j++ ){
733 v3_copy( world->scene_geo->arrvertices[ptri[j]].co, tri[j] );
734 box_addpt( box, tri[j] );
735 }
736
737 v3_add( (v3f){ r, r, r}, box[1], box[1] );
738 v3_add( (v3f){-r,-r,-r}, box[0], box[0] );
739
740 if( !ray_aabb1( box, pa, dir_inv, 1.0f ) )
741 continue;
742
743 float t;
744 v3f n1;
745 if( spherecast_triangle( tri, pa, dir, r, &t, n1 ) ){
746 if( t < min_t ){
747 min_t = t;
748 hit = idx;
749 v3_copy( n1, n );
750 }
751 }
752 }
753
754 *t = min_t;
755 return hit;
756 }
757
758 VG_STATIC
759 struct world_surface *world_tri_index_surface( world_instance *world,
760 u32 index )
761 {
762 for( int i=1; i<world->surface_count; i++ ){
763 struct world_surface *surf = &world->surfaces[i];
764
765 if( (index >= surf->sm_geo.vertex_start) &&
766 (index < surf->sm_geo.vertex_start+surf->sm_geo.vertex_count ) )
767 {
768 return surf;
769 }
770 }
771
772 return &world->surfaces[0];
773 }
774
775 VG_STATIC struct world_surface *world_contact_surface( world_instance *world,
776 rb_ct *ct )
777 {
778 return world_tri_index_surface( world, ct->element_id );
779 }
780
781 VG_STATIC struct world_surface *ray_hit_surface( world_instance *world,
782 ray_hit *hit )
783 {
784 return world_tri_index_surface( world, hit->tri[0] );
785 }
786
787 #endif /* WORLD_H */