well yeah i guess
[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 float last_notch;
98
99 struct route_ui_segment
100 {
101 float length;
102 u32 vertex_start, vertex_count,
103 index_start, index_count, notches;
104 }
105 segments[k_max_ui_segments];
106
107 u32 segment_start, segment_count, fade_start, fade_count;
108 double fade_timer_start;
109 float xpos;
110 }
111 ui_bars[16];
112
113 v3f render_gate_pos;
114 int active_route_board;
115
116 /*
117 * Dynamically allocated when world_load is called.
118 *
119 * the following arrays index somewhere into this linear
120 * allocator
121 *
122 * (world_gen.h)
123 * --------------------------------------------------------------------------
124 */
125 void *dynamic_vgl;
126
127 /*
128 * Main world .mdl
129 */
130 mdl_context *meta;
131
132 /*
133 * Named safe places to respawn
134 */
135 struct respawn_point
136 {
137 v3f co;
138 v4f q;
139 const char *name;
140 }
141 * spawns;
142 u32 spawn_count;
143
144 /*
145 * Audio player entities
146 */
147 struct world_audio_thing
148 {
149 v3f pos;
150 float volume;
151 u32 flags;
152
153 audio_player player;
154 audio_clip temp_embedded_clip;
155 }
156 * audio_things;
157 u32 audio_things_count;
158
159 /*
160 * Relays, random, etc
161 */
162 struct logic_entity
163 {
164 v3f pos;
165 enum logic_type logic_type;
166 int enabled;
167
168 /* indexes the action array */
169 u32 action_start, action_count;
170 }
171 * logic_entities;
172 u32 logic_entity_count;
173
174 /*
175 * Action array
176 */
177 struct logic_action
178 {
179 u32 event, /* on trigger, on enable, etc (TODO: Enum) */
180 target_id; /* thing to target, 0: self */
181
182 }
183 * logic_actions;
184 u32 logic_action_count;
185
186 /*
187 * Box trigger entities
188 */
189 struct trigger_zone
190 {
191 m4x3f transform, inv_transform;
192 u32 trigger_entity;
193 }
194 * triggers;
195 u32 trigger_count;
196
197
198 /*
199 * Routes (world_routes.h)
200 * --------------------------------------------------------------------------
201 */
202 struct route_node
203 {
204 v3f co, right, up, h;
205 u32 next[2];
206
207 u32 special_type, special_id, current_refs, ref_count;
208 u32 route_ids[4]; /* Gates can be linked into up to four routes */
209 }
210 *nodes;
211 u32 node_count;
212
213 struct route
214 {
215 u32 track_id;
216 v4f colour;
217
218 u32 start;
219 mdl_submesh sm;
220
221 int active;
222 float factive;
223
224 double best_lap, latest_pass; /* Session */
225
226 m4x3f scoreboard_transform;
227 }
228 *routes;
229 u32 route_count;
230
231 struct route_gate
232 {
233 struct teleport_gate
234 {
235 v3f co[2];
236 v4f q[2];
237 v2f dims;
238
239 m4x3f to_world, recv_to_world, transport;
240 }
241 gate;
242
243 u32 node_id;
244
245 struct route_timing
246 {
247 u32 version; /* Incremented on every teleport */
248 double time;
249 }
250 timing;
251 }
252 *gates;
253 u32 gate_count;
254
255 struct route_collector
256 {
257 struct route_timing timing;
258 }
259 *collectors;
260 u32 collector_count;
261
262
263 /* logic
264 * ----------------------------------------------------
265 */
266
267 u32 active_gate,
268 current_run_version;
269 double time, rewind_from, rewind_to, last_use;
270
271 /* world geometry */
272 scene *scene_geo,
273 *scene_no_collide,
274 *scene_lines;
275
276 /* spacial mappings */
277 bh_tree *audio_bh,
278 *trigger_bh,
279 *geo_bh;
280
281 /* graphics */
282 glmesh mesh_geo,
283 mesh_no_collide,
284 mesh_route_lines,
285 mesh_water;
286
287 rigidbody rb_geo;
288
289 /* TODO Maybe make this less hardcoded */
290 mdl_submesh sm_geo_std_oob, sm_geo_std, sm_geo_vb,
291 sm_foliage_main, sm_foliage_alphatest,
292 sm_graffiti, sm_subworld, sm_terrain;
293
294 /*
295 * Allocated AFTER all previous buffers are done
296 * --------------------------------------------------------------------------
297 */
298
299 struct instance_cache
300 {
301 mdl_context *mdl;
302 u32 pstr_file;
303 }
304 instance_cache[32];
305 u32 instance_cache_count;
306 }
307 world;
308
309
310 /*
311 * API
312 */
313
314 VG_STATIC int ray_hit_is_ramp( ray_hit *hit );
315 VG_STATIC int ray_hit_is_terrain( ray_hit *hit );
316 VG_STATIC void ray_world_get_tri( ray_hit *hit, v3f tri[3] );
317 VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit );
318
319 /*
320 * Submodules
321 */
322
323 #include "world_routes.h"
324 #include "world_sfd.h"
325 #include "world_render.h"
326 #include "world_water.h"
327 #include "world_gen.h"
328 #include "world_gate.h"
329
330 /*
331 * -----------------------------------------------------------------------------
332 * Events
333 * -----------------------------------------------------------------------------
334 */
335
336 VG_STATIC void world_init(void)
337 {
338 vg_convar_push( (struct vg_convar){
339 .name = "water_enable",
340 .data = &world.water.enabled,
341 .data_type = k_convar_dtype_i32,
342 .opt_i32 = { .min=0, .max=1, .clamp=1 },
343 .persistent = 0
344 });
345
346 world.sky_rate = 1.0;
347 world.sky_target_rate = 1.0;
348
349 shader_terrain_register();
350 shader_sky_register();
351 shader_planeinf_register();
352 shader_gpos_register();
353 shader_fscolour_register();
354 shader_alphatest_register();
355
356 vg_info( "Loading world resources\n" );
357
358 vg_linear_clear( vg_mem.scratch );
359 mdl_context *msky = mdl_load_full( vg_mem.scratch, "models/rs_skydome.mdl" );
360
361 mdl_node *nlower = mdl_node_from_name( msky, "dome_lower" ),
362 *nupper = mdl_node_from_name( msky, "dome_upper" );
363
364 world.dome_lower = *mdl_node_submesh( msky, nlower, 0 );
365 world.dome_upper = *mdl_node_submesh( msky, nupper, 0 );
366
367 vg_acquire_thread_sync();
368 {
369 mdl_unpack_glmesh( msky, &world.skydome );
370 }
371 vg_release_thread_sync();
372
373 /* Other systems */
374 vg_info( "Loading other world systems\n" );
375
376 vg_loader_highwater( world_render_init, NULL, NULL );
377 vg_loader_highwater( world_sfd_init, NULL, NULL );
378 vg_loader_highwater( world_water_init, NULL, NULL );
379 vg_loader_highwater( world_gates_init, NULL, NULL );
380 vg_loader_highwater( world_routes_init, NULL, NULL );
381
382 /* Allocate dynamic world memory arena */
383 u32 max_size = 72*1024*1024;
384 world.dynamic_vgl = vg_create_linear_allocator( vg_mem.rtmemory, max_size );
385 }
386
387 VG_STATIC void world_update( v3f pos )
388 {
389 world.sky_time += world.sky_rate * vg.time_delta;
390 world.sky_rate = vg_lerp( world.sky_rate, world.sky_target_rate,
391 vg.time_delta * 5.0 );
392
393 world_routes_update();
394 #if 0
395 world_routes_debug();
396 #endif
397
398 int closest = 0;
399 float min_dist = INFINITY;
400
401 for( int i=0; i<world.route_count; i++ )
402 {
403 float d = v3_dist2( world.routes[i].scoreboard_transform[3], pos );
404
405 if( d < min_dist )
406 {
407 min_dist = d;
408 closest = i;
409 }
410 }
411
412 if( (world.active_route_board != closest) || network_scores_updated )
413 {
414 network_scores_updated = 0;
415 world.active_route_board = closest;
416
417 struct route *route = &world.routes[closest];
418
419 u32 id = route->track_id;
420
421 if( id != 0xffffffff )
422 {
423 struct netmsg_board *local_board = &scoreboard_client_data.boards[id];
424
425 for( int i=0; i<13; i++ )
426 {
427 sfd_encode( i, &local_board->data[27*i] );
428 }
429 }
430 }
431
432 #if 0
433 VG_STATIC int in_zone = 0;
434
435 int in_zone_this_time = 0;
436
437 for( int i=0; i<world.achievement_zones_count; i++ )
438 {
439 struct achievement_zone *zone = &world.achievement_zones[i];
440
441 v3f local;
442 m4x3_mulv( zone->inv_transform, pos, local );
443
444 if( (fabsf(local[0]) <= 1.0f) &&
445 (fabsf(local[1]) <= 1.0f) &&
446 (fabsf(local[2]) <= 1.0f) )
447 {
448 in_zone_this_time = 1;
449
450 if( !in_zone && zone->ptarget )
451 {
452 audio_lock();
453 audio_player_playclip( &zone->ptarget->player,
454 &zone->ptarget->temp_embedded_clip );
455 audio_unlock();
456 }
457
458 if( !zone->triggered )
459 {
460 steam_set_achievement( zone->name );
461 steam_store_achievements();
462 }
463
464 zone->triggered = 1;
465 }
466
467 vg_line_boxf_transformed( zone->transform, (boxf){{-1.0f,-1.0f,-1.0f},
468 { 1.0f, 1.0f, 1.0f}},
469 0xff00ff00 );
470 }
471
472 in_zone = in_zone_this_time;
473 #endif
474
475 sfd_update();
476 }
477
478 /*
479 * -----------------------------------------------------------------------------
480 * API implementation
481 * -----------------------------------------------------------------------------
482 */
483
484 VG_STATIC void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
485 {
486 for( int i=0; i<3; i++ )
487 v3_copy( world.scene_geo->arrvertices[ hit->tri[i] ].co, tri[i] );
488 }
489
490 VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit )
491 {
492 return scene_raycast( world.scene_geo, world.geo_bh, pos, dir, hit );
493 }
494
495 VG_STATIC int ray_hit_is_terrain( ray_hit *hit )
496 {
497 u32 valid_start = 0,
498 valid_end = world.sm_terrain.vertex_count;
499
500 return (hit->tri[0] >= valid_start) &&
501 (hit->tri[0] < valid_end);
502 }
503
504 VG_STATIC int ray_hit_is_ramp( ray_hit *hit )
505 {
506 u32 valid_start = world.sm_geo_std.vertex_start,
507 valid_end = world.sm_geo_vb.vertex_start;
508
509 return (hit->tri[0] >= valid_start) &&
510 (hit->tri[0] < valid_end);
511 }
512
513 #endif /* WORLD_H */