c5c2fc747a3a77ebbb61bd85b53af7dff26d3f4f
[carveJwlIkooP6JGAAIwe30JlM.git] / world_entity.c
1 #ifndef WORLD_ENTITY_C
2 #define WORLD_ENTITY_C
3
4 #include "model.h"
5 #include "entity.h"
6 #include "world.h"
7 #include "world_load.h"
8 #include "save.h"
9 #include "vg/vg_msg.h"
10 #include "menu.h"
11 #include "ent_challenge.h"
12 #include "ent_skateshop.h"
13 #include "ent_route.h"
14
15 static void world_entity_focus( u32 entity_id ){
16 localplayer.immobile = 1;
17 menu.disable_open = 1;
18
19 v3_zero( localplayer.rb.v );
20 v3_zero( localplayer.rb.w );
21 player_walk.move_speed = 0.0f;
22 world_static.focused_entity = entity_id;
23 skaterift.activity = k_skaterift_ent_focus;
24 }
25
26 static void world_entity_unfocus(void){
27 localplayer.immobile = 0;
28 skaterift.activity = k_skaterift_default;
29 menu.disable_open = 0;
30 srinput.state = k_input_state_resume;
31 }
32
33 static void world_entity_focus_camera( world_instance *world, u32 uid ){
34 if( mdl_entity_id_type( uid ) == k_ent_camera ){
35 u32 index = mdl_entity_id_id( uid );
36 ent_camera *cam = mdl_arritm( &world->ent_camera, index );
37
38 v3f dir = {0.0f,-1.0f,0.0f};
39 mdl_transform_vector( &cam->transform, dir, dir );
40 v3_angles( dir, world_static.focus_cam.angles );
41 v3_copy( cam->transform.co, world_static.focus_cam.pos );
42 world_static.focus_cam.fov = cam->fov;
43 }
44 else {
45 camera_copy( &localplayer.cam, &world_static.focus_cam );
46
47 /* TODO ? */
48 world_static.focus_cam.nearz = localplayer.cam.nearz;
49 world_static.focus_cam.farz = localplayer.cam.farz;
50 }
51 }
52
53 /* logic preupdate */
54 static void world_entity_focus_preupdate(void){
55 f32 rate = vg_minf( 1.0f, vg.time_frame_delta * 2.0f );
56 int active = 0;
57 if( skaterift.activity == k_skaterift_ent_focus )
58 active = 1;
59
60 vg_slewf( &world_static.focus_strength, active,
61 vg.time_frame_delta * (1.0f/0.5f) );
62
63 u32 type = mdl_entity_id_type( world_static.focused_entity ),
64 index = mdl_entity_id_id( world_static.focused_entity );
65 world_instance *world = world_current_instance();
66
67 /* TODO: Table. */
68 if( type == k_ent_skateshop ){
69 ent_skateshop *skateshop = mdl_arritm( &world->ent_skateshop, index );
70 ent_skateshop_preupdate( skateshop, active );
71 }
72 else if( type == k_ent_challenge ){
73 ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
74 ent_challenge_preupdate( challenge, active );
75 }
76 else if( type == k_ent_route ){
77 ent_route *route = mdl_arritm( &world->ent_route, index );
78 ent_route_preupdate( route, active );
79 }
80 }
81
82 /* additional renderings like text etc.. */
83 static void world_entity_focus_render(void){
84 if( skaterift.activity != k_skaterift_ent_focus )
85 return;
86
87 u32 type = mdl_entity_id_type( world_static.focused_entity ),
88 index = mdl_entity_id_id( world_static.focused_entity );
89 world_instance *world = world_current_instance();
90
91 if( type == k_ent_skateshop ){
92 ent_skateshop *skateshop = mdl_arritm( &world->ent_skateshop, index );
93 skateshop_render( skateshop );
94 }
95 else if( type == k_ent_challenge ){}
96 else if( type == k_ent_route ){}
97 else if( type == k_ent_miniworld ){}
98 else {
99 vg_fatal_error( "Programming error\n" );
100 }
101 }
102
103 static void world_gen_entities_init( world_instance *world ){
104 /* lights */
105 for( u32 j=0; j<mdl_arrcount(&world->ent_light); j ++ ){
106 ent_light *light = mdl_arritm( &world->ent_light, j );
107
108 m4x3f to_world;
109 q_m3x3( light->transform.q, to_world );
110 v3_copy( light->transform.co, to_world[3] );
111 m4x3_invert_affine( to_world, light->inverse_world );
112
113 light->angle_sin_cos[0] = sinf( light->angle * 0.5f );
114 light->angle_sin_cos[1] = cosf( light->angle * 0.5f );
115 }
116
117 /* gates */
118 for( u32 j=0; j<mdl_arrcount(&world->ent_gate); j ++ ){
119 ent_gate *gate = mdl_arritm( &world->ent_gate, j );
120
121 if( !(gate->flags & k_ent_gate_nonlocal_DELETED) ) {
122 gate_transform_update( gate );
123 }
124 }
125
126 /* water */
127 for( u32 j=0; j<mdl_arrcount(&world->ent_water); j++ ){
128 ent_water *water = mdl_arritm( &world->ent_water, j );
129 if( world->water.enabled ){
130 vg_warn( "Multiple water surfaces in level!\n" );
131 break;
132 }
133
134 world->water.enabled = 1;
135 water_set_surface( world, water->transform.co[1] );
136 }
137
138 /* volumes */
139 for( u32 j=0; j<mdl_arrcount(&world->ent_volume); j++ ){
140 ent_volume *volume = mdl_arritm( &world->ent_volume, j );
141 mdl_transform_m4x3( &volume->transform, volume->to_world );
142 m4x3_invert_full( volume->to_world, volume->to_local );
143 }
144
145 /* audio packs */
146 for( u32 j=0; j<mdl_arrcount(&world->ent_audio); j++ ){
147 ent_audio *audio = mdl_arritm( &world->ent_audio, j );
148
149 for( u32 k=0; k<audio->clip_count; k++ ){
150 ent_audio_clip *clip = mdl_arritm( &world->ent_audio_clip,
151 audio->clip_start+k );
152
153 if( clip->_.file.pack_size ){
154 u32 size = clip->_.file.pack_size,
155 offset = clip->_.file.pack_offset;
156
157 /* embedded files are fine to clear the scratch buffer, only
158 * external audio uses it */
159
160 vg_linear_clear( vg_mem.scratch );
161 void *data = vg_linear_alloc( vg_mem.scratch,
162 clip->_.file.pack_size );
163
164 mdl_fread_pack_file( &world->meta, &clip->_.file, data );
165
166 clip->_.clip.path = NULL;
167 clip->_.clip.flags = audio->flags;
168 clip->_.clip.data = data;
169 clip->_.clip.size = size;
170 }
171 else{
172 clip->_.clip.path = mdl_pstr(&world->meta,clip->_.file.pstr_path);
173 clip->_.clip.flags = audio->flags;
174 clip->_.clip.data = NULL;
175 clip->_.clip.size = 0;
176 }
177
178 audio_clip_load( &clip->_.clip, world->heap );
179 }
180 }
181
182 /* create generic entity hierachy for those who need it */
183 u32 indexed_count = 0;
184 struct {
185 u32 type;
186 mdl_array_ptr *array;
187 }
188 indexables[] = {
189 { k_ent_gate, &world->ent_gate },
190 { k_ent_objective, &world->ent_objective },
191 { k_ent_volume, &world->ent_volume },
192 { k_ent_challenge, &world->ent_challenge }
193 };
194
195 for( u32 i=0; i<vg_list_size(indexables); i++ )
196 indexed_count += mdl_arrcount( indexables[i].array );
197 vg_info( "indexing %u entities\n", indexed_count );
198
199 world->entity_list = vg_linear_alloc( world->heap,
200 vg_align8(indexed_count*sizeof(u32)));
201
202 u32 index=0;
203 for( u32 i=0; i<vg_list_size(indexables); i++ ){
204 u32 type = indexables[i].type,
205 count = mdl_arrcount( indexables[i].array );
206
207 for( u32 j=0; j<count; j ++ )
208 world->entity_list[index ++] = mdl_entity_id( type, j );
209 }
210
211 world->entity_bh = bh_create( world->heap, &bh_system_entity_list, world,
212 indexed_count, 2 );
213 }
214
215 static
216 ent_spawn *world_find_closest_spawn( world_instance *world, v3f position )
217 {
218 ent_spawn *rp = NULL, *r;
219 float min_dist = INFINITY;
220
221 for( u32 i=0; i<mdl_arrcount(&world->ent_spawn); i++ ){
222 r = mdl_arritm( &world->ent_spawn, i );
223 float d = v3_dist2( r->transform.co, position );
224
225 if( d < min_dist ){
226 min_dist = d;
227 rp = r;
228 }
229 }
230
231 if( !rp ){
232 if( mdl_arrcount(&world->ent_spawn) ){
233 vg_warn( "Invalid distances to spawns.. defaulting to first one.\n" );
234 return mdl_arritm( &world->ent_spawn, 0 );
235 }
236 else{
237 vg_error( "There are no spawns in the level!\n" );
238 }
239 }
240
241 return rp;
242 }
243
244 static
245 ent_spawn *world_find_spawn_by_name( world_instance *world, const char *name )
246 {
247 ent_spawn *rp = NULL, *r;
248 for( u32 i=0; i<mdl_arrcount(&world->ent_spawn); i++ ){
249 r = mdl_arritm( &world->ent_spawn, i );
250 if( !strcmp( mdl_pstr(&world->meta, r->pstr_name), name ) ){
251 rp = r;
252 break;
253 }
254 }
255
256 if( !rp )
257 vg_warn( "No spawn named '%s'\n", name );
258
259 return rp;
260 }
261
262 static void ent_volume_call( world_instance *world, ent_call *call )
263 {
264 u32 index = mdl_entity_id_id( call->id );
265 ent_volume *volume = mdl_arritm( &world->ent_volume, index );
266 if( !volume->target ) return;
267
268 if( call->function == k_ent_function_trigger ){
269 call->id = volume->target;
270
271 if( volume->flags & k_ent_volume_flag_particles ){
272 float *co = alloca( sizeof(float)*3 );
273 co[0] = vg_randf64()*2.0f-1.0f;
274 co[1] = vg_randf64()*2.0f-1.0f;
275 co[2] = vg_randf64()*2.0f-1.0f;
276 m4x3_mulv( volume->to_world, co, co );
277
278 call->function = k_ent_function_particle_spawn;
279 call->data = co;
280 entity_call( world, call );
281 }
282 else{
283 call->function = volume->trigger.event;
284 entity_call( world, call );
285 }
286 }
287 else if( call->function == k_ent_function_trigger_leave ){
288 call->id = volume->target;
289
290 if( volume->flags & k_ent_volume_flag_particles ){
291 assert(0);
292 }
293 else{
294 call->function = volume->trigger.event_leave;
295 entity_call( world, call );
296 }
297 }
298 }
299
300 static void ent_audio_call( world_instance *world, ent_call *call ){
301 if( world->status == k_world_status_unloading ){
302 vg_warn( "cannot modify audio while unloading world\n" );
303 return;
304 }
305
306 u8 world_id = (world - world_static.instances) + 1;
307 u32 index = mdl_entity_id_id( call->id );
308 ent_audio *audio = mdl_arritm( &world->ent_audio, index );
309
310 v3f sound_co;
311
312 if( call->function == k_ent_function_particle_spawn ){
313 v3_copy( call->data, sound_co );
314 }
315 else if( call->function == k_ent_function_trigger ){
316 v3_copy( audio->transform.co, sound_co );
317 }
318 else
319 vg_fatal_error( "ent_audio_call (invalid function id)" );
320
321 float chance = vg_randf64()*100.0f,
322 bar = 0.0f;
323
324 for( u32 i=0; i<audio->clip_count; i++ ){
325 ent_audio_clip *clip = mdl_arritm( &world->ent_audio_clip,
326 audio->clip_start+i );
327
328 float mod = world->probabilities[ audio->probability_curve ],
329 p = clip->probability * mod;
330
331 bar += p;
332 if( chance < bar ){
333 audio_lock();
334
335 if( audio->behaviour == k_channel_behaviour_unlimited ){
336 audio_oneshot_3d( &clip->_.clip, sound_co,
337 audio->transform.s[0],
338 audio->volume );
339 }
340 else if( audio->behaviour == k_channel_behaviour_discard_if_full ){
341 audio_channel *ch =
342 audio_get_group_idle_channel( audio->group,
343 audio->max_channels );
344
345 if( ch ){
346 audio_channel_init( ch, &clip->_.clip, audio->flags );
347 audio_channel_group( ch, audio->group );
348 audio_channel_world( ch, world_id );
349 audio_channel_set_spacial( ch, sound_co, audio->transform.s[0] );
350 audio_channel_edit_volume( ch, audio->volume, 1 );
351 ch = audio_relinquish_channel( ch );
352 }
353 }
354 else if( audio->behaviour == k_channel_behaviour_crossfade_if_full){
355 audio_channel *ch =
356 audio_get_group_idle_channel( audio->group,
357 audio->max_channels );
358
359 /* group is full */
360 if( !ch ){
361 audio_channel *existing =
362 audio_get_group_first_active_channel( audio->group );
363
364 if( existing ){
365 if( existing->source == &clip->_.clip ){
366 audio_unlock();
367 return;
368 }
369
370 existing->group = 0;
371 existing = audio_channel_fadeout(existing, audio->crossfade);
372 }
373
374 ch = audio_get_first_idle_channel();
375 }
376
377 if( ch ){
378 audio_channel_init( ch, &clip->_.clip, audio->flags );
379 audio_channel_group( ch, audio->group );
380 audio_channel_world( ch, world_id );
381 audio_channel_fadein( ch, audio->crossfade );
382 ch = audio_relinquish_channel( ch );
383 }
384 }
385
386 audio_unlock();
387 return;
388 }
389 }
390 }
391
392
393 static void ent_ccmd_call( world_instance *world, ent_call *call ){
394 if( call->function == k_ent_function_trigger ){
395 u32 index = mdl_entity_id_id( call->id );
396 ent_ccmd *ccmd = mdl_arritm( &world->ent_ccmd, index );
397 vg_execute_console_input( mdl_pstr(&world->meta, ccmd->pstr_command) );
398 }
399 }
400
401 /*
402 * BVH implementation
403 * ----------------------------------------------------------------------------
404 */
405
406 static void
407 entity_bh_expand_bound( void *user, boxf bound, u32 item_index ){
408 world_instance *world = user;
409
410 u32 id = world->entity_list[ item_index ],
411 type = mdl_entity_id_type( id ),
412 index = mdl_entity_id_id( id );
413
414 if( type == k_ent_gate ){
415 ent_gate *gate = mdl_arritm( &world->ent_gate, index );
416 boxf box = {{ -gate->dimensions[0], -gate->dimensions[1], -0.1f },
417 { gate->dimensions[0], gate->dimensions[1], 0.1f }};
418
419 m4x3_expand_aabb_aabb( gate->to_world, bound, box );
420 }
421 else if( type == k_ent_objective ){
422 ent_objective *objective = mdl_arritm( &world->ent_objective, index );
423
424 /* TODO: This might be more work than necessary. could maybe just get
425 * away with representing them as points */
426
427 boxf box;
428 box_init_inf( box );
429
430 for( u32 i=0; i<objective->submesh_count; i++ ){
431 mdl_submesh *sm = mdl_arritm( &world->meta.submeshs,
432 objective->submesh_start+i );
433 box_concat( box, sm->bbx );
434 }
435
436 m4x3f transform;
437 mdl_transform_m4x3( &objective->transform, transform );
438 m4x3_expand_aabb_aabb( transform, bound, box );
439 }
440 else if( type == k_ent_volume ){
441 ent_volume *volume = mdl_arritm( &world->ent_volume, index );
442 m4x3_expand_aabb_aabb( volume->to_world, bound,
443 (boxf){{-1.0f,-1.0f,-1.0f},{ 1.0f, 1.0f, 1.0f}} );
444 }
445 else if( type == k_ent_challenge ){
446 ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
447
448 boxf box = {{-1.2f*0.5f,-0.72f*0.5f,-0.01f*0.5f},
449 { 1.2f*0.5f, 0.72f*0.5f, 0.01f*0.5f}};
450 m4x3f transform;
451 mdl_transform_m4x3( &challenge->transform, transform );
452 m4x3_expand_aabb_aabb( transform, bound, box );
453 }
454 else{
455 vg_fatal_error( "Programming error\n" );
456 }
457 }
458
459 static float entity_bh_centroid( void *user, u32 item_index, int axis ){
460 world_instance *world = user;
461
462 u32 id = world->entity_list[ item_index ],
463 type = mdl_entity_id_type( id ),
464 index = mdl_entity_id_id( id );
465
466 if( type == k_ent_gate ){
467 ent_gate *gate = mdl_arritm( &world->ent_gate, index );
468 return gate->to_world[3][axis];
469 }
470 else if( type == k_ent_objective ){
471 ent_objective *objective = mdl_arritm( &world->ent_objective, index );
472 return objective->transform.co[axis];
473 }
474 else if( type == k_ent_volume ){
475 ent_volume *volume = mdl_arritm( &world->ent_volume, index );
476 return volume->transform.co[axis];
477 }
478 else if( type == k_ent_challenge ){
479 ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
480 return challenge->transform.co[axis];
481 }
482 else {
483 vg_fatal_error( "Programming error\n" );
484 return INFINITY;
485 }
486 }
487
488 static void entity_bh_swap( void *user, u32 ia, u32 ib ){
489 world_instance *world = user;
490
491 u32 a = world->entity_list[ ia ],
492 b = world->entity_list[ ib ];
493
494 world->entity_list[ ia ] = b;
495 world->entity_list[ ib ] = a;
496 }
497
498 static void entity_bh_debug( void *user, u32 item_index ){
499 world_instance *world = user;
500
501 u32 id = world->entity_list[ item_index ],
502 type = mdl_entity_id_type( id ),
503 index = mdl_entity_id_id( id );
504
505 if( type == k_ent_gate ){
506 ent_gate *gate = mdl_arritm( &world->ent_gate, index );
507 boxf box = {{ -gate->dimensions[0], -gate->dimensions[1], -0.1f },
508 { gate->dimensions[0], gate->dimensions[1], 0.1f }};
509 vg_line_boxf_transformed( gate->to_world, box, 0xf000ff00 );
510 }
511 else if( type == k_ent_objective ){
512 ent_objective *objective = mdl_arritm( &world->ent_objective, index );
513 boxf box;
514 box_init_inf( box );
515
516 for( u32 i=0; i<objective->submesh_count; i++ ){
517 mdl_submesh *sm = mdl_arritm( &world->meta.submeshs,
518 objective->submesh_start+i );
519 box_concat( box, sm->bbx );
520 }
521
522 m4x3f transform;
523 mdl_transform_m4x3( &objective->transform, transform );
524 vg_line_boxf_transformed( transform, box, 0xf000ff00 );
525 }
526 else if( type == k_ent_volume ){
527 ent_volume *volume = mdl_arritm( &world->ent_volume, index );
528 vg_line_boxf_transformed( volume->to_world,
529 (boxf){{-1.0f,-1.0f,-1.0f},{ 1.0f, 1.0f, 1.0f}},
530 0xf000ff00 );
531 }
532 else if( type == k_ent_challenge ){
533 ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
534
535 boxf box = {{-1.2f*0.5f,-0.72f*0.5f,-0.01f*0.5f},
536 { 1.2f*0.5f, 0.72f*0.5f, 0.01f*0.5f}};
537 m4x3f transform;
538 mdl_transform_m4x3( &challenge->transform, transform );
539 vg_line_boxf_transformed( transform, box, 0xf0ff0000 );
540 }
541 else{
542 vg_fatal_error( "Programming error\n" );
543 }
544 }
545
546 static void entity_bh_closest( void *user, u32 item_index, v3f point,
547 v3f closest ){
548 world_instance *world = user;
549
550 u32 id = world->entity_list[ item_index ],
551 type = mdl_entity_id_type( id ),
552 index = mdl_entity_id_id( id );
553
554 if( type == k_ent_gate ){
555 ent_gate *gate = mdl_arritm( &world->ent_gate, index );
556 v3_copy( gate->to_world[3], closest );
557 }
558 else if( type == k_ent_objective ){
559 ent_objective *challenge = mdl_arritm( &world->ent_objective, index );
560 v3_copy( challenge->transform.co, closest );
561 }
562 else if( type == k_ent_volume ){
563 ent_volume *volume = mdl_arritm( &world->ent_volume, index );
564 v3_copy( volume->to_world[3], closest );
565 }
566 else if( type == k_ent_challenge ){
567 ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
568 v3_copy( challenge->transform.co, closest );
569 }
570 else{
571 vg_fatal_error( "Programming error\n" );
572 }
573 }
574
575 static void world_entity_start( world_instance *world, vg_msg *sav ){
576 vg_info( "Start instance %p\n", world );
577
578 world->probabilities[ k_probability_curve_constant ] = 1.0f;
579 for( u32 i=0; i<mdl_arrcount(&world->ent_audio); i++ ){
580 ent_audio *audio = mdl_arritm(&world->ent_audio,i);
581 if( audio->flags & AUDIO_FLAG_AUTO_START ){
582 ent_call call;
583 call.data = NULL;
584 call.function = k_ent_function_trigger;
585 call.id = mdl_entity_id( k_ent_audio, i );
586 entity_call( world, &call );
587 }
588 }
589
590 /* read savedata
591 * ----------------------------------------------------------------------- */
592
593 for( u32 i=0; i<mdl_arrcount(&world->ent_challenge); i++ ){
594 ent_challenge *challenge = mdl_arritm( &world->ent_challenge, i );
595 const char *alias = mdl_pstr( &world->meta, challenge->pstr_alias );
596
597 if( vg_msg_getkvu32( sav, alias, 0 ) ){
598 ent_call call;
599 call.data = NULL;
600 call.function = 0;
601 call.id = mdl_entity_id( k_ent_challenge, i );
602 entity_call( world, &call );
603 }
604 }
605 }
606
607 #if 0
608 /*
609 * used for relinking multi-world data. ran anytime the world setup changes
610 */
611 static void world_entity_relink( world_instance *world ){
612 vg_info( "entity_relink(%d)\n", world - world_static.instances );
613 for( u32 i=0; i<mdl_arrcount(&world->ent_miniworld); i++ ){
614 ent_miniworld *miniworld = mdl_arritm( &world->ent_miniworld, i );
615 miniworld->purpose = k_world_purpose_invalid;
616
617 const char *uid = mdl_pstr( &world->meta, miniworld->pstr_world );
618 addon_alias q;
619 addon_uid_to_alias( uid, &q );
620
621 u32 addon_id = addon_match( &q );
622 if( addon_id != 0xffffffff ){
623 addon_reg *reg = get_addon_from_index( k_addon_type_world, addon_id );
624
625 for( int j=0; j<k_world_max; j ++ ){
626 world_instance *other = &world_static.instances[j];
627 if( other == world ) continue;
628 if( (other->status == k_world_status_loaded) &&
629 (world_static.instance_addons[j] == reg) ){
630 miniworld->purpose = j;
631 break;
632 }
633 }
634 }
635 }
636 }
637 #endif
638
639 static void world_entity_serialize( world_instance *world, vg_msg *sav ){
640 for( u32 i=0; i<mdl_arrcount(&world->ent_challenge); i++ ){
641 ent_challenge *challenge = mdl_arritm(&world->ent_challenge,i);
642
643 const char *alias = mdl_pstr(&world->meta,challenge->pstr_alias);
644 vg_msg_wkvu32( sav, alias, challenge->status );
645 }
646 }
647
648 #endif /* WORLD_ENTITY_C */