7 #include "world_load.h"
11 #include "ent_challenge.h"
12 #include "ent_skateshop.h"
14 VG_STATIC
void world_entity_focus( u32 entity_id
){
15 localplayer
.immobile
= 1;
16 menu
.disable_open
= 1;
18 v3_zero( localplayer
.rb
.v
);
19 v3_zero( localplayer
.rb
.w
);
20 localplayer
._walk
.move_speed
= 0.0f
;
21 world_static
.focused_entity
= entity_id
;
22 skaterift
.activity
= k_skaterift_ent_focus
;
25 VG_STATIC
void world_entity_unfocus(void){
26 localplayer
.immobile
= 0;
27 skaterift
.activity
= k_skaterift_default
;
28 menu
.disable_open
= 0;
33 VG_STATIC
void world_entity_focus_preupdate(void){
34 f32 rate
= vg_minf( 1.0f
, vg
.time_frame_delta
* 2.0f
);
36 if( skaterift
.activity
== k_skaterift_ent_focus
)
39 vg_slewf( &world_static
.focus_strength
, active
,
40 vg
.time_frame_delta
* (1.0f
/0.5f
) );
44 u32 type
= mdl_entity_id_type( world_static
.focused_entity
),
45 index
= mdl_entity_id_id( world_static
.focused_entity
);
46 world_instance
*world
= world_current_instance();
48 if( type
== k_ent_skateshop
){
49 ent_skateshop
*skateshop
= mdl_arritm( &world
->ent_skateshop
, index
);
50 ent_skateshop_preupdate( skateshop
);
52 else if( type
== k_ent_challenge
){
53 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
54 ent_challenge_preupdate( challenge
);
57 vg_fatal_error( "Programming error\n" );
61 /* additional renderings like text etc.. */
62 VG_STATIC
void world_entity_focus_render(void){
63 if( skaterift
.activity
!= k_skaterift_ent_focus
)
66 u32 type
= mdl_entity_id_type( world_static
.focused_entity
),
67 index
= mdl_entity_id_id( world_static
.focused_entity
);
68 world_instance
*world
= world_current_instance();
70 if( type
== k_ent_skateshop
){
71 ent_skateshop
*skateshop
= mdl_arritm( &world
->ent_skateshop
, index
);
72 skateshop_render( skateshop
);
74 else if( type
== k_ent_challenge
){
78 vg_fatal_error( "Programming error\n" );
82 VG_STATIC
void world_gen_entities_init( world_instance
*world
){
84 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_light
); j
++ ){
85 ent_light
*light
= mdl_arritm( &world
->ent_light
, j
);
88 q_m3x3( light
->transform
.q
, to_world
);
89 v3_copy( light
->transform
.co
, to_world
[3] );
90 m4x3_invert_affine( to_world
, light
->inverse_world
);
92 light
->angle_sin_cos
[0] = sinf( light
->angle
* 0.5f
);
93 light
->angle_sin_cos
[1] = cosf( light
->angle
* 0.5f
);
97 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_gate
); j
++ ){
98 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, j
);
100 if( !(gate
->flags
& k_ent_gate_nonlocal
) ) {
101 gate_transform_update( gate
);
104 vg_async_call( world_link_nonlocal_async
, world
, 0 );
107 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_water
); j
++ ){
108 ent_water
*water
= mdl_arritm( &world
->ent_water
, j
);
109 if( world
->water
.enabled
){
110 vg_warn( "Multiple water surfaces in level!\n" );
114 world
->water
.enabled
= 1;
115 water_set_surface( world
, water
->transform
.co
[1] );
119 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_volume
); j
++ ){
120 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, j
);
121 mdl_transform_m4x3( &volume
->transform
, volume
->to_world
);
122 m4x3_invert_full( volume
->to_world
, volume
->to_local
);
126 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_audio
); j
++ ){
127 ent_audio
*audio
= mdl_arritm( &world
->ent_audio
, j
);
129 for( u32 k
=0; k
<audio
->clip_count
; k
++ ){
130 ent_audio_clip
*clip
= mdl_arritm( &world
->ent_audio_clip
,
131 audio
->clip_start
+k
);
133 if( clip
->_
.file
.pack_size
){
134 u32 size
= clip
->_
.file
.pack_size
,
135 offset
= clip
->_
.file
.pack_offset
;
137 /* embedded files are fine to clear the scratch buffer, only
138 * external audio uses it */
140 vg_linear_clear( vg_mem
.scratch
);
141 void *data
= vg_linear_alloc( vg_mem
.scratch
,
142 clip
->_
.file
.pack_size
);
144 mdl_fread_pack_file( &world
->meta
, &clip
->_
.file
, data
);
146 clip
->_
.clip
.path
= NULL
;
147 clip
->_
.clip
.flags
= audio
->flags
;
148 clip
->_
.clip
.data
= data
;
149 clip
->_
.clip
.size
= size
;
152 clip
->_
.clip
.path
= mdl_pstr(&world
->meta
,clip
->_
.file
.pstr_path
);
153 clip
->_
.clip
.flags
= audio
->flags
;
154 clip
->_
.clip
.data
= NULL
;
155 clip
->_
.clip
.size
= 0;
158 audio_clip_load( &clip
->_
.clip
, world
->heap
);
162 /* create generic entity hierachy for those who need it */
163 u32 indexed_count
= 0;
166 mdl_array_ptr
*array
;
169 { k_ent_gate
, &world
->ent_gate
},
170 { k_ent_objective
, &world
->ent_objective
},
171 { k_ent_volume
, &world
->ent_volume
},
172 { k_ent_challenge
, &world
->ent_challenge
}
175 for( u32 i
=0; i
<vg_list_size(indexables
); i
++ )
176 indexed_count
+= mdl_arrcount( indexables
[i
].array
);
177 vg_info( "indexing %u entities\n", indexed_count
);
179 world
->entity_list
= vg_linear_alloc( world
->heap
,
180 vg_align8(indexed_count
*sizeof(u32
)));
183 for( u32 i
=0; i
<vg_list_size(indexables
); i
++ ){
184 u32 type
= indexables
[i
].type
,
185 count
= mdl_arrcount( indexables
[i
].array
);
187 for( u32 j
=0; j
<count
; j
++ )
188 world
->entity_list
[index
++] = mdl_entity_id( type
, j
);
191 world
->entity_bh
= bh_create( world
->heap
, &bh_system_entity_list
, world
,
196 ent_spawn
*world_find_closest_spawn( world_instance
*world
, v3f position
)
198 ent_spawn
*rp
= NULL
, *r
;
199 float min_dist
= INFINITY
;
201 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_spawn
); i
++ ){
202 r
= mdl_arritm( &world
->ent_spawn
, i
);
203 float d
= v3_dist2( r
->transform
.co
, position
);
212 if( mdl_arrcount(&world
->ent_spawn
) ){
213 vg_warn( "Invalid distances to spawns.. defaulting to first one.\n" );
214 return mdl_arritm( &world
->ent_spawn
, 0 );
217 vg_error( "There are no spawns in the level!\n" );
225 ent_spawn
*world_find_spawn_by_name( world_instance
*world
, const char *name
)
227 ent_spawn
*rp
= NULL
, *r
;
228 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_spawn
); i
++ ){
229 r
= mdl_arritm( &world
->ent_spawn
, i
);
230 if( !strcmp( mdl_pstr(&world
->meta
, r
->pstr_name
), name
) ){
237 vg_warn( "No spawn named '%s'\n", name
);
242 VG_STATIC
void ent_volume_call( world_instance
*world
, ent_call
*call
)
244 u32 index
= mdl_entity_id_id( call
->id
);
245 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
246 if( !volume
->target
) return;
248 if( call
->function
== k_ent_function_trigger
){
249 call
->id
= volume
->target
;
251 if( volume
->flags
& k_ent_volume_flag_particles
){
252 float *co
= alloca( sizeof(float)*3 );
253 co
[0] = vg_randf64()*2.0f
-1.0f
;
254 co
[1] = vg_randf64()*2.0f
-1.0f
;
255 co
[2] = vg_randf64()*2.0f
-1.0f
;
256 m4x3_mulv( volume
->to_world
, co
, co
);
258 call
->function
= k_ent_function_particle_spawn
;
260 entity_call( world
, call
);
263 call
->function
= volume
->trigger
.event
;
264 entity_call( world
, call
);
269 VG_STATIC
void ent_audio_call( world_instance
*world
, ent_call
*call
){
270 if( world
->status
== k_world_status_unloading
){
271 vg_warn( "cannot modify audio while unloading world\n" );
275 u8 world_id
= (world
- world_static
.instances
) + 1;
276 u32 index
= mdl_entity_id_id( call
->id
);
277 ent_audio
*audio
= mdl_arritm( &world
->ent_audio
, index
);
281 if( call
->function
== k_ent_function_particle_spawn
){
282 v3_copy( call
->data
, sound_co
);
284 else if( call
->function
== k_ent_function_trigger
){
285 v3_copy( audio
->transform
.co
, sound_co
);
288 vg_fatal_error( "ent_audio_call (invalid function id)" );
290 float chance
= vg_randf64()*100.0f
,
293 for( u32 i
=0; i
<audio
->clip_count
; i
++ ){
294 ent_audio_clip
*clip
= mdl_arritm( &world
->ent_audio_clip
,
295 audio
->clip_start
+i
);
297 float mod
= world
->probabilities
[ audio
->probability_curve
],
298 p
= clip
->probability
* mod
;
304 if( audio
->behaviour
== k_channel_behaviour_unlimited
){
305 audio_oneshot_3d( &clip
->_
.clip
, sound_co
,
306 audio
->transform
.s
[0],
309 else if( audio
->behaviour
== k_channel_behaviour_discard_if_full
){
311 audio_get_group_idle_channel( audio
->group
,
312 audio
->max_channels
);
315 audio_channel_init( ch
, &clip
->_
.clip
, audio
->flags
);
316 audio_channel_group( ch
, audio
->group
);
317 audio_channel_world( ch
, world_id
);
318 audio_channel_set_spacial( ch
, sound_co
, audio
->transform
.s
[0] );
319 audio_channel_edit_volume( ch
, audio
->volume
, 1 );
320 ch
= audio_relinquish_channel( ch
);
323 else if( audio
->behaviour
== k_channel_behaviour_crossfade_if_full
){
325 audio_get_group_idle_channel( audio
->group
,
326 audio
->max_channels
);
330 audio_channel
*existing
=
331 audio_get_group_first_active_channel( audio
->group
);
334 if( existing
->source
== &clip
->_
.clip
){
340 existing
= audio_channel_fadeout(existing
, audio
->crossfade
);
343 ch
= audio_get_first_idle_channel();
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_fadein( ch
, audio
->crossfade
);
351 ch
= audio_relinquish_channel( ch
);
362 VG_STATIC
void ent_ccmd_call( world_instance
*world
, ent_call
*call
){
363 if( call
->function
== k_ent_function_trigger
){
364 u32 index
= mdl_entity_id_id( call
->id
);
365 ent_ccmd
*ccmd
= mdl_arritm( &world
->ent_ccmd
, index
);
366 vg_execute_console_input( mdl_pstr(&world
->meta
, ccmd
->pstr_command
) );
372 * ----------------------------------------------------------------------------
376 entity_bh_expand_bound( void *user
, boxf bound
, u32 item_index
){
377 world_instance
*world
= user
;
379 u32 id
= world
->entity_list
[ item_index
],
380 type
= mdl_entity_id_type( id
),
381 index
= mdl_entity_id_id( id
);
383 if( type
== k_ent_gate
){
384 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
385 boxf box
= {{ -gate
->dimensions
[0], -gate
->dimensions
[1], -0.1f
},
386 { gate
->dimensions
[0], gate
->dimensions
[1], 0.1f
}};
388 m4x3_expand_aabb_aabb( gate
->to_world
, bound
, box
);
390 else if( type
== k_ent_objective
){
391 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, index
);
393 /* TODO: This might be more work than necessary. could maybe just get
394 * away with representing them as points */
399 for( u32 i
=0; i
<objective
->submesh_count
; i
++ ){
400 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
401 objective
->submesh_start
+i
);
402 box_concat( box
, sm
->bbx
);
406 mdl_transform_m4x3( &objective
->transform
, transform
);
407 m4x3_expand_aabb_aabb( transform
, bound
, box
);
409 else if( type
== k_ent_volume
){
410 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
411 m4x3_expand_aabb_aabb( volume
->to_world
, bound
,
412 (boxf
){{-1.0f
,-1.0f
,-1.0f
},{ 1.0f
, 1.0f
, 1.0f
}} );
414 else if( type
== k_ent_challenge
){
415 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
417 boxf box
= {{-1.2f
*0.5f
,-0.72f
*0.5f
,-0.01f
*0.5f
},
418 { 1.2f
*0.5f
, 0.72f
*0.5f
, 0.01f
*0.5f
}};
420 mdl_transform_m4x3( &challenge
->transform
, transform
);
421 m4x3_expand_aabb_aabb( transform
, bound
, box
);
424 vg_fatal_error( "Programming error\n" );
428 VG_STATIC
float entity_bh_centroid( void *user
, u32 item_index
, int axis
){
429 world_instance
*world
= user
;
431 u32 id
= world
->entity_list
[ item_index
],
432 type
= mdl_entity_id_type( id
),
433 index
= mdl_entity_id_id( id
);
435 if( type
== k_ent_gate
){
436 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
437 return gate
->to_world
[3][axis
];
439 else if( type
== k_ent_objective
){
440 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, index
);
441 return objective
->transform
.co
[axis
];
443 else if( type
== k_ent_volume
){
444 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
445 return volume
->transform
.co
[axis
];
447 else if( type
== k_ent_challenge
){
448 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
449 return challenge
->transform
.co
[axis
];
452 vg_fatal_error( "Programming error\n" );
457 VG_STATIC
void entity_bh_swap( void *user
, u32 ia
, u32 ib
){
458 world_instance
*world
= user
;
460 u32 a
= world
->entity_list
[ ia
],
461 b
= world
->entity_list
[ ib
];
463 world
->entity_list
[ ia
] = b
;
464 world
->entity_list
[ ib
] = a
;
467 VG_STATIC
void entity_bh_debug( void *user
, u32 item_index
){
468 world_instance
*world
= user
;
470 u32 id
= world
->entity_list
[ item_index
],
471 type
= mdl_entity_id_type( id
),
472 index
= mdl_entity_id_id( id
);
474 if( type
== k_ent_gate
){
475 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
476 boxf box
= {{ -gate
->dimensions
[0], -gate
->dimensions
[1], -0.1f
},
477 { gate
->dimensions
[0], gate
->dimensions
[1], 0.1f
}};
478 vg_line_boxf_transformed( gate
->to_world
, box
, 0xf000ff00 );
480 else if( type
== k_ent_objective
){
481 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, index
);
485 for( u32 i
=0; i
<objective
->submesh_count
; i
++ ){
486 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
487 objective
->submesh_start
+i
);
488 box_concat( box
, sm
->bbx
);
492 mdl_transform_m4x3( &objective
->transform
, transform
);
493 vg_line_boxf_transformed( transform
, box
, 0xf000ff00 );
495 else if( type
== k_ent_volume
){
496 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
497 vg_line_boxf_transformed( volume
->to_world
,
498 (boxf
){{-1.0f
,-1.0f
,-1.0f
},{ 1.0f
, 1.0f
, 1.0f
}},
501 else if( type
== k_ent_challenge
){
502 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
504 boxf box
= {{-1.2f
*0.5f
,-0.72f
*0.5f
,-0.01f
*0.5f
},
505 { 1.2f
*0.5f
, 0.72f
*0.5f
, 0.01f
*0.5f
}};
507 mdl_transform_m4x3( &challenge
->transform
, transform
);
508 vg_line_boxf_transformed( transform
, box
, 0xf0ff0000 );
511 vg_fatal_error( "Programming error\n" );
515 VG_STATIC
void entity_bh_closest( void *user
, u32 item_index
, v3f point
,
517 world_instance
*world
= user
;
519 u32 id
= world
->entity_list
[ item_index
],
520 type
= mdl_entity_id_type( id
),
521 index
= mdl_entity_id_id( id
);
523 if( type
== k_ent_gate
){
524 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
525 v3_copy( gate
->to_world
[3], closest
);
527 else if( type
== k_ent_objective
){
528 ent_objective
*challenge
= mdl_arritm( &world
->ent_objective
, index
);
529 v3_copy( challenge
->transform
.co
, closest
);
531 else if( type
== k_ent_volume
){
532 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
533 v3_copy( volume
->to_world
[3], closest
);
535 else if( type
== k_ent_challenge
){
536 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
537 v3_copy( challenge
->transform
.co
, closest
);
540 vg_fatal_error( "Programming error\n" );
544 VG_STATIC
void world_entity_start( world_instance
*world
, vg_msg
*sav
){
545 vg_info( "Start instance %p\n", world
);
547 world
->probabilities
[ k_probability_curve_constant
] = 1.0f
;
548 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_audio
); i
++ ){
549 ent_audio
*audio
= mdl_arritm(&world
->ent_audio
,i
);
550 if( audio
->flags
& AUDIO_FLAG_AUTO_START
){
553 call
.function
= k_ent_function_trigger
;
554 call
.id
= mdl_entity_id( k_ent_audio
, i
);
555 entity_call( world
, &call
);
560 * ----------------------------------------------------------------------- */
562 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_challenge
); i
++ ){
563 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, i
);
564 const char *alias
= mdl_pstr( &world
->meta
, challenge
->pstr_alias
);
566 if( vg_msg_seekkvu32( sav
, alias
, k_vg_msg_first
) ){
570 call
.id
= mdl_entity_id( k_ent_challenge
, i
);
571 entity_call( world
, &call
);
576 VG_STATIC
void world_entity_serialize( world_instance
*world
, vg_msg
*sav
){
577 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_challenge
); i
++ ){
578 ent_challenge
*challenge
= mdl_arritm(&world
->ent_challenge
,i
);
580 const char *alias
= mdl_pstr(&world
->meta
,challenge
->pstr_alias
);
581 vg_msg_wkvu32( sav
, alias
, challenge
->status
);
585 #endif /* WORLD_ENTITY_C */