oh yeah mr crabs
[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 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 "traffic.h" /*TODO: -> world_traffic.h */
23
24 #include "shaders/terrain.h"
25 #include "shaders/sky.h"
26 #include "shaders/planeinf.h"
27 #include "shaders/standard.h"
28 #include "shaders/vblend.h"
29 #include "shaders/gpos.h"
30 #include "shaders/fscolour.h"
31 #include "shaders/alphatest.h"
32
33 enum { k_max_ui_segments = 8 };
34 enum { k_max_ui_splits_per_segment = 16 };
35
36 enum { k_max_ui_elements = k_max_ui_segments*k_max_ui_splits_per_segment };
37 enum { k_max_element_verts = 10 };
38 enum { k_max_element_indices = 20 };
39
40 enum { k_route_ui_max_verts = k_max_ui_elements*k_max_element_verts };
41 enum { k_route_ui_max_indices = k_max_ui_elements*k_max_element_indices };
42
43 static struct gworld
44 {
45 struct subworld_gen
46 {
47
48 }
49 subworld_gen;
50
51 /* gameplay */
52 struct respawn_point
53 {
54 v3f co;
55 v4f q;
56 char name[32];
57 }
58 spawns[32];
59 u32 spawn_count;
60
61 struct world_audio_thing
62 {
63 v3f pos;
64 float volume;
65 u32 flags;
66
67 audio_player player;
68 audio_clip temp_embedded_clip;
69 }
70 * audio_things;
71
72 u32 audio_things_count,
73 audio_things_cap;
74
75 struct achievement_zone
76 {
77 m4x3f transform, inv_transform;
78 char name[32];
79 int triggered;
80
81 union
82 {
83 mdl_node *ptarget_delegated;
84 struct world_audio_thing *ptarget;
85 };
86 }
87 * achievement_zones;
88
89 u32 achievement_zones_count,
90 achievement_zones_cap;
91
92 struct subworld_routes
93 {
94 struct route_node
95 {
96 v3f co, right, up, h;
97 u32 next[2];
98
99 u32 special_type, special_id, current_refs, ref_count;
100 u32 route_ids[4]; /* Gates can be linked into up to four routes */
101 }
102 *nodes;
103
104 u32 node_count,
105 node_cap;
106
107 struct route
108 {
109 u32 track_id;
110 v4f colour;
111
112 u32 start;
113 mdl_submesh sm;
114
115 int active;
116 float factive;
117
118 double best_lap, latest_pass; /* Session */
119
120 struct
121 {
122 GLuint vao, vbo, ebo;
123
124 u32 indices_head;
125 u32 vertex_head;
126
127 float last_notch;
128
129 struct route_ui_segment
130 {
131 float length;
132 u32 vertex_start, vertex_count,
133 index_start, index_count, notches;
134 }
135 segments[k_max_ui_segments];
136
137 u32 segment_start, segment_count, fade_start, fade_count;
138 double fade_timer_start;
139 float xpos;
140 }
141 ui;
142
143 m4x3f scoreboard_transform;
144 }
145 *routes;
146
147 double time, rewind_from, rewind_to, last_use;
148
149 u32 route_count,
150 route_cap;
151
152 struct route_gate
153 {
154 struct teleport_gate
155 {
156 v3f co[2];
157 v4f q[2];
158 v2f dims;
159
160 m4x3f to_world, recv_to_world, transport;
161 }
162 gate;
163
164 u32 node_id;
165
166 struct route_timing
167 {
168 u32 version; /* Incremented on every teleport */
169 double time;
170 }
171 timing;
172 }
173 *gates;
174
175 struct route_collector
176 {
177 struct route_timing timing;
178 }
179 *collectors;
180
181 u32 gate_count,
182 gate_cap,
183 collector_count,
184 collector_cap;
185
186 u32 active_gate,
187 current_run_version;
188
189 scene scene_lines;
190 }
191 routes;
192
193 struct subworld_sfd
194 {
195 scene mesh;
196 mdl_submesh *sm_module, *sm_card;
197 glmesh temp;
198
199 struct sfd_instance
200 {
201 float *buffer;
202
203 u32 w,h;
204 }
205 tester;
206 }
207 sfd;
208
209 /* Paths */
210 traffic_node traffic[128];
211 u32 traffic_count;
212
213 #if 0
214 traffic_driver van_man[6];
215 #endif
216
217 double sky_time, sky_rate, sky_target_rate;
218
219 /* Physics */
220
221 /* Rendering & geometry */
222 scene geo, foliage;
223 rigidbody rb_geo;
224
225 /* TODO Maybe make this less hardcoded */
226 mdl_submesh sm_geo_std_oob, sm_geo_std, sm_geo_vb,
227 sm_foliage_main, sm_foliage_alphatest,
228 sm_graffiti, sm_subworld, sm_terrain;
229
230 glmesh skybox, skydome;
231 mdl_submesh dome_upper, dome_lower;
232
233 glmesh cars;
234 mdl_submesh car_holden;
235
236 /* Load time */
237
238 struct instance_cache
239 {
240 mdl_header *mdl;
241 u32 pstr_file;
242 }
243 * instance_cache;
244 u32 instance_cache_count,
245 instance_cache_cap;
246
247 v3f render_gate_pos;
248 int active_route_board;
249 }
250 world ;
251
252 /*
253 * API
254 */
255
256 static int ray_hit_is_ramp( ray_hit *hit );
257 static int ray_hit_is_terrain( ray_hit *hit );
258 static void ray_world_get_tri( ray_hit *hit, v3f tri[3] );
259 static int ray_world( v3f pos, v3f dir, ray_hit *hit );
260
261 /*
262 * Submodules
263 */
264 #include "world_routes.h"
265 #include "world_sfd.h"
266 #include "world_render.h"
267 #include "world_water.h"
268 #include "world_gen.h"
269 #include "world_gate.h"
270
271 /*
272 * -----------------------------------------------------------------------------
273 * Events
274 * -----------------------------------------------------------------------------
275 */
276
277 static void world_init(void)
278 {
279 world.sky_rate = 1.0;
280 world.sky_target_rate = 1.0;
281
282 shader_terrain_register();
283 shader_sky_register();
284 shader_planeinf_register();
285 shader_gpos_register();
286 shader_fscolour_register();
287 shader_alphatest_register();
288
289 vg_info( "Loading world resources\n" );
290
291 VG_REQUIRED_ASSET( mdl_header*, mcars, mdl_load, "models/rs_cars.mdl" );
292 VG_REQUIRED_ASSET( mdl_header*, msky, mdl_load, "models/rs_skydome.mdl" );
293
294 mdl_node *nholden = mdl_node_from_name( mcars, "holden" );
295 world.car_holden = *mdl_node_submesh( mcars, nholden, 0 );
296
297 mdl_node *nlower = mdl_node_from_name( msky, "dome_lower" ),
298 *nupper = mdl_node_from_name( msky, "dome_upper" );
299
300 world.dome_lower = *mdl_node_submesh( msky, nlower, 0 );
301 world.dome_upper = *mdl_node_submesh( msky, nupper, 0 );
302
303 vg_acquire_thread_sync();
304 {
305 mdl_unpack_glmesh( mcars, &world.cars );
306 mdl_unpack_glmesh( msky, &world.skydome );
307 }
308 vg_release_thread_sync();
309
310 vg_free(mcars);
311 vg_free(msky);
312
313 /* Other systems */
314 vg_info( "Loading other world systems\n" );
315
316 vg_loader_highwater( world_render_init, world_render_free, NULL );
317 vg_loader_highwater( world_sfd_init, world_sfd_free, NULL );
318 vg_loader_highwater( world_water_init, world_water_free, NULL );
319 vg_loader_highwater( world_gates_init, world_gates_free, NULL );
320 vg_loader_highwater( world_routes_init, world_routes_free, NULL );
321 }
322
323 static void world_free( void *_ )
324 {
325 mesh_free( &world.cars );
326 mesh_free( &world.skydome );
327 vg_free( world.achievement_zones );
328
329 /* FIXME: This fucks with the audio player. Use-after-free */
330 #if 0
331 vg_free( world.audio_things );
332 #endif
333 }
334
335 static void world_update( v3f pos )
336 {
337 world.sky_time += world.sky_rate * vg.time_delta;
338 world.sky_rate = vg_lerp( world.sky_rate, world.sky_target_rate,
339 vg.time_delta * 5.0 );
340
341 world_routes_update();
342 #if 0
343 world_routes_debug();
344 #endif
345
346 int closest = 0;
347 float min_dist = INFINITY;
348
349 for( int i=0; i<world.routes.route_count; i++ )
350 {
351 float d = v3_dist2( world.routes.routes[i].scoreboard_transform[3], pos );
352
353 if( d < min_dist )
354 {
355 min_dist = d;
356 closest = i;
357 }
358 }
359
360 if( (world.active_route_board != closest) || network_scores_updated )
361 {
362 network_scores_updated = 0;
363 world.active_route_board = closest;
364 struct subworld_sfd *sfd = &world.sfd;
365
366 struct route *route = &world.routes.routes[closest];
367
368 u32 id = route->track_id;
369
370 if( id != 0xffffffff )
371 {
372 struct netmsg_board *local_board = &scoreboard_client_data.boards[id];
373
374 for( int i=0; i<13; i++ )
375 {
376 sfd_encode( &sfd->tester, i, &local_board->data[27*i] );
377 }
378 }
379 }
380
381 static int in_zone = 0;
382
383 int in_zone_this_time = 0;
384
385 for( int i=0; i<world.achievement_zones_count; i++ )
386 {
387 struct achievement_zone *zone = &world.achievement_zones[i];
388
389 v3f local;
390 m4x3_mulv( zone->inv_transform, pos, local );
391
392 if( (fabsf(local[0]) <= 1.0f) &&
393 (fabsf(local[1]) <= 1.0f) &&
394 (fabsf(local[2]) <= 1.0f) )
395 {
396 in_zone_this_time = 1;
397
398 if( !in_zone && zone->ptarget )
399 {
400 audio_lock();
401 audio_player_playclip( &zone->ptarget->player,
402 &zone->ptarget->temp_embedded_clip );
403 audio_unlock();
404 }
405
406 if( !zone->triggered )
407 {
408 steam_set_achievement( zone->name );
409 steam_store_achievements();
410 }
411
412 zone->triggered = 1;
413 }
414
415 vg_line_boxf_transformed( zone->transform, (boxf){{-1.0f,-1.0f,-1.0f},
416 { 1.0f, 1.0f, 1.0f}},
417 0xff00ff00 );
418 }
419
420 in_zone = in_zone_this_time;
421
422 sfd_update( &world.sfd.tester );
423 }
424
425 /*
426 * -----------------------------------------------------------------------------
427 * API implementation
428 * -----------------------------------------------------------------------------
429 */
430
431 static void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
432 {
433 for( int i=0; i<3; i++ )
434 v3_copy( world.geo.verts[ hit->tri[i] ].co, tri[i] );
435 }
436
437 static int ray_world( v3f pos, v3f dir, ray_hit *hit )
438 {
439 return scene_raycast( &world.geo, pos, dir, hit );
440 }
441
442 static int ray_hit_is_terrain( ray_hit *hit )
443 {
444 u32 valid_start = 0,
445 valid_end = world.sm_terrain.vertex_count;
446
447 return (hit->tri[0] >= valid_start) &&
448 (hit->tri[0] < valid_end);
449 }
450
451 static int ray_hit_is_ramp( ray_hit *hit )
452 {
453 u32 valid_start = world.sm_geo_std.vertex_start,
454 valid_end = world.sm_geo_vb.vertex_start;
455
456 return (hit->tri[0] >= valid_start) &&
457 (hit->tri[0] < valid_end);
458 }
459
460 #endif /* WORLD_H */