bouncy balls
[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 rb_object obj;
243 m4x3f mlocal;
244 ent_glyph *glyph;
245 v4f colour;
246
247 m4x3f mdl;
248 }
249 text_particles[6*4];
250 u32 text_particle_count;
251
252 }
253 world_global;
254
255 VG_STATIC world_instance *get_active_world( void )
256 {
257 return &world_global.worlds[ world_global.active_world ];
258 }
259
260 /*
261 * API
262 */
263
264 VG_STATIC
265 int ray_hit_is_ramp( world_instance *world, ray_hit *hit );
266
267 VG_STATIC
268 struct world_surface *ray_hit_surface( world_instance *world, ray_hit *hit );
269
270 VG_STATIC
271 void ray_world_get_tri( world_instance *world, ray_hit *hit, v3f tri[3] );
272
273 VG_STATIC
274 int ray_world( world_instance *world, v3f pos, v3f dir, ray_hit *hit );
275
276 /*
277 * Submodules
278 */
279
280 #include "world_routes.h"
281 #include "world_sfd.h"
282 #include "world_render.h"
283 #include "world_water.h"
284 #include "world_volumes.h"
285 #include "world_gen.h"
286 #include "world_gate.h"
287
288 /*
289 * -----------------------------------------------------------------------------
290 * Events
291 * -----------------------------------------------------------------------------
292 */
293
294 VG_STATIC int world_stop_sound( int argc, const char *argv[] )
295 {
296 world_instance *world = get_active_world();
297 return 0;
298 }
299
300 VG_STATIC void world_init(void)
301 {
302 world_global.sky_rate = 1.0;
303 world_global.sky_target_rate = 1.0;
304
305 shader_scene_standard_register();
306 shader_scene_standard_alphatest_register();
307 shader_scene_vertex_blend_register();
308 shader_scene_terrain_register();
309 shader_scene_depth_register();
310 shader_scene_position_register();
311
312 shader_model_sky_register();
313
314 vg_info( "Loading world resources\n" );
315
316 vg_linear_clear( vg_mem.scratch );
317
318 mdl_context msky;
319 mdl_open( &msky, "models/rs_skydome.mdl", vg_mem.scratch );
320 mdl_load_metadata_block( &msky, vg_mem.scratch );
321 mdl_load_mesh_block( &msky, vg_mem.scratch );
322 mdl_close( &msky );
323
324 vg_acquire_thread_sync();
325 {
326 mdl_unpack_glmesh( &msky, &world_global.skydome );
327 }
328 vg_release_thread_sync();
329
330 /* Other systems */
331 vg_info( "Loading other world systems\n" );
332
333 vg_loader_step( world_render_init, NULL );
334 vg_loader_step( world_sfd_init, NULL );
335 vg_loader_step( world_water_init, NULL );
336 vg_loader_step( world_gates_init, NULL );
337 vg_loader_step( world_routes_init, NULL );
338
339 /* Allocate dynamic world memory arena */
340 u32 max_size = 76*1024*1024;
341 world_global.generic_heap = vg_create_linear_allocator( vg_mem.rtmemory,
342 max_size,
343 VG_MEMORY_SYSTEM );
344 }
345
346 typedef struct ent_call ent_call;
347 struct ent_call{
348 ent_index ent;
349 u32 function;
350 void *data;
351 };
352
353 VG_STATIC void entity_call( world_instance *world, ent_call *call );
354
355 VG_STATIC void ent_volume_call( world_instance *world, ent_call *call )
356 {
357 ent_volume *volume = mdl_arritm( &world->ent_volume, call->ent.index );
358 if( !volume->target.type ) return;
359
360 if( call->function == k_ent_function_trigger ){
361 call->ent = volume->target;
362
363 if( volume->type == k_volume_subtype_particle ){
364 float *co = alloca( sizeof(float)*3 );
365 co[0] = vg_randf()*2.0f-1.0f;
366 co[1] = vg_randf()*2.0f-1.0f;
367 co[2] = vg_randf()*2.0f-1.0f;
368 m4x3_mulv( volume->to_world, co, co );
369
370 call->function = k_ent_function_particle_spawn;
371 call->data = co;
372 entity_call( world, call );
373 }
374 else
375 entity_call( world, call );
376 }
377 }
378
379 VG_STATIC void ent_audio_call( world_instance *world, ent_call *call )
380 {
381 ent_audio *audio = mdl_arritm( &world->ent_audio, call->ent.index );
382
383 v3f sound_co;
384
385 if( call->function == k_ent_function_particle_spawn ){
386 v3_copy( call->data, sound_co );
387 }
388 else if( call->function == k_ent_function_trigger ){
389 v3_copy( audio->transform.co, sound_co );
390 }
391 else
392 vg_fatal_exit_loop( "ent_audio_call (invalid function id)" );
393
394 float chance = vg_randf()*100.0f,
395 bar = 0.0f;
396
397 for( u32 i=0; i<audio->clip_count; i++ ){
398 ent_audio_clip *clip = mdl_arritm( &world->ent_audio_clip,
399 audio->clip_start+i );
400
401 float mod = world->probabilities[ audio->probability_curve ],
402 p = clip->probability * mod;
403
404 bar += p;
405
406 if( chance < bar ){
407
408 audio_lock();
409
410 if( audio->behaviour == k_channel_behaviour_unlimited ){
411 audio_oneshot_3d( &clip->clip, sound_co,
412 audio->transform.s[0],
413 audio->volume );
414 }
415 else if( audio->behaviour == k_channel_behaviour_discard_if_full ){
416 audio_channel *ch =
417 audio_get_group_idle_channel( audio->group,
418 audio->max_channels );
419
420 if( ch ){
421 audio_channel_init( ch, &clip->clip, audio->flags );
422 audio_channel_group( ch, audio->group );
423 audio_channel_set_spacial( ch, sound_co, audio->transform.s[0] );
424 audio_channel_edit_volume( ch, audio->volume, 1 );
425 ch = audio_relinquish_channel( ch );
426 }
427 }
428 else if( audio->behaviour == k_channel_behaviour_crossfade_if_full){
429 audio_channel *ch =
430 audio_get_group_idle_channel( audio->group,
431 audio->max_channels );
432
433 /* group is full */
434 if( !ch ){
435 audio_channel *existing =
436 audio_get_group_first_active_channel( audio->group );
437
438 if( existing ){
439 if( existing->source == &clip->clip ){
440 audio_unlock();
441 return;
442 }
443
444 existing->group = 0;
445 existing = audio_channel_fadeout(existing, audio->crossfade);
446 }
447
448 ch = audio_get_first_idle_channel();
449 }
450
451 if( ch ){
452 audio_channel_init( ch, &clip->clip, audio->flags );
453 audio_channel_group( ch, audio->group );
454 audio_channel_fadein( ch, audio->crossfade );
455 ch = audio_relinquish_channel( ch );
456 }
457 }
458
459 audio_unlock();
460 return;
461 }
462 }
463 }
464
465 VG_STATIC void entity_call( world_instance *world, ent_call *call )
466 {
467 if( call->ent.type == k_ent_volume ){
468 ent_volume_call( world, call );
469 } else if( call->ent.type == k_ent_audio ){
470 ent_audio_call( world, call );
471 }
472 }
473
474 VG_STATIC void world_update( world_instance *world, v3f pos )
475 {
476 /* TEMP!!!!!! */
477 static double g_time = 0.0;
478 g_time += vg.time_delta * (1.0/(k_day_length*60.0));
479
480
481 struct ub_world_lighting *state = &world->ub_lighting;
482
483 state->g_time = g_time;
484 state->g_realtime = vg.time;
485 state->g_debug_indices = k_debug_light_indices;
486 state->g_light_preview = k_light_preview;
487 state->g_debug_complexity = k_debug_light_complexity;
488
489 state->g_time_of_day = vg_fractf( g_time );
490 state->g_day_phase = cosf( state->g_time_of_day * VG_PIf * 2.0f );
491 state->g_sunset_phase= cosf( state->g_time_of_day * VG_PIf * 4.0f + VG_PIf );
492
493 state->g_day_phase = state->g_day_phase * 0.5f + 0.5f;
494 state->g_sunset_phase = powf( state->g_sunset_phase * 0.5f + 0.5f, 6.0f );
495
496 float a = state->g_time_of_day * VG_PIf * 2.0f;
497 state->g_sun_dir[0] = sinf( a );
498 state->g_sun_dir[1] = cosf( a );
499 state->g_sun_dir[2] = 0.2f;
500 v3_normalize( state->g_sun_dir );
501
502
503 world->probabilities[ k_probability_curve_constant ] = 1.0f;
504
505 float dp = state->g_day_phase;
506
507 world->probabilities[ k_probability_curve_wildlife_day ] =
508 (dp*dp*0.8f+state->g_sunset_phase)*0.8f;
509 world->probabilities[ k_probability_curve_wildlife_night ] =
510 1.0f-powf(fabsf((state->g_time_of_day-0.5f)*5.0f),5.0f);
511
512
513 glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting );
514 glBufferSubData( GL_UNIFORM_BUFFER, 0,
515 sizeof(struct ub_world_lighting), &world->ub_lighting );
516 /* TEMP!!!!!! */
517
518 world_global.sky_time += world_global.sky_rate * vg.time_delta;
519 world_global.sky_rate = vg_lerp( world_global.sky_rate,
520 world_global.sky_target_rate,
521 vg.time_delta * 5.0 );
522
523 world_routes_update_timer_texts( world );
524 world_routes_update( world );
525 //world_routes_debug( world );
526
527 /* ---- SFD ------------ */
528
529 if( mdl_arrcount( &world->ent_route ) ){
530 u32 closest = 0;
531 float min_dist = INFINITY;
532
533 for( u32 i=0; i<mdl_arrcount( &world->ent_route ); i++ ){
534 ent_route *route = mdl_arritm( &world->ent_route, i );
535 float dist = v3_dist2( route->board_transform[3], pos );
536
537 if( dist < min_dist ){
538 min_dist = dist;
539 closest = i;
540 }
541 }
542
543 if( (world_global.sfd.active_route_board != closest)
544 || network_scores_updated )
545 {
546 network_scores_updated = 0;
547 world_global.sfd.active_route_board = closest;
548
549 ent_route *route = mdl_arritm( &world->ent_route, closest );
550 u32 id = route->official_track_id;
551
552 if( id != 0xffffffff ){
553 struct netmsg_board *local_board =
554 &scoreboard_client_data.boards[id];
555
556 for( int i=0; i<13; i++ ){
557 sfd_encode( i, &local_board->data[27*i] );
558 }
559 }else{
560 sfd_encode( 0, mdl_pstr( &world->meta, route->pstr_name ) );
561 sfd_encode( 1, "No data" );
562 }
563 }
564 }
565 sfd_update();
566
567
568
569 static float random_accum = 0.0f;
570 random_accum += vg.time_delta;
571
572 u32 random_ticks = 0;
573
574 while( random_accum > 0.1f ){
575 random_accum -= 0.1f;
576 random_ticks ++;
577 }
578
579 float radius = 25.0f;
580 boxf volume_proximity;
581 v3_add( pos, (v3f){ radius, radius, radius }, volume_proximity[1] );
582 v3_sub( pos, (v3f){ radius, radius, radius }, volume_proximity[0] );
583
584 bh_iter it;
585 bh_iter_init( 0, &it );
586 int idx;
587
588 int in_volume = 0;
589
590 while( bh_next( world->volume_bh, &it, volume_proximity, &idx ) ){
591 ent_volume *volume = mdl_arritm( &world->ent_volume, idx );
592
593 boxf cube = {{-1.0f,-1.0f,-1.0f},{1.0f,1.0f,1.0f}};
594
595 if( volume->type == k_volume_subtype_trigger ){
596 v3f local;
597 m4x3_mulv( volume->to_local, pos, local );
598
599 if( (fabsf(local[0]) <= 1.0f) &&
600 (fabsf(local[1]) <= 1.0f) &&
601 (fabsf(local[2]) <= 1.0f) )
602 {
603 in_volume = 1;
604 vg_line_boxf_transformed( volume->to_world, cube, 0xff00ff00 );
605
606 if( !world_global.in_volume ){
607 ent_call basecall;
608 basecall.ent.index = idx;
609 basecall.ent.type = k_ent_volume;
610 basecall.function = k_ent_function_trigger;
611 basecall.data = NULL;
612
613 entity_call( world, &basecall );
614 }
615 }
616 else
617 vg_line_boxf_transformed( volume->to_world, cube, 0xff0000ff );
618 }
619 else if( volume->type == k_volume_subtype_particle ){
620 vg_line_boxf_transformed( volume->to_world, cube, 0xff00c0ff );
621
622 for( int j=0; j<random_ticks; j++ ){
623 ent_call basecall;
624 basecall.ent.index = idx;
625 basecall.ent.type = k_ent_volume;
626 basecall.function = k_ent_function_trigger;
627 basecall.data = NULL;
628
629 entity_call( world, &basecall );
630 }
631 }
632 }
633 world_global.in_volume = in_volume;
634
635 #if 0
636 if( k_debug_light_indices )
637 {
638 for( int i=0; i<world->light_count; i++ ){
639 struct world_light *light = &world->lights[i];
640 struct classtype_world_light *inf = light->inf;
641
642 u32 colour = 0xff000000;
643 u8 r = inf->colour[0] * 255.0f,
644 g = inf->colour[1] * 255.0f,
645 b = inf->colour[2] * 255.0f;
646
647 colour |= r;
648 colour |= g << 8;
649 colour |= b << 16;
650
651 vg_line_pt3( light->node->co, 0.25f, colour );
652 }
653 }
654
655 #endif
656
657 #if 0
658
659 /* process soundscape transactions */
660 audio_lock();
661 for( int i=0; i<world->soundscape_count; i++ )
662 {
663 struct soundscape *s = &world->soundscapes[i];
664 s->usage_count = 0;
665
666 for( int j=0; j<s->max_instances; j++ )
667 {
668 if( s->channels[j] )
669 {
670 if( audio_channel_finished(s->channels[j]) )
671 s->channels[j] = audio_relinquish_channel( s->channels[j] );
672 else
673 s->usage_count ++;
674 }
675 }
676 }
677 audio_unlock();
678 #endif
679 }
680
681 /*
682 * -----------------------------------------------------------------------------
683 * API implementation
684 * -----------------------------------------------------------------------------
685 */
686
687 VG_STATIC void ray_world_get_tri( world_instance *world,
688 ray_hit *hit, v3f tri[3] )
689 {
690 for( int i=0; i<3; i++ )
691 v3_copy( world->scene_geo->arrvertices[ hit->tri[i] ].co, tri[i] );
692 }
693
694 VG_STATIC int ray_world( world_instance *world,
695 v3f pos, v3f dir, ray_hit *hit )
696 {
697 return scene_raycast( world->scene_geo, world->geo_bh, pos, dir, hit );
698 }
699
700 /*
701 * Cast a sphere from a to b and see what time it hits
702 */
703 VG_STATIC int spherecast_world( world_instance *world,
704 v3f pa, v3f pb, float r, float *t, v3f n )
705 {
706 bh_iter it;
707 bh_iter_init( 0, &it );
708
709 boxf region;
710 box_init_inf( region );
711 box_addpt( region, pa );
712 box_addpt( region, pb );
713
714 v3_add( (v3f){ r, r, r}, region[1], region[1] );
715 v3_add( (v3f){-r,-r,-r}, region[0], region[0] );
716
717 v3f dir;
718 v3_sub( pb, pa, dir );
719
720 v3f dir_inv;
721 dir_inv[0] = 1.0f/dir[0];
722 dir_inv[1] = 1.0f/dir[1];
723 dir_inv[2] = 1.0f/dir[2];
724
725 int hit = -1;
726 float min_t = 1.0f;
727
728 int idx;
729 while( bh_next( world->geo_bh, &it, region, &idx ) ){
730 u32 *ptri = &world->scene_geo->arrindices[ idx*3 ];
731 v3f tri[3];
732
733 boxf box;
734 box_init_inf( box );
735
736 for( int j=0; j<3; j++ ){
737 v3_copy( world->scene_geo->arrvertices[ptri[j]].co, tri[j] );
738 box_addpt( box, tri[j] );
739 }
740
741 v3_add( (v3f){ r, r, r}, box[1], box[1] );
742 v3_add( (v3f){-r,-r,-r}, box[0], box[0] );
743
744 if( !ray_aabb1( box, pa, dir_inv, 1.0f ) )
745 continue;
746
747 float t;
748 v3f n1;
749 if( spherecast_triangle( tri, pa, dir, r, &t, n1 ) ){
750 if( t < min_t ){
751 min_t = t;
752 hit = idx;
753 v3_copy( n1, n );
754 }
755 }
756 }
757
758 *t = min_t;
759 return hit;
760 }
761
762 VG_STATIC
763 struct world_surface *world_tri_index_surface( world_instance *world,
764 u32 index )
765 {
766 for( int i=1; i<world->surface_count; i++ ){
767 struct world_surface *surf = &world->surfaces[i];
768
769 if( (index >= surf->sm_geo.vertex_start) &&
770 (index < surf->sm_geo.vertex_start+surf->sm_geo.vertex_count ) )
771 {
772 return surf;
773 }
774 }
775
776 return &world->surfaces[0];
777 }
778
779 VG_STATIC struct world_surface *world_contact_surface( world_instance *world,
780 rb_ct *ct )
781 {
782 return world_tri_index_surface( world, ct->element_id );
783 }
784
785 VG_STATIC struct world_surface *ray_hit_surface( world_instance *world,
786 ray_hit *hit )
787 {
788 return world_tri_index_surface( world, hit->tri[0] );
789 }
790
791 #endif /* WORLD_H */