7 #include "world_load.h"
11 VG_STATIC
void world_gen_entities_init( world_instance
*world
){
13 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_light
); j
++ ){
14 ent_light
*light
= mdl_arritm( &world
->ent_light
, j
);
17 q_m3x3( light
->transform
.q
, to_world
);
18 v3_copy( light
->transform
.co
, to_world
[3] );
19 m4x3_invert_affine( to_world
, light
->inverse_world
);
21 light
->angle_sin_cos
[0] = sinf( light
->angle
* 0.5f
);
22 light
->angle_sin_cos
[1] = cosf( light
->angle
* 0.5f
);
26 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_gate
); j
++ ){
27 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, j
);
29 if( !(gate
->flags
& k_ent_gate_nonlocal
) ) {
30 gate_transform_update( gate
);
33 vg_async_call( world_link_nonlocal_async
, world
, 0 );
36 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_water
); j
++ ){
37 ent_water
*water
= mdl_arritm( &world
->ent_water
, j
);
38 if( world
->water
.enabled
){
39 vg_warn( "Multiple water surfaces in level!\n" );
43 world
->water
.enabled
= 1;
44 water_set_surface( world
, water
->transform
.co
[1] );
48 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_volume
); j
++ ){
49 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, j
);
50 mdl_transform_m4x3( &volume
->transform
, volume
->to_world
);
51 m4x3_invert_full( volume
->to_world
, volume
->to_local
);
55 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_audio
); j
++ ){
56 ent_audio
*audio
= mdl_arritm( &world
->ent_audio
, j
);
58 for( u32 k
=0; k
<audio
->clip_count
; k
++ ){
59 ent_audio_clip
*clip
= mdl_arritm( &world
->ent_audio_clip
,
60 audio
->clip_start
+k
);
62 if( clip
->_
.file
.pack_size
){
63 u32 size
= clip
->_
.file
.pack_size
,
64 offset
= clip
->_
.file
.pack_offset
;
66 /* embedded files are fine to clear the scratch buffer, only
67 * external audio uses it */
69 vg_linear_clear( vg_mem
.scratch
);
70 void *data
= vg_linear_alloc( vg_mem
.scratch
,
71 clip
->_
.file
.pack_size
);
73 mdl_fread_pack_file( &world
->meta
, &clip
->_
.file
, data
);
75 clip
->_
.clip
.path
= NULL
;
76 clip
->_
.clip
.flags
= audio
->flags
;
77 clip
->_
.clip
.data
= data
;
78 clip
->_
.clip
.size
= size
;
81 clip
->_
.clip
.path
= mdl_pstr(&world
->meta
,clip
->_
.file
.pstr_path
);
82 clip
->_
.clip
.flags
= audio
->flags
;
83 clip
->_
.clip
.data
= NULL
;
84 clip
->_
.clip
.size
= 0;
87 audio_clip_load( &clip
->_
.clip
, world
->heap
);
91 /* create generic entity hierachy for those who need it */
92 u32 indexed_count
= 0;
98 { k_ent_gate
, &world
->ent_gate
},
99 { k_ent_challenge
, &world
->ent_challenge
},
100 { k_ent_volume
, &world
->ent_volume
},
101 { k_ent_unlock
, &world
->ent_unlock
}
104 for( u32 i
=0; i
<vg_list_size(indexables
); i
++ )
105 indexed_count
+= mdl_arrcount( indexables
[i
].array
);
106 vg_info( "indexing %u entities\n", indexed_count
);
108 world
->entity_list
= vg_linear_alloc( world
->heap
,
109 vg_align8(indexed_count
*sizeof(u32
)));
112 for( u32 i
=0; i
<vg_list_size(indexables
); i
++ ){
113 u32 type
= indexables
[i
].type
,
114 count
= mdl_arrcount( indexables
[i
].array
);
116 for( u32 j
=0; j
<count
; j
++ )
117 world
->entity_list
[index
++] = mdl_entity_id( type
, j
);
120 world
->entity_bh
= bh_create( world
->heap
, &bh_system_entity_list
, world
,
125 ent_spawn
*world_find_closest_spawn( world_instance
*world
, v3f position
)
127 ent_spawn
*rp
= NULL
, *r
;
128 float min_dist
= INFINITY
;
130 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_spawn
); i
++ ){
131 r
= mdl_arritm( &world
->ent_spawn
, i
);
132 float d
= v3_dist2( r
->transform
.co
, position
);
141 if( mdl_arrcount(&world
->ent_spawn
) ){
142 vg_warn( "Invalid distances to spawns.. defaulting to first one.\n" );
143 return mdl_arritm( &world
->ent_spawn
, 0 );
146 vg_error( "There are no spawns in the level!\n" );
154 ent_spawn
*world_find_spawn_by_name( world_instance
*world
, const char *name
)
156 ent_spawn
*rp
= NULL
, *r
;
157 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_spawn
); i
++ ){
158 r
= mdl_arritm( &world
->ent_spawn
, i
);
159 if( !strcmp( mdl_pstr(&world
->meta
, r
->pstr_name
), name
) ){
166 vg_warn( "No spawn named '%s'\n", name
);
171 VG_STATIC
void ent_volume_call( world_instance
*world
, ent_call
*call
)
173 u32 index
= mdl_entity_id_id( call
->id
);
174 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
175 if( !volume
->target
) return;
177 if( call
->function
== k_ent_function_trigger
){
178 call
->id
= volume
->target
;
180 if( volume
->flags
& k_ent_volume_flag_particles
){
181 float *co
= alloca( sizeof(float)*3 );
182 co
[0] = vg_randf64()*2.0f
-1.0f
;
183 co
[1] = vg_randf64()*2.0f
-1.0f
;
184 co
[2] = vg_randf64()*2.0f
-1.0f
;
185 m4x3_mulv( volume
->to_world
, co
, co
);
187 call
->function
= k_ent_function_particle_spawn
;
189 entity_call( world
, call
);
192 call
->function
= volume
->trigger
.event
;
193 entity_call( world
, call
);
198 VG_STATIC
void ent_audio_call( world_instance
*world
, ent_call
*call
){
199 if( world
->status
== k_world_status_unloading
){
200 vg_warn( "cannot modify audio while unloading world\n" );
204 u8 world_id
= (world
- world_static
.instances
) + 1;
205 u32 index
= mdl_entity_id_id( call
->id
);
206 ent_audio
*audio
= mdl_arritm( &world
->ent_audio
, index
);
210 if( call
->function
== k_ent_function_particle_spawn
){
211 v3_copy( call
->data
, sound_co
);
213 else if( call
->function
== k_ent_function_trigger
){
214 v3_copy( audio
->transform
.co
, sound_co
);
217 vg_fatal_error( "ent_audio_call (invalid function id)" );
219 float chance
= vg_randf64()*100.0f
,
222 for( u32 i
=0; i
<audio
->clip_count
; i
++ ){
223 ent_audio_clip
*clip
= mdl_arritm( &world
->ent_audio_clip
,
224 audio
->clip_start
+i
);
226 float mod
= world
->probabilities
[ audio
->probability_curve
],
227 p
= clip
->probability
* mod
;
233 if( audio
->behaviour
== k_channel_behaviour_unlimited
){
234 audio_oneshot_3d( &clip
->_
.clip
, sound_co
,
235 audio
->transform
.s
[0],
238 else if( audio
->behaviour
== k_channel_behaviour_discard_if_full
){
240 audio_get_group_idle_channel( audio
->group
,
241 audio
->max_channels
);
244 audio_channel_init( ch
, &clip
->_
.clip
, audio
->flags
);
245 audio_channel_group( ch
, audio
->group
);
246 audio_channel_world( ch
, world_id
);
247 audio_channel_set_spacial( ch
, sound_co
, audio
->transform
.s
[0] );
248 audio_channel_edit_volume( ch
, audio
->volume
, 1 );
249 ch
= audio_relinquish_channel( ch
);
252 else if( audio
->behaviour
== k_channel_behaviour_crossfade_if_full
){
254 audio_get_group_idle_channel( audio
->group
,
255 audio
->max_channels
);
259 audio_channel
*existing
=
260 audio_get_group_first_active_channel( audio
->group
);
263 if( existing
->source
== &clip
->_
.clip
){
269 existing
= audio_channel_fadeout(existing
, audio
->crossfade
);
272 ch
= audio_get_first_idle_channel();
276 audio_channel_init( ch
, &clip
->_
.clip
, audio
->flags
);
277 audio_channel_group( ch
, audio
->group
);
278 audio_channel_world( ch
, world_id
);
279 audio_channel_fadein( ch
, audio
->crossfade
);
280 ch
= audio_relinquish_channel( ch
);
291 VG_STATIC
void ent_ccmd_call( world_instance
*world
, ent_call
*call
){
292 if( call
->function
== k_ent_function_trigger
){
293 u32 index
= mdl_entity_id_id( call
->id
);
294 ent_ccmd
*ccmd
= mdl_arritm( &world
->ent_ccmd
, index
);
295 vg_execute_console_input( mdl_pstr(&world
->meta
, ccmd
->pstr_command
) );
301 * ----------------------------------------------------------------------------
305 entity_bh_expand_bound( void *user
, boxf bound
, u32 item_index
){
306 world_instance
*world
= user
;
308 u32 id
= world
->entity_list
[ item_index
],
309 type
= mdl_entity_id_type( id
),
310 index
= mdl_entity_id_id( id
);
312 if( type
== k_ent_gate
){
313 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
314 boxf box
= {{ -gate
->dimensions
[0], -gate
->dimensions
[1], -0.1f
},
315 { gate
->dimensions
[0], gate
->dimensions
[1], 0.1f
}};
317 m4x3_expand_aabb_aabb( gate
->to_world
, bound
, box
);
319 else if( type
== k_ent_challenge
){
320 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
322 /* TODO: This might be more work than necessary. could maybe just get
323 * away with representing them as points */
328 for( u32 i
=0; i
<challenge
->submesh_count
; i
++ ){
329 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
330 challenge
->submesh_start
+i
);
331 box_concat( box
, sm
->bbx
);
335 mdl_transform_m4x3( &challenge
->transform
, transform
);
336 m4x3_expand_aabb_aabb( transform
, bound
, box
);
338 else if( type
== k_ent_volume
){
339 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
340 m4x3_expand_aabb_aabb( volume
->to_world
, bound
,
341 (boxf
){{-1.0f
,-1.0f
,-1.0f
},{ 1.0f
, 1.0f
, 1.0f
}} );
345 VG_STATIC
float entity_bh_centroid( void *user
, u32 item_index
, int axis
){
346 world_instance
*world
= user
;
348 u32 id
= world
->entity_list
[ item_index
],
349 type
= mdl_entity_id_type( id
),
350 index
= mdl_entity_id_id( id
);
352 if( type
== k_ent_gate
){
353 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
354 return gate
->to_world
[3][axis
];
356 else if( type
== k_ent_challenge
){
357 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
358 return challenge
->transform
.co
[axis
];
360 else if( type
== k_ent_volume
){
361 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
362 return volume
->transform
.co
[axis
];
364 else if( type
== k_ent_unlock
){
365 ent_unlock
*unlock
= mdl_arritm( &world
->ent_unlock
, index
);
366 return unlock
->transform
.co
[axis
];
369 vg_fatal_error( "Programming error\n" );
374 VG_STATIC
void entity_bh_swap( void *user
, u32 ia
, u32 ib
){
375 world_instance
*world
= user
;
377 u32 a
= world
->entity_list
[ ia
],
378 b
= world
->entity_list
[ ib
];
380 world
->entity_list
[ ia
] = b
;
381 world
->entity_list
[ ib
] = a
;
384 VG_STATIC
void entity_bh_debug( void *user
, u32 item_index
){
385 world_instance
*world
= user
;
387 u32 id
= world
->entity_list
[ item_index
],
388 type
= mdl_entity_id_type( id
),
389 index
= mdl_entity_id_id( id
);
391 if( type
== k_ent_gate
){
392 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
393 boxf box
= {{ -gate
->dimensions
[0], -gate
->dimensions
[1], -0.1f
},
394 { gate
->dimensions
[0], gate
->dimensions
[1], 0.1f
}};
395 vg_line_boxf_transformed( gate
->to_world
, box
, 0xf000ff00 );
397 else if( type
== k_ent_challenge
){
398 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
402 for( u32 i
=0; i
<challenge
->submesh_count
; i
++ ){
403 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
404 challenge
->submesh_start
+i
);
405 box_concat( box
, sm
->bbx
);
409 mdl_transform_m4x3( &challenge
->transform
, transform
);
410 vg_line_boxf_transformed( transform
, box
, 0xf000ff00 );
412 else if( type
== k_ent_volume
){
413 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
414 vg_line_boxf_transformed( volume
->to_world
,
415 (boxf
){{-1.0f
,-1.0f
,-1.0f
},{ 1.0f
, 1.0f
, 1.0f
}},
419 vg_fatal_error( "Programming error\n" );
423 VG_STATIC
void entity_bh_closest( void *user
, u32 item_index
, v3f point
,
425 world_instance
*world
= user
;
427 u32 id
= world
->entity_list
[ item_index
],
428 type
= mdl_entity_id_type( id
),
429 index
= mdl_entity_id_id( id
);
431 if( type
== k_ent_gate
){
432 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
433 v3_copy( gate
->to_world
[3], closest
);
435 else if( type
== k_ent_challenge
){
436 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
437 v3_copy( challenge
->transform
.co
, closest
);
439 else if( type
== k_ent_volume
){
440 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
441 v3_copy( volume
->to_world
[3], closest
);
444 vg_fatal_error( "Programming error\n" );
448 VG_STATIC
void world_entity_start( world_instance
*world
, vg_msg
*sav
){
449 vg_info( "Start instance %p\n", world
);
451 world
->probabilities
[ k_probability_curve_constant
] = 1.0f
;
452 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_audio
); i
++ ){
453 ent_audio
*audio
= mdl_arritm(&world
->ent_audio
,i
);
454 if( audio
->flags
& AUDIO_FLAG_AUTO_START
){
457 call
.function
= k_ent_function_trigger
;
458 call
.id
= mdl_entity_id( k_ent_audio
, i
);
459 entity_call( world
, &call
);
464 * ----------------------------------------------------------------------- */
466 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_unlock
); i
++ ){
467 ent_unlock
*unlock
= mdl_arritm( &world
->ent_unlock
, i
);
468 const char *alias
= mdl_pstr( &world
->meta
, unlock
->pstr_alias
);
470 if( vg_msg_seekkvu32( sav
, alias
, k_vg_msg_first
) ){
474 call
.id
= mdl_entity_id( k_ent_unlock
, i
);
475 entity_call( world
, &call
);
480 VG_STATIC
void world_entity_serialize( world_instance
*world
, vg_msg
*sav
){
481 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_unlock
); i
++ ){
482 ent_unlock
*unlock
= mdl_arritm(&world
->ent_unlock
,i
);
484 const char *alias
= mdl_pstr(&world
->meta
,unlock
->pstr_alias
);
485 vg_msg_wkvu32( sav
, alias
, unlock
->status
);
489 #endif /* WORLD_ENTITY_C */