#include "rigidbody.h"
#include "bvh.h"
#include "model.h"
+#include "entity.h"
#include "shaders/scene_standard.h"
#include "shaders/scene_standard_alphatest.h"
#include "shaders/model_sky.h"
-typedef struct teleport_gate teleport_gate;
-
enum { k_max_ui_segments = 8 };
enum { k_max_ui_elements = k_max_ui_segments };
float g_water_fog;
float g_time;
+ float g_realtime;
float g_shadow_length;
float g_shadow_spread;
tex_light_entities,
tex_light_cubes;
+ float probabilities[3];
+
v3i light_cubes;
struct framebuffer heightmap;
/*
* Main world .mdl
*/
- mdl_context *meta;
-
- /*
- * Materials / textures
- */
+ mdl_context meta;
GLuint *textures;
u32 texture_count;
- struct world_material
+ struct world_surface
{
mdl_material info;
mdl_submesh sm_geo,
sm_no_collide;
}
- * materials;
- u32 material_count;
+ * surfaces;
+ u32 surface_count;
+
+ mdl_array_ptr ent_spawn,
+ ent_gate,
+ ent_light,
+ ent_route_node,
+ ent_path_index,
+ ent_checkpoint,
+ ent_route,
+ ent_water,
+
+ ent_audio_clip,
+ ent_audio,
+ ent_volume;
+ ent_gate *rendering_gate;
+
+#if 0
/*
* Named safe places to respawn
*/
struct classtype_world_light *inf;
m4x3f inverse_world;
v2f angle_sin_cos;
-
- /* enabled.. etc?
- * TODO: we should order entities in the binary by their type */
}
* lights;
u32 light_count;
* Routes (world_routes.h)
* --------------------------------------------------------------------------
*/
+
struct route_node
{
v3f co, right, up, h;
}
*collectors;
u32 collector_count;
+#endif
/* logic
/* rendering */
glmesh skydome;
- mdl_submesh dome_upper, dome_lower;
-
- glmesh mesh_gate_surface;
+ glmesh mesh_gate;
+ mdl_submesh sm_gate_surface,
+ sm_gate_marker[4];
double sky_time, sky_rate, sky_target_rate;
- /* gates, TODO: active_gate should also know which instance */
- u32 active_gate,
- current_run_version;
+ u32 current_run_version;
double time, rewind_from, rewind_to, last_use;
/* water rendering */
/* split flap display */
struct
{
- mdl_submesh *sm_module, *sm_card;
glmesh mesh_base, mesh_display;
+ mdl_submesh sm_base;
+ u32 active_route_board;
u32 w, h;
float *buffer;
}
sfd;
- /* timing bars, fixed maximum amount */
- struct route_ui_bar
- {
- GLuint vao, vbo, ebo;
-
- u32 indices_head;
- u32 vertex_head;
-
- struct route_ui_segment
- {
- float length;
- u32 vertex_start, vertex_count,
- index_start, index_count, notches;
- }
- segments[k_max_ui_segments];
-
- u32 segment_start, segment_count, fade_start, fade_count;
- double fade_timer_start;
- float xpos;
- }
- ui_bars[16];
-
v3f render_gate_pos;
- int active_route_board;
int in_volume;
int switching_to_new_world;
int ray_hit_is_ramp( world_instance *world, ray_hit *hit );
VG_STATIC
-struct world_material *ray_hit_material( world_instance *world, ray_hit *hit );
+struct world_surface *ray_hit_surface( world_instance *world, ray_hit *hit );
VG_STATIC
void ray_world_get_tri( world_instance *world, ray_hit *hit, v3f tri[3] );
vg_info( "Loading world resources\n" );
vg_linear_clear( vg_mem.scratch );
- mdl_context *msky = mdl_load_full( vg_mem.scratch, "models/rs_skydome.mdl" );
- mdl_node *nupper = mdl_node_from_name( msky, "dome_complete" );
- world_global.dome_upper = *mdl_node_submesh( msky, nupper, 0 );
+ mdl_context msky;
+ mdl_open( &msky, "models/rs_skydome.mdl", vg_mem.scratch );
+ mdl_load_metadata_block( &msky, vg_mem.scratch );
+ mdl_load_mesh_block( &msky, vg_mem.scratch );
+ mdl_close( &msky );
vg_acquire_thread_sync();
{
- mdl_unpack_glmesh( msky, &world_global.skydome );
+ mdl_unpack_glmesh( &msky, &world_global.skydome );
}
vg_release_thread_sync();
VG_MEMORY_SYSTEM );
}
+typedef struct ent_call ent_call;
+struct ent_call{
+ ent_index ent;
+ u32 function;
+ void *data;
+};
+
+VG_STATIC void entity_call( world_instance *world, ent_call *call );
+
+VG_STATIC void ent_volume_call( world_instance *world, ent_call *call )
+{
+ ent_volume *volume = mdl_arritm( &world->ent_volume, call->ent.index );
+ if( !volume->target.type ) return;
+
+ if( call->function == k_ent_function_trigger ){
+ call->ent = volume->target;
+
+ if( volume->type == k_volume_subtype_particle ){
+ v3f co;
+ co[0] = vg_randf()*2.0f-1.0f;
+ co[1] = vg_randf()*2.0f-1.0f;
+ co[2] = vg_randf()*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
+ entity_call( world, call );
+ }
+}
+
+VG_STATIC void ent_audio_call( world_instance *world, ent_call *call )
+{
+ ent_audio *audio = mdl_arritm( &world->ent_audio, call->ent.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
+ vg_fatal_exit_loop( "ent_audio_call (invalid function id)" );
+
+ float chance = vg_randf()*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_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_fadein( ch, audio->crossfade );
+ ch = audio_relinquish_channel( ch );
+ }
+ }
+
+ audio_unlock();
+ return;
+ }
+ }
+}
+
+VG_STATIC void entity_call( world_instance *world, ent_call *call )
+{
+ if( call->ent.type == k_ent_volume ){
+ ent_volume_call( world, call );
+ } else if( call->ent.type == k_ent_audio ){
+ ent_audio_call( world, call );
+ }
+}
+
VG_STATIC void world_update( world_instance *world, v3f pos )
{
/* TEMP!!!!!! */
struct ub_world_lighting *state = &world->ub_lighting;
state->g_time = g_time;
+ state->g_realtime = vg.time;
state->g_debug_indices = k_debug_light_indices;
state->g_light_preview = k_light_preview;
state->g_debug_complexity = k_debug_light_complexity;
v3_normalize( state->g_sun_dir );
+ world->probabilities[ k_probability_curve_constant ] = 1.0f;
+
+ float dp = state->g_day_phase;
+
+ world->probabilities[ k_probability_curve_wildlife_day ] =
+ (dp*dp*0.8f+state->g_sunset_phase)*0.8f;
+ world->probabilities[ k_probability_curve_wildlife_night ] =
+ 1.0f-powf(fabsf((state->g_time_of_day-0.5f)*5.0f),5.0f);
+
glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting );
glBufferSubData( GL_UNIFORM_BUFFER, 0,
vg.time_delta * 5.0 );
world_routes_update( world );
-#if 0
- world_routes_debug();
-#endif
+ world_routes_debug( world );
+
+ /* ---- SFD ------------ */
- if( world->route_count > 0 )
- {
- int closest = 0;
+ if( mdl_arrcount( &world->ent_route ) ){
+ u32 closest = 0;
float min_dist = INFINITY;
- for( int i=0; i<world->route_count; i++ )
- {
- float d = v3_dist2( world->routes[i].scoreboard_transform[3], pos );
+ for( u32 i=0; i<mdl_arrcount( &world->ent_route ); i++ ){
+ ent_route *route = mdl_arritm( &world->ent_route, i );
+ float dist = v3_dist2( route->board_transform[3], pos );
- if( d < min_dist )
- {
- min_dist = d;
+ if( dist < min_dist ){
+ min_dist = dist;
closest = i;
}
}
- if( (world_global.active_route_board != closest)
+ if( (world_global.sfd.active_route_board != closest)
|| network_scores_updated )
{
network_scores_updated = 0;
- world_global.active_route_board = closest;
+ world_global.sfd.active_route_board = closest;
- struct route *route = &world->routes[closest];
+ ent_route *route = mdl_arritm( &world->ent_route, closest );
+ u32 id = route->official_track_id;
- u32 id = route->track_id;
-
- if( id != 0xffffffff )
- {
+ if( id != 0xffffffff ){
struct netmsg_board *local_board =
&scoreboard_client_data.boards[id];
- for( int i=0; i<13; i++ )
- {
+ for( int i=0; i<13; i++ ){
sfd_encode( i, &local_board->data[27*i] );
}
+ }else{
+ sfd_encode( 0, mdl_pstr( &world->meta, route->pstr_name ) );
+ sfd_encode( 1, "No data" );
}
}
}
+ sfd_update();
- /* TODO: Bvh */
+
static float random_accum = 0.0f;
random_accum += vg.time_delta;
u32 random_ticks = 0;
- while( random_accum > 0.1f )
- {
+ while( random_accum > 0.1f ){
random_accum -= 0.1f;
random_ticks ++;
}
int in_volume = 0;
- while( bh_next( world->volume_bh, &it, volume_proximity, &idx ) )
- {
- struct world_volume *zone = &world->volumes[idx];
+ while( bh_next( world->volume_bh, &it, volume_proximity, &idx ) ){
+ ent_volume *volume = mdl_arritm( &world->ent_volume, idx );
- if( zone->node->classtype == k_classtype_volume_audio )
- {
- vg_line_boxf_transformed( zone->transform, (boxf){{-1.0f,-1.0f,-1.0f},
- { 1.0f, 1.0f, 1.0f}},
- 0xff00c0ff );
-#if 0
- for( int j=0; j<random_ticks; j++ )
+ boxf cube = {{-1.0f,-1.0f,-1.0f},{1.0f,1.0f,1.0f}};
+
+ if( volume->type == k_volume_subtype_trigger ){
+ v3f local;
+ m4x3_mulv( volume->to_local, pos, local );
+
+ if( (fabsf(local[0]) <= 1.0f) &&
+ (fabsf(local[1]) <= 1.0f) &&
+ (fabsf(local[2]) <= 1.0f) )
{
- logic_packet packet;
- packet.location = zone->target_logic_brick;
- packet.function = 0;
+ in_volume = 1;
+ vg_line_boxf_transformed( volume->to_world, cube, 0xff00ff00 );
- packet.type = k_mdl_128bit_datatype_vec3;
- packet.data._v4f[0] = vg_randf()*2.0f-1.0f;
- packet.data._v4f[1] = vg_randf()*2.0f-1.0f;
- packet.data._v4f[2] = vg_randf()*2.0f-1.0f;
- m4x3_mulv( zone->transform, packet.data._v4f, packet.data._v4f );
+ if( !world_global.in_volume ){
+ ent_call basecall;
+ basecall.ent.index = idx;
+ basecall.ent.type = k_ent_volume;
+ basecall.function = k_ent_function_trigger;
+ basecall.data = NULL;
- logic_bricks_send_packet( world, &packet );
+ entity_call( world, &basecall );
+ }
}
-#endif
- continue;
+ else
+ vg_line_boxf_transformed( volume->to_world, cube, 0xff0000ff );
}
+ else if( volume->type == k_volume_subtype_particle ){
+ vg_line_boxf_transformed( volume->to_world, cube, 0xff00c0ff );
- v3f local;
- m4x3_mulv( zone->inv_transform, pos, local );
-
- if( (fabsf(local[0]) <= 1.0f) &&
- (fabsf(local[1]) <= 1.0f) &&
- (fabsf(local[2]) <= 1.0f) )
- {
- in_volume = 1;
-
- if( !world_global.in_volume )
- {
-#if 0
- logic_packet packet;
- packet.location = zone->target_logic_brick;
- packet.function = 0;
+ for( int j=0; j<random_ticks; j++ ){
+ ent_call basecall;
+ basecall.ent.index = idx;
+ basecall.ent.type = k_ent_volume;
+ basecall.function = k_ent_function_trigger;
+ basecall.data = NULL;
- packet.type = k_mdl_128bit_datatype_vec3;
- v3_copy( pos, packet.data._v4f );
-
- logic_bricks_send_packet( world, &packet );
-#endif
+ entity_call( world, &basecall );
}
-
- vg_line_boxf_transformed( zone->transform, (boxf){{-1.0f,-1.0f,-1.0f},
- { 1.0f, 1.0f, 1.0f}},
- 0xff00ff00 );
- }
- else
- {
- vg_line_boxf_transformed( zone->transform, (boxf){{-1.0f,-1.0f,-1.0f},
- { 1.0f, 1.0f, 1.0f}},
- 0xff0000ff );
}
}
+ world_global.in_volume = in_volume;
+#if 0
if( k_debug_light_indices )
{
- for( int i=0; i<world->light_count; i++ )
- {
+ for( int i=0; i<world->light_count; i++ ){
struct world_light *light = &world->lights[i];
struct classtype_world_light *inf = light->inf;
}
}
- world_global.in_volume = in_volume;
- sfd_update();
+#endif
+
+#if 0
/* process soundscape transactions */
audio_lock();
}
}
audio_unlock();
+#endif
}
/*
float min_t = 1.0f;
int idx;
- while( bh_next( world->geo_bh, &it, region, &idx ) )
- {
+ while( bh_next( world->geo_bh, &it, region, &idx ) ){
u32 *ptri = &world->scene_geo->arrindices[ idx*3 ];
v3f tri[3];
boxf box;
box_init_inf( box );
- for( int j=0; j<3; j++ )
- {
+ for( int j=0; j<3; j++ ){
v3_copy( world->scene_geo->arrvertices[ptri[j]].co, tri[j] );
box_addpt( box, tri[j] );
}
float t;
v3f n1;
- if( spherecast_triangle( tri, pa, dir, r, &t, n1 ) )
- {
- if( t < min_t )
- {
+ if( spherecast_triangle( tri, pa, dir, r, &t, n1 ) ){
+ if( t < min_t ){
min_t = t;
hit = idx;
v3_copy( n1, n );
}
VG_STATIC
-struct world_material *world_tri_index_material( world_instance *world,
+struct world_surface *world_tri_index_surface( world_instance *world,
u32 index )
{
- for( int i=1; i<world->material_count; i++ )
- {
- struct world_material *mat = &world->materials[i];
+ for( int i=1; i<world->surface_count; i++ ){
+ struct world_surface *surf = &world->surfaces[i];
- if( (index >= mat->sm_geo.vertex_start) &&
- (index < mat->sm_geo.vertex_start+mat->sm_geo.vertex_count ) )
+ if( (index >= surf->sm_geo.vertex_start) &&
+ (index < surf->sm_geo.vertex_start+surf->sm_geo.vertex_count ) )
{
- return mat;
+ return surf;
}
}
- /* error material */
- return &world->materials[0];
+ return &world->surfaces[0];
}
-VG_STATIC struct world_material *world_contact_material( world_instance *world,
+VG_STATIC struct world_surface *world_contact_surface( world_instance *world,
rb_ct *ct )
{
- return world_tri_index_material( world, ct->element_id );
+ return world_tri_index_surface( world, ct->element_id );
}
-VG_STATIC struct world_material *ray_hit_material( world_instance *world,
- ray_hit *hit )
+VG_STATIC struct world_surface *ray_hit_surface( world_instance *world,
+ ray_hit *hit )
{
- return world_tri_index_material( world, hit->tri[0] );
+ return world_tri_index_surface( world, hit->tri[0] );
}
#endif /* WORLD_H */