code is no longer based :(
[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 }
97 else if( type == k_ent_route ){
98 }
99 else {
100 vg_fatal_error( "Programming error\n" );
101 }
102 }
103
104 static void world_gen_entities_init( world_instance *world ){
105 /* lights */
106 for( u32 j=0; j<mdl_arrcount(&world->ent_light); j ++ ){
107 ent_light *light = mdl_arritm( &world->ent_light, j );
108
109 m4x3f to_world;
110 q_m3x3( light->transform.q, to_world );
111 v3_copy( light->transform.co, to_world[3] );
112 m4x3_invert_affine( to_world, light->inverse_world );
113
114 light->angle_sin_cos[0] = sinf( light->angle * 0.5f );
115 light->angle_sin_cos[1] = cosf( light->angle * 0.5f );
116 }
117
118 /* gates */
119 for( u32 j=0; j<mdl_arrcount(&world->ent_gate); j ++ ){
120 ent_gate *gate = mdl_arritm( &world->ent_gate, j );
121
122 if( !(gate->flags & k_ent_gate_nonlocal_DELETED) ) {
123 gate_transform_update( gate );
124 }
125 }
126
127 /* water */
128 for( u32 j=0; j<mdl_arrcount(&world->ent_water); j++ ){
129 ent_water *water = mdl_arritm( &world->ent_water, j );
130 if( world->water.enabled ){
131 vg_warn( "Multiple water surfaces in level!\n" );
132 break;
133 }
134
135 world->water.enabled = 1;
136 water_set_surface( world, water->transform.co[1] );
137 }
138
139 /* volumes */
140 for( u32 j=0; j<mdl_arrcount(&world->ent_volume); j++ ){
141 ent_volume *volume = mdl_arritm( &world->ent_volume, j );
142 mdl_transform_m4x3( &volume->transform, volume->to_world );
143 m4x3_invert_full( volume->to_world, volume->to_local );
144 }
145
146 /* audio packs */
147 for( u32 j=0; j<mdl_arrcount(&world->ent_audio); j++ ){
148 ent_audio *audio = mdl_arritm( &world->ent_audio, j );
149
150 for( u32 k=0; k<audio->clip_count; k++ ){
151 ent_audio_clip *clip = mdl_arritm( &world->ent_audio_clip,
152 audio->clip_start+k );
153
154 if( clip->_.file.pack_size ){
155 u32 size = clip->_.file.pack_size,
156 offset = clip->_.file.pack_offset;
157
158 /* embedded files are fine to clear the scratch buffer, only
159 * external audio uses it */
160
161 vg_linear_clear( vg_mem.scratch );
162 void *data = vg_linear_alloc( vg_mem.scratch,
163 clip->_.file.pack_size );
164
165 mdl_fread_pack_file( &world->meta, &clip->_.file, data );
166
167 clip->_.clip.path = NULL;
168 clip->_.clip.flags = audio->flags;
169 clip->_.clip.data = data;
170 clip->_.clip.size = size;
171 }
172 else{
173 clip->_.clip.path = mdl_pstr(&world->meta,clip->_.file.pstr_path);
174 clip->_.clip.flags = audio->flags;
175 clip->_.clip.data = NULL;
176 clip->_.clip.size = 0;
177 }
178
179 audio_clip_load( &clip->_.clip, world->heap );
180 }
181 }
182
183 /* create generic entity hierachy for those who need it */
184 u32 indexed_count = 0;
185 struct {
186 u32 type;
187 mdl_array_ptr *array;
188 }
189 indexables[] = {
190 { k_ent_gate, &world->ent_gate },
191 { k_ent_objective, &world->ent_objective },
192 { k_ent_volume, &world->ent_volume },
193 { k_ent_challenge, &world->ent_challenge }
194 };
195
196 for( u32 i=0; i<vg_list_size(indexables); i++ )
197 indexed_count += mdl_arrcount( indexables[i].array );
198 vg_info( "indexing %u entities\n", indexed_count );
199
200 world->entity_list = vg_linear_alloc( world->heap,
201 vg_align8(indexed_count*sizeof(u32)));
202
203 u32 index=0;
204 for( u32 i=0; i<vg_list_size(indexables); i++ ){
205 u32 type = indexables[i].type,
206 count = mdl_arrcount( indexables[i].array );
207
208 for( u32 j=0; j<count; j ++ )
209 world->entity_list[index ++] = mdl_entity_id( type, j );
210 }
211
212 world->entity_bh = bh_create( world->heap, &bh_system_entity_list, world,
213 indexed_count, 2 );
214 }
215
216 static
217 ent_spawn *world_find_closest_spawn( world_instance *world, v3f position )
218 {
219 ent_spawn *rp = NULL, *r;
220 float min_dist = INFINITY;
221
222 for( u32 i=0; i<mdl_arrcount(&world->ent_spawn); i++ ){
223 r = mdl_arritm( &world->ent_spawn, i );
224 float d = v3_dist2( r->transform.co, position );
225
226 if( d < min_dist ){
227 min_dist = d;
228 rp = r;
229 }
230 }
231
232 if( !rp ){
233 if( mdl_arrcount(&world->ent_spawn) ){
234 vg_warn( "Invalid distances to spawns.. defaulting to first one.\n" );
235 return mdl_arritm( &world->ent_spawn, 0 );
236 }
237 else{
238 vg_error( "There are no spawns in the level!\n" );
239 }
240 }
241
242 return rp;
243 }
244
245 static
246 ent_spawn *world_find_spawn_by_name( world_instance *world, const char *name )
247 {
248 ent_spawn *rp = NULL, *r;
249 for( u32 i=0; i<mdl_arrcount(&world->ent_spawn); i++ ){
250 r = mdl_arritm( &world->ent_spawn, i );
251 if( !strcmp( mdl_pstr(&world->meta, r->pstr_name), name ) ){
252 rp = r;
253 break;
254 }
255 }
256
257 if( !rp )
258 vg_warn( "No spawn named '%s'\n", name );
259
260 return rp;
261 }
262
263 static void ent_volume_call( world_instance *world, ent_call *call )
264 {
265 u32 index = mdl_entity_id_id( call->id );
266 ent_volume *volume = mdl_arritm( &world->ent_volume, index );
267 if( !volume->target ) return;
268
269 if( call->function == k_ent_function_trigger ){
270 call->id = volume->target;
271
272 if( volume->flags & k_ent_volume_flag_particles ){
273 float *co = alloca( sizeof(float)*3 );
274 co[0] = vg_randf64()*2.0f-1.0f;
275 co[1] = vg_randf64()*2.0f-1.0f;
276 co[2] = vg_randf64()*2.0f-1.0f;
277 m4x3_mulv( volume->to_world, co, co );
278
279 call->function = k_ent_function_particle_spawn;
280 call->data = co;
281 entity_call( world, call );
282 }
283 else{
284 call->function = volume->trigger.event;
285 entity_call( world, call );
286 }
287 }
288 else if( call->function == k_ent_function_trigger_leave ){
289 call->id = volume->target;
290
291 if( volume->flags & k_ent_volume_flag_particles ){
292 assert(0);
293 }
294 else{
295 call->function = volume->trigger.event_leave;
296 entity_call( world, call );
297 }
298 }
299 }
300
301 static void ent_audio_call( world_instance *world, ent_call *call ){
302 if( world->status == k_world_status_unloading ){
303 vg_warn( "cannot modify audio while unloading world\n" );
304 return;
305 }
306
307 u8 world_id = (world - world_static.instances) + 1;
308 u32 index = mdl_entity_id_id( call->id );
309 ent_audio *audio = mdl_arritm( &world->ent_audio, index );
310
311 v3f sound_co;
312
313 if( call->function == k_ent_function_particle_spawn ){
314 v3_copy( call->data, sound_co );
315 }
316 else if( call->function == k_ent_function_trigger ){
317 v3_copy( audio->transform.co, sound_co );
318 }
319 else
320 vg_fatal_error( "ent_audio_call (invalid function id)" );
321
322 float chance = vg_randf64()*100.0f,
323 bar = 0.0f;
324
325 for( u32 i=0; i<audio->clip_count; i++ ){
326 ent_audio_clip *clip = mdl_arritm( &world->ent_audio_clip,
327 audio->clip_start+i );
328
329 float mod = world->probabilities[ audio->probability_curve ],
330 p = clip->probability * mod;
331
332 bar += p;
333 if( chance < bar ){
334 audio_lock();
335
336 if( audio->behaviour == k_channel_behaviour_unlimited ){
337 audio_oneshot_3d( &clip->_.clip, sound_co,
338 audio->transform.s[0],
339 audio->volume );
340 }
341 else if( audio->behaviour == k_channel_behaviour_discard_if_full ){
342 audio_channel *ch =
343 audio_get_group_idle_channel( audio->group,
344 audio->max_channels );
345
346 if( ch ){
347 audio_channel_init( ch, &clip->_.clip, audio->flags );
348 audio_channel_group( ch, audio->group );
349 audio_channel_world( ch, world_id );
350 audio_channel_set_spacial( ch, sound_co, audio->transform.s[0] );
351 audio_channel_edit_volume( ch, audio->volume, 1 );
352 ch = audio_relinquish_channel( ch );
353 }
354 }
355 else if( audio->behaviour == k_channel_behaviour_crossfade_if_full){
356 audio_channel *ch =
357 audio_get_group_idle_channel( audio->group,
358 audio->max_channels );
359
360 /* group is full */
361 if( !ch ){
362 audio_channel *existing =
363 audio_get_group_first_active_channel( audio->group );
364
365 if( existing ){
366 if( existing->source == &clip->_.clip ){
367 audio_unlock();
368 return;
369 }
370
371 existing->group = 0;
372 existing = audio_channel_fadeout(existing, audio->crossfade);
373 }
374
375 ch = audio_get_first_idle_channel();
376 }
377
378 if( ch ){
379 audio_channel_init( ch, &clip->_.clip, audio->flags );
380 audio_channel_group( ch, audio->group );
381 audio_channel_world( ch, world_id );
382 audio_channel_fadein( ch, audio->crossfade );
383 ch = audio_relinquish_channel( ch );
384 }
385 }
386
387 audio_unlock();
388 return;
389 }
390 }
391 }
392
393
394 static void ent_ccmd_call( world_instance *world, ent_call *call ){
395 if( call->function == k_ent_function_trigger ){
396 u32 index = mdl_entity_id_id( call->id );
397 ent_ccmd *ccmd = mdl_arritm( &world->ent_ccmd, index );
398 vg_execute_console_input( mdl_pstr(&world->meta, ccmd->pstr_command) );
399 }
400 }
401
402 /*
403 * BVH implementation
404 * ----------------------------------------------------------------------------
405 */
406
407 static void
408 entity_bh_expand_bound( void *user, boxf bound, u32 item_index ){
409 world_instance *world = user;
410
411 u32 id = world->entity_list[ item_index ],
412 type = mdl_entity_id_type( id ),
413 index = mdl_entity_id_id( id );
414
415 if( type == k_ent_gate ){
416 ent_gate *gate = mdl_arritm( &world->ent_gate, index );
417 boxf box = {{ -gate->dimensions[0], -gate->dimensions[1], -0.1f },
418 { gate->dimensions[0], gate->dimensions[1], 0.1f }};
419
420 m4x3_expand_aabb_aabb( gate->to_world, bound, box );
421 }
422 else if( type == k_ent_objective ){
423 ent_objective *objective = mdl_arritm( &world->ent_objective, index );
424
425 /* TODO: This might be more work than necessary. could maybe just get
426 * away with representing them as points */
427
428 boxf box;
429 box_init_inf( box );
430
431 for( u32 i=0; i<objective->submesh_count; i++ ){
432 mdl_submesh *sm = mdl_arritm( &world->meta.submeshs,
433 objective->submesh_start+i );
434 box_concat( box, sm->bbx );
435 }
436
437 m4x3f transform;
438 mdl_transform_m4x3( &objective->transform, transform );
439 m4x3_expand_aabb_aabb( transform, bound, box );
440 }
441 else if( type == k_ent_volume ){
442 ent_volume *volume = mdl_arritm( &world->ent_volume, index );
443 m4x3_expand_aabb_aabb( volume->to_world, bound,
444 (boxf){{-1.0f,-1.0f,-1.0f},{ 1.0f, 1.0f, 1.0f}} );
445 }
446 else if( type == k_ent_challenge ){
447 ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
448
449 boxf box = {{-1.2f*0.5f,-0.72f*0.5f,-0.01f*0.5f},
450 { 1.2f*0.5f, 0.72f*0.5f, 0.01f*0.5f}};
451 m4x3f transform;
452 mdl_transform_m4x3( &challenge->transform, transform );
453 m4x3_expand_aabb_aabb( transform, bound, box );
454 }
455 else{
456 vg_fatal_error( "Programming error\n" );
457 }
458 }
459
460 static float entity_bh_centroid( void *user, u32 item_index, int axis ){
461 world_instance *world = user;
462
463 u32 id = world->entity_list[ item_index ],
464 type = mdl_entity_id_type( id ),
465 index = mdl_entity_id_id( id );
466
467 if( type == k_ent_gate ){
468 ent_gate *gate = mdl_arritm( &world->ent_gate, index );
469 return gate->to_world[3][axis];
470 }
471 else if( type == k_ent_objective ){
472 ent_objective *objective = mdl_arritm( &world->ent_objective, index );
473 return objective->transform.co[axis];
474 }
475 else if( type == k_ent_volume ){
476 ent_volume *volume = mdl_arritm( &world->ent_volume, index );
477 return volume->transform.co[axis];
478 }
479 else if( type == k_ent_challenge ){
480 ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
481 return challenge->transform.co[axis];
482 }
483 else {
484 vg_fatal_error( "Programming error\n" );
485 return INFINITY;
486 }
487 }
488
489 static void entity_bh_swap( void *user, u32 ia, u32 ib ){
490 world_instance *world = user;
491
492 u32 a = world->entity_list[ ia ],
493 b = world->entity_list[ ib ];
494
495 world->entity_list[ ia ] = b;
496 world->entity_list[ ib ] = a;
497 }
498
499 static void entity_bh_debug( void *user, u32 item_index ){
500 world_instance *world = user;
501
502 u32 id = world->entity_list[ item_index ],
503 type = mdl_entity_id_type( id ),
504 index = mdl_entity_id_id( id );
505
506 if( type == k_ent_gate ){
507 ent_gate *gate = mdl_arritm( &world->ent_gate, index );
508 boxf box = {{ -gate->dimensions[0], -gate->dimensions[1], -0.1f },
509 { gate->dimensions[0], gate->dimensions[1], 0.1f }};
510 vg_line_boxf_transformed( gate->to_world, box, 0xf000ff00 );
511 }
512 else if( type == k_ent_objective ){
513 ent_objective *objective = mdl_arritm( &world->ent_objective, index );
514 boxf box;
515 box_init_inf( box );
516
517 for( u32 i=0; i<objective->submesh_count; i++ ){
518 mdl_submesh *sm = mdl_arritm( &world->meta.submeshs,
519 objective->submesh_start+i );
520 box_concat( box, sm->bbx );
521 }
522
523 m4x3f transform;
524 mdl_transform_m4x3( &objective->transform, transform );
525 vg_line_boxf_transformed( transform, box, 0xf000ff00 );
526 }
527 else if( type == k_ent_volume ){
528 ent_volume *volume = mdl_arritm( &world->ent_volume, index );
529 vg_line_boxf_transformed( volume->to_world,
530 (boxf){{-1.0f,-1.0f,-1.0f},{ 1.0f, 1.0f, 1.0f}},
531 0xf000ff00 );
532 }
533 else if( type == k_ent_challenge ){
534 ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
535
536 boxf box = {{-1.2f*0.5f,-0.72f*0.5f,-0.01f*0.5f},
537 { 1.2f*0.5f, 0.72f*0.5f, 0.01f*0.5f}};
538 m4x3f transform;
539 mdl_transform_m4x3( &challenge->transform, transform );
540 vg_line_boxf_transformed( transform, box, 0xf0ff0000 );
541 }
542 else{
543 vg_fatal_error( "Programming error\n" );
544 }
545 }
546
547 static void entity_bh_closest( void *user, u32 item_index, v3f point,
548 v3f closest ){
549 world_instance *world = user;
550
551 u32 id = world->entity_list[ item_index ],
552 type = mdl_entity_id_type( id ),
553 index = mdl_entity_id_id( id );
554
555 if( type == k_ent_gate ){
556 ent_gate *gate = mdl_arritm( &world->ent_gate, index );
557 v3_copy( gate->to_world[3], closest );
558 }
559 else if( type == k_ent_objective ){
560 ent_objective *challenge = mdl_arritm( &world->ent_objective, index );
561 v3_copy( challenge->transform.co, closest );
562 }
563 else if( type == k_ent_volume ){
564 ent_volume *volume = mdl_arritm( &world->ent_volume, index );
565 v3_copy( volume->to_world[3], closest );
566 }
567 else if( type == k_ent_challenge ){
568 ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
569 v3_copy( challenge->transform.co, closest );
570 }
571 else{
572 vg_fatal_error( "Programming error\n" );
573 }
574 }
575
576 static void world_entity_start( world_instance *world, vg_msg *sav ){
577 vg_info( "Start instance %p\n", world );
578
579 world->probabilities[ k_probability_curve_constant ] = 1.0f;
580 for( u32 i=0; i<mdl_arrcount(&world->ent_audio); i++ ){
581 ent_audio *audio = mdl_arritm(&world->ent_audio,i);
582 if( audio->flags & AUDIO_FLAG_AUTO_START ){
583 ent_call call;
584 call.data = NULL;
585 call.function = k_ent_function_trigger;
586 call.id = mdl_entity_id( k_ent_audio, i );
587 entity_call( world, &call );
588 }
589 }
590
591 /* read savedata
592 * ----------------------------------------------------------------------- */
593
594 for( u32 i=0; i<mdl_arrcount(&world->ent_challenge); i++ ){
595 ent_challenge *challenge = mdl_arritm( &world->ent_challenge, i );
596 const char *alias = mdl_pstr( &world->meta, challenge->pstr_alias );
597
598 if( vg_msg_getkvu32( sav, alias, 0 ) ){
599 ent_call call;
600 call.data = NULL;
601 call.function = 0;
602 call.id = mdl_entity_id( k_ent_challenge, i );
603 entity_call( world, &call );
604 }
605 }
606 }
607
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
638 static void world_entity_serialize( world_instance *world, vg_msg *sav ){
639 for( u32 i=0; i<mdl_arrcount(&world->ent_challenge); i++ ){
640 ent_challenge *challenge = mdl_arritm(&world->ent_challenge,i);
641
642 const char *alias = mdl_pstr(&world->meta,challenge->pstr_alias);
643 vg_msg_wkvu32( sav, alias, challenge->status );
644 }
645 }
646
647 #endif /* WORLD_ENTITY_C */