yabadabadooo
[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/planeinf.h"
25 #include "shaders/standard.h"
26 #include "shaders/vblend.h"
27 #include "shaders/gpos.h"
28 #include "shaders/fscolour.h"
29 #include "shaders/alphatest.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 VG_STATIC struct gworld
50 {
51 /*
52 * Allocated as system memory
53 * --------------------------------------------------------------------------
54 */
55
56 /* rendering */
57 glmesh skydome;
58 mdl_submesh dome_upper, dome_lower;
59
60 glmesh mesh_gate_surface;
61
62 double sky_time, sky_rate, sky_target_rate;
63
64 /* water rendering */
65 struct
66 {
67 struct framebuffer fbreflect, fbdepth;
68
69 boxf depthbounds;
70 int depth_computed;
71
72 float height;
73 int enabled;
74 v4f plane;
75 }
76 water;
77
78 /* split flap display */
79 struct
80 {
81 mdl_submesh *sm_module, *sm_card;
82 glmesh mesh_base, mesh_display;
83
84 u32 w, h;
85 float *buffer;
86 }
87 sfd;
88
89 /* timing bars, fixed maximum amount */
90 struct route_ui_bar
91 {
92 GLuint vao, vbo, ebo;
93
94 u32 indices_head;
95 u32 vertex_head;
96
97 struct route_ui_segment
98 {
99 float length;
100 u32 vertex_start, vertex_count,
101 index_start, index_count, notches;
102 }
103 segments[k_max_ui_segments];
104
105 u32 segment_start, segment_count, fade_start, fade_count;
106 double fade_timer_start;
107 float xpos;
108 }
109 ui_bars[16];
110
111 v3f render_gate_pos;
112 int active_route_board;
113
114 /* This is a small flag we use to changelevel.
115 * It will not be cleared until all sounds stop playing
116 */
117 int switching_to_new_world;
118 char world_name[ 64 ];
119
120 /*
121 * Dynamically allocated when world_load is called.
122 *
123 * the following arrays index somewhere into this linear
124 * allocator
125 *
126 * (world_gen.h)
127 * --------------------------------------------------------------------------
128 */
129 void *dynamic_vgl;
130
131 /*
132 * Main world .mdl
133 */
134 mdl_context *meta;
135
136 /*
137 * Named safe places to respawn
138 */
139 struct respawn_point
140 {
141 v3f co;
142 v4f q;
143 const char *name;
144 }
145 * spawns;
146 u32 spawn_count;
147
148 /*
149 * Audio player entities
150 */
151 struct world_audio_thing
152 {
153 v3f pos;
154 float volume;
155 u32 flags;
156
157 audio_player player;
158 audio_clip temp_embedded_clip;
159 }
160 * audio_things;
161 u32 audio_things_count;
162
163 /*
164 * Relays, random, etc
165 */
166 struct logic_entity
167 {
168 v3f pos;
169 enum logic_type logic_type;
170 int enabled;
171
172 /* indexes the action array */
173 u32 action_start, action_count;
174 }
175 * logic_entities;
176 u32 logic_entity_count;
177
178 /*
179 * Action array
180 */
181 struct logic_action
182 {
183 u32 event, /* on trigger, on enable, etc (TODO: Enum) */
184 target_id; /* thing to target, 0: self */
185
186 }
187 * logic_actions;
188 u32 logic_action_count;
189
190 /*
191 * Box trigger entities
192 */
193 struct trigger_zone
194 {
195 m4x3f transform, inv_transform;
196 u32 trigger_entity;
197 }
198 * triggers;
199 u32 trigger_count;
200
201
202 /*
203 * Routes (world_routes.h)
204 * --------------------------------------------------------------------------
205 */
206 struct route_node
207 {
208 v3f co, right, up, h;
209 u32 next[2];
210
211 u32 special_type, special_id, current_refs, ref_count;
212 u32 route_ids[4]; /* Gates can be linked into up to four routes */
213 }
214 *nodes;
215 u32 node_count;
216
217 struct route
218 {
219 u32 track_id;
220 v4f colour;
221
222 u32 start;
223 mdl_submesh sm;
224
225 int active;
226 float factive;
227
228 double best_lap, latest_pass; /* Session */
229
230 m4x3f scoreboard_transform;
231 }
232 *routes;
233 u32 route_count;
234
235 struct route_gate
236 {
237 struct teleport_gate
238 {
239 v3f co[2];
240 v4f q[2];
241 v2f dims;
242
243 m4x3f to_world, recv_to_world, transport;
244 }
245 gate;
246
247 u32 node_id;
248
249 struct route_timing
250 {
251 u32 version; /* Incremented on every teleport */
252 double time;
253 }
254 timing;
255 }
256 *gates;
257 u32 gate_count;
258
259 struct route_collector
260 {
261 struct route_timing timing;
262 }
263 *collectors;
264 u32 collector_count;
265
266
267 /* logic
268 * ----------------------------------------------------
269 */
270
271 u32 active_gate,
272 current_run_version;
273 double time, rewind_from, rewind_to, last_use;
274
275 /* world geometry */
276 scene *scene_geo,
277 *scene_no_collide,
278 *scene_lines;
279
280 /* spacial mappings */
281 bh_tree *audio_bh,
282 *trigger_bh,
283 *geo_bh;
284
285 /* graphics */
286 glmesh mesh_geo,
287 mesh_no_collide,
288 mesh_route_lines,
289 mesh_water;
290
291 rigidbody rb_geo;
292
293 /* TODO Maybe make this less hardcoded */
294 mdl_submesh sm_geo_std_oob, sm_geo_std, sm_geo_vb,
295 sm_foliage_main, sm_foliage_alphatest,
296 sm_graffiti, sm_subworld, sm_terrain;
297
298 /*
299 * Allocated AFTER all previous buffers are done
300 * --------------------------------------------------------------------------
301 */
302
303 struct instance_cache
304 {
305 mdl_context *mdl;
306 u32 pstr_file;
307 }
308 instance_cache[32];
309 u32 instance_cache_count;
310 }
311 world;
312
313
314 /*
315 * API
316 */
317
318 VG_STATIC int ray_hit_is_ramp( ray_hit *hit );
319 VG_STATIC int ray_hit_is_terrain( ray_hit *hit );
320 VG_STATIC void ray_world_get_tri( ray_hit *hit, v3f tri[3] );
321 VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit );
322
323 /*
324 * Submodules
325 */
326
327 #include "world_routes.h"
328 #include "world_sfd.h"
329 #include "world_render.h"
330 #include "world_water.h"
331 #include "world_gen.h"
332 #include "world_gate.h"
333
334 /*
335 * -----------------------------------------------------------------------------
336 * Events
337 * -----------------------------------------------------------------------------
338 */
339
340 VG_STATIC int world_stop_sound( int argc, const char *argv[] )
341 {
342 /*
343 * None of our world audio runs as one shots, they always have a player.
344 * Therefore it is safe to delete clip data after the players are
345 * disconnected
346 */
347 audio_lock();
348 for( int i=0; i<world.audio_things_count; i++ )
349 {
350 struct world_audio_thing *at = &world.audio_things[i];
351
352 if( audio_player_is_playing( &at->player ) )
353 {
354 u32 cflags = audio_player_get_flags( &at->player );
355 audio_player_set_flags( &at->player, cflags | AUDIO_FLAG_KILL );
356 }
357 }
358 audio_unlock();
359
360 return 0;
361 }
362
363 VG_STATIC int world_change_world( int argc, const char *argv[] )
364 {
365 if( argc == 0 )
366 {
367 vg_info( "%s\n", world.world_name );
368 return 0;
369 }
370 else
371 {
372 vg_info( "Switching world...\n" );
373 strcpy( world.world_name, argv[0] );
374 world.switching_to_new_world = 1;
375 world_stop_sound( 0, NULL );
376 }
377
378 return 0;
379 }
380
381 VG_STATIC void world_init(void)
382 {
383 vg_convar_push( (struct vg_convar){
384 .name = "water_enable",
385 .data = &world.water.enabled,
386 .data_type = k_convar_dtype_i32,
387 .opt_i32 = { .min=0, .max=1, .clamp=1 },
388 .persistent = 0
389 });
390
391 vg_function_push( (struct vg_cmd)
392 {
393 .name = "world_stop_sound",
394 .function = world_stop_sound
395 });
396
397 vg_function_push( (struct vg_cmd)
398 {
399 .name = "world",
400 .function = world_change_world
401 });
402
403 world.sky_rate = 1.0;
404 world.sky_target_rate = 1.0;
405
406 shader_terrain_register();
407 shader_sky_register();
408 shader_planeinf_register();
409 shader_gpos_register();
410 shader_fscolour_register();
411 shader_alphatest_register();
412
413 vg_info( "Loading world resources\n" );
414
415 vg_linear_clear( vg_mem.scratch );
416 mdl_context *msky = mdl_load_full( vg_mem.scratch, "models/rs_skydome.mdl" );
417
418 mdl_node *nlower = mdl_node_from_name( msky, "dome_lower" ),
419 *nupper = mdl_node_from_name( msky, "dome_upper" );
420
421 world.dome_lower = *mdl_node_submesh( msky, nlower, 0 );
422 world.dome_upper = *mdl_node_submesh( msky, nupper, 0 );
423
424 vg_acquire_thread_sync();
425 {
426 mdl_unpack_glmesh( msky, &world.skydome );
427 }
428 vg_release_thread_sync();
429
430 /* Other systems */
431 vg_info( "Loading other world systems\n" );
432
433 vg_loader_highwater( world_render_init, NULL, NULL );
434 vg_loader_highwater( world_sfd_init, NULL, NULL );
435 vg_loader_highwater( world_water_init, NULL, NULL );
436 vg_loader_highwater( world_gates_init, NULL, NULL );
437 vg_loader_highwater( world_routes_init, NULL, NULL );
438
439 /* Allocate dynamic world memory arena */
440 u32 max_size = 72*1024*1024;
441 world.dynamic_vgl = vg_create_linear_allocator( vg_mem.rtmemory, max_size );
442 for( u32 i=0; i<72*1024*1024; i++ )
443 ((u8 *)world.dynamic_vgl)[i] = 0xfe;
444 }
445
446 VG_STATIC void world_update( v3f pos )
447 {
448 if( world.switching_to_new_world )
449 {
450 int all_stopped = 1;
451
452 audio_lock();
453 for( int i=0; i<world.audio_things_count; i++ )
454 {
455 struct world_audio_thing *at = &world.audio_things[i];
456
457 if( audio_player_is_playing( &at->player ) )
458 {
459 all_stopped = 0;
460 break;
461 }
462 }
463 audio_unlock();
464
465 if( all_stopped )
466 {
467 world.switching_to_new_world = 0;
468 world_unload();
469 world_load();
470 }
471 }
472
473
474 world.sky_time += world.sky_rate * vg.time_delta;
475 world.sky_rate = vg_lerp( world.sky_rate, world.sky_target_rate,
476 vg.time_delta * 5.0 );
477
478 world_routes_update();
479 #if 0
480 world_routes_debug();
481 #endif
482
483 int closest = 0;
484 float min_dist = INFINITY;
485
486 for( int i=0; i<world.route_count; i++ )
487 {
488 float d = v3_dist2( world.routes[i].scoreboard_transform[3], pos );
489
490 if( d < min_dist )
491 {
492 min_dist = d;
493 closest = i;
494 }
495 }
496
497 if( (world.active_route_board != closest) || network_scores_updated )
498 {
499 network_scores_updated = 0;
500 world.active_route_board = closest;
501
502 struct route *route = &world.routes[closest];
503
504 u32 id = route->track_id;
505
506 if( id != 0xffffffff )
507 {
508 struct netmsg_board *local_board = &scoreboard_client_data.boards[id];
509
510 for( int i=0; i<13; i++ )
511 {
512 sfd_encode( i, &local_board->data[27*i] );
513 }
514 }
515 }
516
517 #if 0
518 VG_STATIC int in_zone = 0;
519
520 int in_zone_this_time = 0;
521
522 for( int i=0; i<world.achievement_zones_count; i++ )
523 {
524 struct achievement_zone *zone = &world.achievement_zones[i];
525
526 v3f local;
527 m4x3_mulv( zone->inv_transform, pos, local );
528
529 if( (fabsf(local[0]) <= 1.0f) &&
530 (fabsf(local[1]) <= 1.0f) &&
531 (fabsf(local[2]) <= 1.0f) )
532 {
533 in_zone_this_time = 1;
534
535 if( !in_zone && zone->ptarget )
536 {
537 audio_lock();
538 audio_player_playclip( &zone->ptarget->player,
539 &zone->ptarget->temp_embedded_clip );
540 audio_unlock();
541 }
542
543 if( !zone->triggered )
544 {
545 steam_set_achievement( zone->name );
546 steam_store_achievements();
547 }
548
549 zone->triggered = 1;
550 }
551
552 vg_line_boxf_transformed( zone->transform, (boxf){{-1.0f,-1.0f,-1.0f},
553 { 1.0f, 1.0f, 1.0f}},
554 0xff00ff00 );
555 }
556
557 in_zone = in_zone_this_time;
558 #endif
559
560 sfd_update();
561 }
562
563 /*
564 * -----------------------------------------------------------------------------
565 * API implementation
566 * -----------------------------------------------------------------------------
567 */
568
569 VG_STATIC void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
570 {
571 for( int i=0; i<3; i++ )
572 v3_copy( world.scene_geo->arrvertices[ hit->tri[i] ].co, tri[i] );
573 }
574
575 VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit )
576 {
577 return scene_raycast( world.scene_geo, world.geo_bh, pos, dir, hit );
578 }
579
580 VG_STATIC int ray_hit_is_terrain( ray_hit *hit )
581 {
582 u32 valid_start = 0,
583 valid_end = world.sm_terrain.vertex_count;
584
585 return (hit->tri[0] >= valid_start) &&
586 (hit->tri[0] < valid_end);
587 }
588
589 VG_STATIC int ray_hit_is_ramp( ray_hit *hit )
590 {
591 u32 valid_start = world.sm_geo_std.vertex_start,
592 valid_end = world.sm_geo_vb.vertex_start;
593
594 return (hit->tri[0] >= valid_start) &&
595 (hit->tri[0] < valid_end);
596 }
597
598 #endif /* WORLD_H */