7 #include "world_load.h"
11 #include "ent_challenge.h"
12 #include "ent_skateshop.h"
13 #include "ent_route.h"
15 static void world_entity_focus( u32 entity_id
){
16 localplayer
.immobile
= 1;
17 menu
.disable_open
= 1;
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
;
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
;
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
);
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
;
46 camera_copy( &localplayer
.cam
, &world_static
.focus_cam
);
49 world_static
.focus_cam
.nearz
= localplayer
.cam
.nearz
;
50 world_static
.focus_cam
.farz
= localplayer
.cam
.farz
;
55 static void world_entity_focus_preupdate(void){
56 f32 rate
= vg_minf( 1.0f
, vg
.time_frame_delta
* 2.0f
);
58 if( skaterift
.activity
== k_skaterift_ent_focus
)
61 vg_slewf( &world_static
.focus_strength
, active
,
62 vg
.time_frame_delta
* (1.0f
/0.5f
) );
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();
69 if( type
== k_ent_skateshop
){
70 ent_skateshop
*skateshop
= mdl_arritm( &world
->ent_skateshop
, index
);
71 ent_skateshop_preupdate( skateshop
, active
);
73 else if( type
== k_ent_challenge
){
74 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
75 ent_challenge_preupdate( challenge
, active
);
77 else if( type
== k_ent_route
){
78 ent_route
*route
= mdl_arritm( &world
->ent_route
, index
);
79 ent_route_preupdate( route
, active
);
83 /* additional renderings like text etc.. */
84 static void world_entity_focus_render(void){
85 if( skaterift
.activity
!= k_skaterift_ent_focus
)
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();
92 if( type
== k_ent_skateshop
){
93 ent_skateshop
*skateshop
= mdl_arritm( &world
->ent_skateshop
, index
);
94 skateshop_render( skateshop
);
96 else if( type
== k_ent_challenge
){
98 else if( type
== k_ent_route
){
101 vg_fatal_error( "Programming error\n" );
105 static void world_gen_entities_init( world_instance
*world
){
107 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_light
); j
++ ){
108 ent_light
*light
= mdl_arritm( &world
->ent_light
, j
);
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
);
115 light
->angle_sin_cos
[0] = sinf( light
->angle
* 0.5f
);
116 light
->angle_sin_cos
[1] = cosf( light
->angle
* 0.5f
);
120 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_gate
); j
++ ){
121 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, j
);
123 if( !(gate
->flags
& k_ent_gate_nonlocal_DELETED
) ) {
124 gate_transform_update( gate
);
129 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_water
); j
++ ){
130 ent_water
*water
= mdl_arritm( &world
->ent_water
, j
);
131 if( world
->water
.enabled
){
132 vg_warn( "Multiple water surfaces in level!\n" );
136 world
->water
.enabled
= 1;
137 water_set_surface( world
, water
->transform
.co
[1] );
141 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_volume
); j
++ ){
142 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, j
);
143 mdl_transform_m4x3( &volume
->transform
, volume
->to_world
);
144 m4x3_invert_full( volume
->to_world
, volume
->to_local
);
148 for( u32 j
=0; j
<mdl_arrcount(&world
->ent_audio
); j
++ ){
149 ent_audio
*audio
= mdl_arritm( &world
->ent_audio
, j
);
151 for( u32 k
=0; k
<audio
->clip_count
; k
++ ){
152 ent_audio_clip
*clip
= mdl_arritm( &world
->ent_audio_clip
,
153 audio
->clip_start
+k
);
155 if( clip
->_
.file
.pack_size
){
156 u32 size
= clip
->_
.file
.pack_size
,
157 offset
= clip
->_
.file
.pack_offset
;
159 /* embedded files are fine to clear the scratch buffer, only
160 * external audio uses it */
162 vg_linear_clear( vg_mem
.scratch
);
163 void *data
= vg_linear_alloc( vg_mem
.scratch
,
164 clip
->_
.file
.pack_size
);
166 mdl_fread_pack_file( &world
->meta
, &clip
->_
.file
, data
);
168 clip
->_
.clip
.path
= NULL
;
169 clip
->_
.clip
.flags
= audio
->flags
;
170 clip
->_
.clip
.data
= data
;
171 clip
->_
.clip
.size
= size
;
174 clip
->_
.clip
.path
= mdl_pstr(&world
->meta
,clip
->_
.file
.pstr_path
);
175 clip
->_
.clip
.flags
= audio
->flags
;
176 clip
->_
.clip
.data
= NULL
;
177 clip
->_
.clip
.size
= 0;
180 audio_clip_load( &clip
->_
.clip
, world
->heap
);
184 /* create generic entity hierachy for those who need it */
185 u32 indexed_count
= 0;
188 mdl_array_ptr
*array
;
191 { k_ent_gate
, &world
->ent_gate
},
192 { k_ent_objective
, &world
->ent_objective
},
193 { k_ent_volume
, &world
->ent_volume
},
194 { k_ent_challenge
, &world
->ent_challenge
}
197 for( u32 i
=0; i
<vg_list_size(indexables
); i
++ )
198 indexed_count
+= mdl_arrcount( indexables
[i
].array
);
199 vg_info( "indexing %u entities\n", indexed_count
);
201 world
->entity_list
= vg_linear_alloc( world
->heap
,
202 vg_align8(indexed_count
*sizeof(u32
)));
205 for( u32 i
=0; i
<vg_list_size(indexables
); i
++ ){
206 u32 type
= indexables
[i
].type
,
207 count
= mdl_arrcount( indexables
[i
].array
);
209 for( u32 j
=0; j
<count
; j
++ )
210 world
->entity_list
[index
++] = mdl_entity_id( type
, j
);
213 world
->entity_bh
= bh_create( world
->heap
, &bh_system_entity_list
, world
,
218 ent_spawn
*world_find_closest_spawn( world_instance
*world
, v3f position
)
220 ent_spawn
*rp
= NULL
, *r
;
221 float min_dist
= INFINITY
;
223 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_spawn
); i
++ ){
224 r
= mdl_arritm( &world
->ent_spawn
, i
);
225 float d
= v3_dist2( r
->transform
.co
, position
);
234 if( mdl_arrcount(&world
->ent_spawn
) ){
235 vg_warn( "Invalid distances to spawns.. defaulting to first one.\n" );
236 return mdl_arritm( &world
->ent_spawn
, 0 );
239 vg_error( "There are no spawns in the level!\n" );
247 ent_spawn
*world_find_spawn_by_name( world_instance
*world
, const char *name
)
249 ent_spawn
*rp
= NULL
, *r
;
250 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_spawn
); i
++ ){
251 r
= mdl_arritm( &world
->ent_spawn
, i
);
252 if( !strcmp( mdl_pstr(&world
->meta
, r
->pstr_name
), name
) ){
259 vg_warn( "No spawn named '%s'\n", name
);
264 static void ent_volume_call( world_instance
*world
, ent_call
*call
)
266 u32 index
= mdl_entity_id_id( call
->id
);
267 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
268 if( !volume
->target
) return;
270 if( call
->function
== k_ent_function_trigger
){
271 call
->id
= volume
->target
;
273 if( volume
->flags
& k_ent_volume_flag_particles
){
274 float *co
= alloca( sizeof(float)*3 );
275 co
[0] = vg_randf64()*2.0f
-1.0f
;
276 co
[1] = vg_randf64()*2.0f
-1.0f
;
277 co
[2] = vg_randf64()*2.0f
-1.0f
;
278 m4x3_mulv( volume
->to_world
, co
, co
);
280 call
->function
= k_ent_function_particle_spawn
;
282 entity_call( world
, call
);
285 call
->function
= volume
->trigger
.event
;
286 entity_call( world
, call
);
291 static void ent_audio_call( world_instance
*world
, ent_call
*call
){
292 if( world
->status
== k_world_status_unloading
){
293 vg_warn( "cannot modify audio while unloading world\n" );
297 u8 world_id
= (world
- world_static
.instances
) + 1;
298 u32 index
= mdl_entity_id_id( call
->id
);
299 ent_audio
*audio
= mdl_arritm( &world
->ent_audio
, index
);
303 if( call
->function
== k_ent_function_particle_spawn
){
304 v3_copy( call
->data
, sound_co
);
306 else if( call
->function
== k_ent_function_trigger
){
307 v3_copy( audio
->transform
.co
, sound_co
);
310 vg_fatal_error( "ent_audio_call (invalid function id)" );
312 float chance
= vg_randf64()*100.0f
,
315 for( u32 i
=0; i
<audio
->clip_count
; i
++ ){
316 ent_audio_clip
*clip
= mdl_arritm( &world
->ent_audio_clip
,
317 audio
->clip_start
+i
);
319 float mod
= world
->probabilities
[ audio
->probability_curve
],
320 p
= clip
->probability
* mod
;
326 if( audio
->behaviour
== k_channel_behaviour_unlimited
){
327 audio_oneshot_3d( &clip
->_
.clip
, sound_co
,
328 audio
->transform
.s
[0],
331 else if( audio
->behaviour
== k_channel_behaviour_discard_if_full
){
333 audio_get_group_idle_channel( audio
->group
,
334 audio
->max_channels
);
337 audio_channel_init( ch
, &clip
->_
.clip
, audio
->flags
);
338 audio_channel_group( ch
, audio
->group
);
339 audio_channel_world( ch
, world_id
);
340 audio_channel_set_spacial( ch
, sound_co
, audio
->transform
.s
[0] );
341 audio_channel_edit_volume( ch
, audio
->volume
, 1 );
342 ch
= audio_relinquish_channel( ch
);
345 else if( audio
->behaviour
== k_channel_behaviour_crossfade_if_full
){
347 audio_get_group_idle_channel( audio
->group
,
348 audio
->max_channels
);
352 audio_channel
*existing
=
353 audio_get_group_first_active_channel( audio
->group
);
356 if( existing
->source
== &clip
->_
.clip
){
362 existing
= audio_channel_fadeout(existing
, audio
->crossfade
);
365 ch
= audio_get_first_idle_channel();
369 audio_channel_init( ch
, &clip
->_
.clip
, audio
->flags
);
370 audio_channel_group( ch
, audio
->group
);
371 audio_channel_world( ch
, world_id
);
372 audio_channel_fadein( ch
, audio
->crossfade
);
373 ch
= audio_relinquish_channel( ch
);
384 static void ent_ccmd_call( world_instance
*world
, ent_call
*call
){
385 if( call
->function
== k_ent_function_trigger
){
386 u32 index
= mdl_entity_id_id( call
->id
);
387 ent_ccmd
*ccmd
= mdl_arritm( &world
->ent_ccmd
, index
);
388 vg_execute_console_input( mdl_pstr(&world
->meta
, ccmd
->pstr_command
) );
394 * ----------------------------------------------------------------------------
398 entity_bh_expand_bound( void *user
, boxf bound
, u32 item_index
){
399 world_instance
*world
= user
;
401 u32 id
= world
->entity_list
[ item_index
],
402 type
= mdl_entity_id_type( id
),
403 index
= mdl_entity_id_id( id
);
405 if( type
== k_ent_gate
){
406 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
407 boxf box
= {{ -gate
->dimensions
[0], -gate
->dimensions
[1], -0.1f
},
408 { gate
->dimensions
[0], gate
->dimensions
[1], 0.1f
}};
410 m4x3_expand_aabb_aabb( gate
->to_world
, bound
, box
);
412 else if( type
== k_ent_objective
){
413 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, index
);
415 /* TODO: This might be more work than necessary. could maybe just get
416 * away with representing them as points */
421 for( u32 i
=0; i
<objective
->submesh_count
; i
++ ){
422 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
423 objective
->submesh_start
+i
);
424 box_concat( box
, sm
->bbx
);
428 mdl_transform_m4x3( &objective
->transform
, transform
);
429 m4x3_expand_aabb_aabb( transform
, bound
, box
);
431 else if( type
== k_ent_volume
){
432 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
433 m4x3_expand_aabb_aabb( volume
->to_world
, bound
,
434 (boxf
){{-1.0f
,-1.0f
,-1.0f
},{ 1.0f
, 1.0f
, 1.0f
}} );
436 else if( type
== k_ent_challenge
){
437 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
439 boxf box
= {{-1.2f
*0.5f
,-0.72f
*0.5f
,-0.01f
*0.5f
},
440 { 1.2f
*0.5f
, 0.72f
*0.5f
, 0.01f
*0.5f
}};
442 mdl_transform_m4x3( &challenge
->transform
, transform
);
443 m4x3_expand_aabb_aabb( transform
, bound
, box
);
446 vg_fatal_error( "Programming error\n" );
450 static float entity_bh_centroid( void *user
, u32 item_index
, int axis
){
451 world_instance
*world
= user
;
453 u32 id
= world
->entity_list
[ item_index
],
454 type
= mdl_entity_id_type( id
),
455 index
= mdl_entity_id_id( id
);
457 if( type
== k_ent_gate
){
458 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
459 return gate
->to_world
[3][axis
];
461 else if( type
== k_ent_objective
){
462 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, index
);
463 return objective
->transform
.co
[axis
];
465 else if( type
== k_ent_volume
){
466 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
467 return volume
->transform
.co
[axis
];
469 else if( type
== k_ent_challenge
){
470 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
471 return challenge
->transform
.co
[axis
];
474 vg_fatal_error( "Programming error\n" );
479 static void entity_bh_swap( void *user
, u32 ia
, u32 ib
){
480 world_instance
*world
= user
;
482 u32 a
= world
->entity_list
[ ia
],
483 b
= world
->entity_list
[ ib
];
485 world
->entity_list
[ ia
] = b
;
486 world
->entity_list
[ ib
] = a
;
489 static void entity_bh_debug( void *user
, u32 item_index
){
490 world_instance
*world
= user
;
492 u32 id
= world
->entity_list
[ item_index
],
493 type
= mdl_entity_id_type( id
),
494 index
= mdl_entity_id_id( id
);
496 if( type
== k_ent_gate
){
497 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
498 boxf box
= {{ -gate
->dimensions
[0], -gate
->dimensions
[1], -0.1f
},
499 { gate
->dimensions
[0], gate
->dimensions
[1], 0.1f
}};
500 vg_line_boxf_transformed( gate
->to_world
, box
, 0xf000ff00 );
502 else if( type
== k_ent_objective
){
503 ent_objective
*objective
= mdl_arritm( &world
->ent_objective
, index
);
507 for( u32 i
=0; i
<objective
->submesh_count
; i
++ ){
508 mdl_submesh
*sm
= mdl_arritm( &world
->meta
.submeshs
,
509 objective
->submesh_start
+i
);
510 box_concat( box
, sm
->bbx
);
514 mdl_transform_m4x3( &objective
->transform
, transform
);
515 vg_line_boxf_transformed( transform
, box
, 0xf000ff00 );
517 else if( type
== k_ent_volume
){
518 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
519 vg_line_boxf_transformed( volume
->to_world
,
520 (boxf
){{-1.0f
,-1.0f
,-1.0f
},{ 1.0f
, 1.0f
, 1.0f
}},
523 else if( type
== k_ent_challenge
){
524 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
526 boxf box
= {{-1.2f
*0.5f
,-0.72f
*0.5f
,-0.01f
*0.5f
},
527 { 1.2f
*0.5f
, 0.72f
*0.5f
, 0.01f
*0.5f
}};
529 mdl_transform_m4x3( &challenge
->transform
, transform
);
530 vg_line_boxf_transformed( transform
, box
, 0xf0ff0000 );
533 vg_fatal_error( "Programming error\n" );
537 static void entity_bh_closest( void *user
, u32 item_index
, v3f point
,
539 world_instance
*world
= user
;
541 u32 id
= world
->entity_list
[ item_index
],
542 type
= mdl_entity_id_type( id
),
543 index
= mdl_entity_id_id( id
);
545 if( type
== k_ent_gate
){
546 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, index
);
547 v3_copy( gate
->to_world
[3], closest
);
549 else if( type
== k_ent_objective
){
550 ent_objective
*challenge
= mdl_arritm( &world
->ent_objective
, index
);
551 v3_copy( challenge
->transform
.co
, closest
);
553 else if( type
== k_ent_volume
){
554 ent_volume
*volume
= mdl_arritm( &world
->ent_volume
, index
);
555 v3_copy( volume
->to_world
[3], closest
);
557 else if( type
== k_ent_challenge
){
558 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, index
);
559 v3_copy( challenge
->transform
.co
, closest
);
562 vg_fatal_error( "Programming error\n" );
566 static void world_entity_start( world_instance
*world
, vg_msg
*sav
){
567 vg_info( "Start instance %p\n", world
);
569 world
->probabilities
[ k_probability_curve_constant
] = 1.0f
;
570 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_audio
); i
++ ){
571 ent_audio
*audio
= mdl_arritm(&world
->ent_audio
,i
);
572 if( audio
->flags
& AUDIO_FLAG_AUTO_START
){
575 call
.function
= k_ent_function_trigger
;
576 call
.id
= mdl_entity_id( k_ent_audio
, i
);
577 entity_call( world
, &call
);
582 * ----------------------------------------------------------------------- */
584 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_challenge
); i
++ ){
585 ent_challenge
*challenge
= mdl_arritm( &world
->ent_challenge
, i
);
586 const char *alias
= mdl_pstr( &world
->meta
, challenge
->pstr_alias
);
588 if( vg_msg_getkvu32( sav
, alias
, 0 ) ){
592 call
.id
= mdl_entity_id( k_ent_challenge
, i
);
593 entity_call( world
, &call
);
599 * used for relinking multi-world data. ran anytime the world setup changes
601 static void world_entity_relink( world_instance
*world
){
602 vg_info( "entity_relink(%d)\n", world
- world_static
.instances
);
603 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_miniworld
); i
++ ){
604 ent_miniworld
*miniworld
= mdl_arritm( &world
->ent_miniworld
, i
);
605 miniworld
->purpose
= k_world_purpose_invalid
;
607 const char *uid
= mdl_pstr( &world
->meta
, miniworld
->pstr_world
);
609 addon_uid_to_alias( uid
, &q
);
611 u32 addon_id
= addon_match( &q
);
612 if( addon_id
!= 0xffffffff ){
613 addon_reg
*reg
= get_addon_from_index( k_addon_type_world
, addon_id
);
615 for( int j
=0; j
<k_world_max
; j
++ ){
616 world_instance
*other
= &world_static
.instances
[j
];
617 if( other
== world
) continue;
618 if( (other
->status
== k_world_status_loaded
) &&
619 (world_static
.instance_addons
[j
] == reg
) ){
620 miniworld
->purpose
= j
;
628 static void world_entity_serialize( world_instance
*world
, vg_msg
*sav
){
629 for( u32 i
=0; i
<mdl_arrcount(&world
->ent_challenge
); i
++ ){
630 ent_challenge
*challenge
= mdl_arritm(&world
->ent_challenge
,i
);
632 const char *alias
= mdl_pstr(&world
->meta
,challenge
->pstr_alias
);
633 vg_msg_wkvu32( sav
, alias
, challenge
->status
);
637 #endif /* WORLD_ENTITY_C */