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