+++ /dev/null
-#ifndef WORLD_ENTITY_C
-#define WORLD_ENTITY_C
-
-#include "model.h"
-#include "entity.h"
-#include "world.h"
-#include "world_load.h"
-#include "save.h"
-#include "vg/vg_msg.h"
-#include "menu.h"
-#include "ent_challenge.h"
-#include "ent_skateshop.h"
-#include "ent_route.h"
-
-static void world_entity_focus( u32 entity_id ){
- localplayer.immobile = 1;
- menu.disable_open = 1;
-
- v3_zero( localplayer.rb.v );
- v3_zero( localplayer.rb.w );
- player_walk.move_speed = 0.0f;
- world_static.focused_entity = entity_id;
- skaterift.activity = k_skaterift_ent_focus;
-}
-
-static void world_entity_unfocus(void){
- localplayer.immobile = 0;
- skaterift.activity = k_skaterift_default;
- menu.disable_open = 0;
- srinput.state = k_input_state_resume;
-}
-
-static void world_entity_focus_camera( world_instance *world, u32 uid ){
- if( mdl_entity_id_type( uid ) == k_ent_camera ){
- u32 index = mdl_entity_id_id( uid );
- ent_camera *cam = mdl_arritm( &world->ent_camera, index );
-
- v3f dir = {0.0f,-1.0f,0.0f};
- mdl_transform_vector( &cam->transform, dir, dir );
- v3_angles( dir, world_static.focus_cam.angles );
- v3_copy( cam->transform.co, world_static.focus_cam.pos );
- world_static.focus_cam.fov = cam->fov;
- }
- else {
- camera_copy( &localplayer.cam, &world_static.focus_cam );
-
- /* TODO ? */
- world_static.focus_cam.nearz = localplayer.cam.nearz;
- world_static.focus_cam.farz = localplayer.cam.farz;
- }
-}
-
-/* logic preupdate */
-static void world_entity_focus_preupdate(void){
- f32 rate = vg_minf( 1.0f, vg.time_frame_delta * 2.0f );
- int active = 0;
- if( skaterift.activity == k_skaterift_ent_focus )
- active = 1;
-
- vg_slewf( &world_static.focus_strength, active,
- vg.time_frame_delta * (1.0f/0.5f) );
-
- u32 type = mdl_entity_id_type( world_static.focused_entity ),
- index = mdl_entity_id_id( world_static.focused_entity );
- world_instance *world = world_current_instance();
-
- /* TODO: Table. */
- if( type == k_ent_skateshop ){
- ent_skateshop *skateshop = mdl_arritm( &world->ent_skateshop, index );
- ent_skateshop_preupdate( skateshop, active );
- }
- else if( type == k_ent_challenge ){
- ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
- ent_challenge_preupdate( challenge, active );
- }
- else if( type == k_ent_route ){
- ent_route *route = mdl_arritm( &world->ent_route, index );
- ent_route_preupdate( route, active );
- }
-}
-
-/* additional renderings like text etc.. */
-static void world_entity_focus_render(void){
- if( skaterift.activity != k_skaterift_ent_focus )
- return;
-
- u32 type = mdl_entity_id_type( world_static.focused_entity ),
- index = mdl_entity_id_id( world_static.focused_entity );
- world_instance *world = world_current_instance();
-
- if( type == k_ent_skateshop ){
- ent_skateshop *skateshop = mdl_arritm( &world->ent_skateshop, index );
- skateshop_render( skateshop );
- }
- else if( type == k_ent_challenge ){}
- else if( type == k_ent_route ){}
- else if( type == k_ent_miniworld ){}
- else {
- vg_fatal_error( "Programming error\n" );
- }
-}
-
-static void world_gen_entities_init( world_instance *world ){
- /* lights */
- for( u32 j=0; j<mdl_arrcount(&world->ent_light); j ++ ){
- ent_light *light = mdl_arritm( &world->ent_light, j );
-
- m4x3f to_world;
- q_m3x3( light->transform.q, to_world );
- v3_copy( light->transform.co, to_world[3] );
- m4x3_invert_affine( to_world, light->inverse_world );
-
- light->angle_sin_cos[0] = sinf( light->angle * 0.5f );
- light->angle_sin_cos[1] = cosf( light->angle * 0.5f );
- }
-
- /* gates */
- for( u32 j=0; j<mdl_arrcount(&world->ent_gate); j ++ ){
- ent_gate *gate = mdl_arritm( &world->ent_gate, j );
-
- if( !(gate->flags & k_ent_gate_nonlocal) ) {
- gate_transform_update( gate );
- }
- }
-
- vg_async_call( world_link_nonlocal_async, world, 0 );
-
- /* water */
- for( u32 j=0; j<mdl_arrcount(&world->ent_water); j++ ){
- ent_water *water = mdl_arritm( &world->ent_water, j );
- if( world->water.enabled ){
- vg_warn( "Multiple water surfaces in level!\n" );
- break;
- }
-
- world->water.enabled = 1;
- water_set_surface( world, water->transform.co[1] );
- }
-
- /* volumes */
- for( u32 j=0; j<mdl_arrcount(&world->ent_volume); j++ ){
- ent_volume *volume = mdl_arritm( &world->ent_volume, j );
- mdl_transform_m4x3( &volume->transform, volume->to_world );
- m4x3_invert_full( volume->to_world, volume->to_local );
- }
-
- /* audio packs */
- for( u32 j=0; j<mdl_arrcount(&world->ent_audio); j++ ){
- ent_audio *audio = mdl_arritm( &world->ent_audio, j );
-
- for( u32 k=0; k<audio->clip_count; k++ ){
- ent_audio_clip *clip = mdl_arritm( &world->ent_audio_clip,
- audio->clip_start+k );
-
- if( clip->_.file.pack_size ){
- u32 size = clip->_.file.pack_size,
- offset = clip->_.file.pack_offset;
-
- /* embedded files are fine to clear the scratch buffer, only
- * external audio uses it */
-
- vg_linear_clear( vg_mem.scratch );
- void *data = vg_linear_alloc( vg_mem.scratch,
- clip->_.file.pack_size );
-
- mdl_fread_pack_file( &world->meta, &clip->_.file, data );
-
- clip->_.clip.path = NULL;
- clip->_.clip.flags = audio->flags;
- clip->_.clip.data = data;
- clip->_.clip.size = size;
- }
- else{
- clip->_.clip.path = mdl_pstr(&world->meta,clip->_.file.pstr_path);
- clip->_.clip.flags = audio->flags;
- clip->_.clip.data = NULL;
- clip->_.clip.size = 0;
- }
-
- audio_clip_load( &clip->_.clip, world->heap );
- }
- }
-
- /* create generic entity hierachy for those who need it */
- u32 indexed_count = 0;
- struct {
- u32 type;
- mdl_array_ptr *array;
- }
- indexables[] = {
- { k_ent_gate, &world->ent_gate },
- { k_ent_objective, &world->ent_objective },
- { k_ent_volume, &world->ent_volume },
- { k_ent_challenge, &world->ent_challenge }
- };
-
- for( u32 i=0; i<vg_list_size(indexables); i++ )
- indexed_count += mdl_arrcount( indexables[i].array );
- vg_info( "indexing %u entities\n", indexed_count );
-
- world->entity_list = vg_linear_alloc( world->heap,
- vg_align8(indexed_count*sizeof(u32)));
-
- u32 index=0;
- for( u32 i=0; i<vg_list_size(indexables); i++ ){
- u32 type = indexables[i].type,
- count = mdl_arrcount( indexables[i].array );
-
- for( u32 j=0; j<count; j ++ )
- world->entity_list[index ++] = mdl_entity_id( type, j );
- }
-
- world->entity_bh = bh_create( world->heap, &bh_system_entity_list, world,
- indexed_count, 2 );
-}
-
-static
-ent_spawn *world_find_closest_spawn( world_instance *world, v3f position )
-{
- ent_spawn *rp = NULL, *r;
- float min_dist = INFINITY;
-
- for( u32 i=0; i<mdl_arrcount(&world->ent_spawn); i++ ){
- r = mdl_arritm( &world->ent_spawn, i );
- float d = v3_dist2( r->transform.co, position );
-
- if( d < min_dist ){
- min_dist = d;
- rp = r;
- }
- }
-
- if( !rp ){
- if( mdl_arrcount(&world->ent_spawn) ){
- vg_warn( "Invalid distances to spawns.. defaulting to first one.\n" );
- return mdl_arritm( &world->ent_spawn, 0 );
- }
- else{
- vg_error( "There are no spawns in the level!\n" );
- }
- }
-
- return rp;
-}
-
-static
-ent_spawn *world_find_spawn_by_name( world_instance *world, const char *name )
-{
- ent_spawn *rp = NULL, *r;
- for( u32 i=0; i<mdl_arrcount(&world->ent_spawn); i++ ){
- r = mdl_arritm( &world->ent_spawn, i );
- if( !strcmp( mdl_pstr(&world->meta, r->pstr_name), name ) ){
- rp = r;
- break;
- }
- }
-
- if( !rp )
- vg_warn( "No spawn named '%s'\n", name );
-
- return rp;
-}
-
-static void ent_volume_call( world_instance *world, ent_call *call )
-{
- u32 index = mdl_entity_id_id( call->id );
- ent_volume *volume = mdl_arritm( &world->ent_volume, index );
- if( !volume->target ) return;
-
- if( call->function == k_ent_function_trigger ){
- call->id = volume->target;
-
- if( volume->flags & k_ent_volume_flag_particles ){
- float *co = alloca( sizeof(float)*3 );
- co[0] = vg_randf64()*2.0f-1.0f;
- co[1] = vg_randf64()*2.0f-1.0f;
- co[2] = vg_randf64()*2.0f-1.0f;
- m4x3_mulv( volume->to_world, co, co );
-
- call->function = k_ent_function_particle_spawn;
- call->data = co;
- entity_call( world, call );
- }
- else{
- call->function = volume->trigger.event;
- entity_call( world, call );
- }
- }
- else if( call->function == k_ent_function_trigger_leave ){
- call->id = volume->target;
-
- if( volume->flags & k_ent_volume_flag_particles ){
- assert(0);
- }
- else{
- call->function = volume->trigger.event_leave;
- entity_call( world, call );
- }
- }
-}
-
-static void ent_audio_call( world_instance *world, ent_call *call ){
- if( world->status == k_world_status_unloading ){
- vg_warn( "cannot modify audio while unloading world\n" );
- return;
- }
-
- u8 world_id = (world - world_static.instances) + 1;
- u32 index = mdl_entity_id_id( call->id );
- ent_audio *audio = mdl_arritm( &world->ent_audio, index );
-
- v3f sound_co;
-
- if( call->function == k_ent_function_particle_spawn ){
- v3_copy( call->data, sound_co );
- }
- else if( call->function == k_ent_function_trigger ){
- v3_copy( audio->transform.co, sound_co );
- }
- else
- return;
-
- float chance = vg_randf64()*100.0f,
- bar = 0.0f;
-
- for( u32 i=0; i<audio->clip_count; i++ ){
- ent_audio_clip *clip = mdl_arritm( &world->ent_audio_clip,
- audio->clip_start+i );
-
- float mod = world->probabilities[ audio->probability_curve ],
- p = clip->probability * mod;
-
- bar += p;
- if( chance < bar ){
- audio_lock();
-
- if( audio->behaviour == k_channel_behaviour_unlimited ){
- audio_oneshot_3d( &clip->_.clip, sound_co,
- audio->transform.s[0],
- audio->volume );
- }
- else if( audio->behaviour == k_channel_behaviour_discard_if_full ){
- audio_channel *ch =
- audio_get_group_idle_channel( audio->group,
- audio->max_channels );
-
- if( ch ){
- audio_channel_init( ch, &clip->_.clip, audio->flags );
- audio_channel_group( ch, audio->group );
- audio_channel_world( ch, world_id );
- audio_channel_set_spacial( ch, sound_co, audio->transform.s[0] );
- audio_channel_edit_volume( ch, audio->volume, 1 );
- ch = audio_relinquish_channel( ch );
- }
- }
- else if( audio->behaviour == k_channel_behaviour_crossfade_if_full){
- audio_channel *ch =
- audio_get_group_idle_channel( audio->group,
- audio->max_channels );
-
- /* group is full */
- if( !ch ){
- audio_channel *existing =
- audio_get_group_first_active_channel( audio->group );
-
- if( existing ){
- if( existing->source == &clip->_.clip ){
- audio_unlock();
- return;
- }
-
- existing->group = 0;
- existing = audio_channel_fadeout(existing, audio->crossfade);
- }
-
- ch = audio_get_first_idle_channel();
- }
-
- if( ch ){
- audio_channel_init( ch, &clip->_.clip, audio->flags );
- audio_channel_group( ch, audio->group );
- audio_channel_world( ch, world_id );
- audio_channel_fadein( ch, audio->crossfade );
- ch = audio_relinquish_channel( ch );
- }
- }
-
- audio_unlock();
- return;
- }
- }
-}
-
-
-static void ent_ccmd_call( world_instance *world, ent_call *call ){
- if( call->function == k_ent_function_trigger ){
- u32 index = mdl_entity_id_id( call->id );
- ent_ccmd *ccmd = mdl_arritm( &world->ent_ccmd, index );
- vg_execute_console_input( mdl_pstr(&world->meta, ccmd->pstr_command) );
- }
-}
-
-/*
- * BVH implementation
- * ----------------------------------------------------------------------------
- */
-
-static void
-entity_bh_expand_bound( void *user, boxf bound, u32 item_index ){
- world_instance *world = user;
-
- u32 id = world->entity_list[ item_index ],
- type = mdl_entity_id_type( id ),
- index = mdl_entity_id_id( id );
-
- if( type == k_ent_gate ){
- ent_gate *gate = mdl_arritm( &world->ent_gate, index );
- boxf box = {{ -gate->dimensions[0], -gate->dimensions[1], -0.1f },
- { gate->dimensions[0], gate->dimensions[1], 0.1f }};
-
- m4x3_expand_aabb_aabb( gate->to_world, bound, box );
- }
- else if( type == k_ent_objective ){
- ent_objective *objective = mdl_arritm( &world->ent_objective, index );
-
- /* TODO: This might be more work than necessary. could maybe just get
- * away with representing them as points */
-
- boxf box;
- box_init_inf( box );
-
- for( u32 i=0; i<objective->submesh_count; i++ ){
- mdl_submesh *sm = mdl_arritm( &world->meta.submeshs,
- objective->submesh_start+i );
- box_concat( box, sm->bbx );
- }
-
- m4x3f transform;
- mdl_transform_m4x3( &objective->transform, transform );
- m4x3_expand_aabb_aabb( transform, bound, box );
- }
- else if( type == k_ent_volume ){
- ent_volume *volume = mdl_arritm( &world->ent_volume, index );
- m4x3_expand_aabb_aabb( volume->to_world, bound,
- (boxf){{-1.0f,-1.0f,-1.0f},{ 1.0f, 1.0f, 1.0f}} );
- }
- else if( type == k_ent_challenge ){
- ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
-
- boxf box = {{-1.2f*0.5f,-0.72f*0.5f,-0.01f*0.5f},
- { 1.2f*0.5f, 0.72f*0.5f, 0.01f*0.5f}};
- m4x3f transform;
- mdl_transform_m4x3( &challenge->transform, transform );
- m4x3_expand_aabb_aabb( transform, bound, box );
- }
- else{
- vg_fatal_error( "Programming error\n" );
- }
-}
-
-static float entity_bh_centroid( void *user, u32 item_index, int axis ){
- world_instance *world = user;
-
- u32 id = world->entity_list[ item_index ],
- type = mdl_entity_id_type( id ),
- index = mdl_entity_id_id( id );
-
- if( type == k_ent_gate ){
- ent_gate *gate = mdl_arritm( &world->ent_gate, index );
- return gate->to_world[3][axis];
- }
- else if( type == k_ent_objective ){
- ent_objective *objective = mdl_arritm( &world->ent_objective, index );
- return objective->transform.co[axis];
- }
- else if( type == k_ent_volume ){
- ent_volume *volume = mdl_arritm( &world->ent_volume, index );
- return volume->transform.co[axis];
- }
- else if( type == k_ent_challenge ){
- ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
- return challenge->transform.co[axis];
- }
- else {
- vg_fatal_error( "Programming error\n" );
- return INFINITY;
- }
-}
-
-static void entity_bh_swap( void *user, u32 ia, u32 ib ){
- world_instance *world = user;
-
- u32 a = world->entity_list[ ia ],
- b = world->entity_list[ ib ];
-
- world->entity_list[ ia ] = b;
- world->entity_list[ ib ] = a;
-}
-
-static void entity_bh_debug( void *user, u32 item_index ){
- world_instance *world = user;
-
- u32 id = world->entity_list[ item_index ],
- type = mdl_entity_id_type( id ),
- index = mdl_entity_id_id( id );
-
- if( type == k_ent_gate ){
- ent_gate *gate = mdl_arritm( &world->ent_gate, index );
- boxf box = {{ -gate->dimensions[0], -gate->dimensions[1], -0.1f },
- { gate->dimensions[0], gate->dimensions[1], 0.1f }};
- vg_line_boxf_transformed( gate->to_world, box, 0xf000ff00 );
- }
- else if( type == k_ent_objective ){
- ent_objective *objective = mdl_arritm( &world->ent_objective, index );
- boxf box;
- box_init_inf( box );
-
- for( u32 i=0; i<objective->submesh_count; i++ ){
- mdl_submesh *sm = mdl_arritm( &world->meta.submeshs,
- objective->submesh_start+i );
- box_concat( box, sm->bbx );
- }
-
- m4x3f transform;
- mdl_transform_m4x3( &objective->transform, transform );
- vg_line_boxf_transformed( transform, box, 0xf000ff00 );
- }
- else if( type == k_ent_volume ){
- ent_volume *volume = mdl_arritm( &world->ent_volume, index );
- vg_line_boxf_transformed( volume->to_world,
- (boxf){{-1.0f,-1.0f,-1.0f},{ 1.0f, 1.0f, 1.0f}},
- 0xf000ff00 );
- }
- else if( type == k_ent_challenge ){
- ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
-
- boxf box = {{-1.2f*0.5f,-0.72f*0.5f,-0.01f*0.5f},
- { 1.2f*0.5f, 0.72f*0.5f, 0.01f*0.5f}};
- m4x3f transform;
- mdl_transform_m4x3( &challenge->transform, transform );
- vg_line_boxf_transformed( transform, box, 0xf0ff0000 );
- }
- else{
- vg_fatal_error( "Programming error\n" );
- }
-}
-
-static void entity_bh_closest( void *user, u32 item_index, v3f point,
- v3f closest ){
- world_instance *world = user;
-
- u32 id = world->entity_list[ item_index ],
- type = mdl_entity_id_type( id ),
- index = mdl_entity_id_id( id );
-
- if( type == k_ent_gate ){
- ent_gate *gate = mdl_arritm( &world->ent_gate, index );
- v3_copy( gate->to_world[3], closest );
- }
- else if( type == k_ent_objective ){
- ent_objective *challenge = mdl_arritm( &world->ent_objective, index );
- v3_copy( challenge->transform.co, closest );
- }
- else if( type == k_ent_volume ){
- ent_volume *volume = mdl_arritm( &world->ent_volume, index );
- v3_copy( volume->to_world[3], closest );
- }
- else if( type == k_ent_challenge ){
- ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index );
- v3_copy( challenge->transform.co, closest );
- }
- else{
- vg_fatal_error( "Programming error\n" );
- }
-}
-
-static void world_entity_start( world_instance *world, vg_msg *sav ){
- vg_info( "Start instance %p\n", world );
-
- world->probabilities[ k_probability_curve_constant ] = 1.0f;
- for( u32 i=0; i<mdl_arrcount(&world->ent_audio); i++ ){
- ent_audio *audio = mdl_arritm(&world->ent_audio,i);
- if( audio->flags & AUDIO_FLAG_AUTO_START ){
- ent_call call;
- call.data = NULL;
- call.function = k_ent_function_trigger;
- call.id = mdl_entity_id( k_ent_audio, i );
- entity_call( world, &call );
- }
- }
-
- /* read savedata
- * ----------------------------------------------------------------------- */
-
- for( u32 i=0; i<mdl_arrcount(&world->ent_challenge); i++ ){
- ent_challenge *challenge = mdl_arritm( &world->ent_challenge, i );
- const char *alias = mdl_pstr( &world->meta, challenge->pstr_alias );
-
- if( vg_msg_getkvu32( sav, alias, 0 ) ){
- ent_call call;
- call.data = NULL;
- call.function = 0;
- call.id = mdl_entity_id( k_ent_challenge, i );
- entity_call( world, &call );
- }
- }
-}
-
-static void world_entity_serialize( world_instance *world, vg_msg *sav ){
- for( u32 i=0; i<mdl_arrcount(&world->ent_challenge); i++ ){
- ent_challenge *challenge = mdl_arritm(&world->ent_challenge,i);
-
- const char *alias = mdl_pstr(&world->meta,challenge->pstr_alias);
- vg_msg_wkvu32( sav, alias, challenge->status );
- }
-}
-
-#endif /* WORLD_ENTITY_C */