#include "bvh.h"
#include "model.h"
#include "entity.h"
+#include "font.h"
#include "shaders/scene_standard.h"
#include "shaders/scene_standard_alphatest.h"
static const float k_light_cube_size = 8.0f;
-struct world_instance
-{
- /* This is a small flag we use to changelevel.
- * It will not be cleared until all sounds stop playing
- */
-
+struct world_instance {
/* Fixed items
* -------------------------------------------------------
*/
char world_name[ 64 ];
- struct
- {
+ struct{
boxf depthbounds;
int depth_computed;
water;
/* STD140 */
- struct ub_world_lighting
- {
+ struct ub_world_lighting{
v4f g_cube_min,
g_cube_inv_range;
v4f g_sunset_ambient;
v4f g_sun_colour;
v4f g_sun_dir;
+ v4f g_board_0;
+ v4f g_board_1;
float g_water_fog;
float g_time;
tex_light_entities,
tex_light_cubes;
+ float probabilities[3];
+
v3i light_cubes;
struct framebuffer heightmap;
* (world_gen.h)
* --------------------------------------------------------------------------
*/
+
/*
* Main world .mdl
*/
GLuint *textures;
u32 texture_count;
- struct world_surface
- {
+ struct world_surface{
mdl_material info;
mdl_submesh sm_geo,
sm_no_collide;
ent_route_node,
ent_path_index,
ent_checkpoint,
- ent_route;
-
- ent_gate *rendering_gate;
+ ent_route,
+ ent_water,
-#if 0
- /*
- * Named safe places to respawn
- */
- struct respawn_point
- {
- v3f co;
- v4f q;
- const char *name;
- }
- * spawns;
- u32 spawn_count;
-
- /*
- * Audio player entities
- */
- struct world_audio_thing
- {
- v3f pos;
- float volume, range;
- u32 flags;
- audio_clip temp_embedded_clip;
- }
- * audio_things;
- u32 audio_things_count;
-
- struct soundscape
- {
- /* locking */
- audio_channel *channels[4];
-
- /* accessable without locking */
- v3f spawn_position;
-
- u32 usage_count;
- u32 max_instances;
- u32 allow_transitions;
- float transition_duration;
- const char *label;
- }
- * soundscapes;
- u32 soundscape_count;
-
- /*
- * Box volume entities
- */
- struct world_volume
- {
- m4x3f transform, inv_transform;
- mdl_node *node;
- }
- * volumes;
- u32 volume_count;
-
- /*
- * Lights
- */
- struct world_light
- {
- mdl_node *node;
- struct classtype_world_light *inf;
- m4x3f inverse_world;
- v2f angle_sin_cos;
- }
- * lights;
- u32 light_count;
-
- /*
- * Routes (world_routes.h)
- * --------------------------------------------------------------------------
- */
-
- struct route_node
- {
- v3f co, right, up, h;
- u32 next[2];
-
- u32 special_type, special_id, current_refs, ref_count;
- u32 route_ids[4]; /* Gates can be linked into up to four routes */
- }
- *nodes;
- u32 node_count;
-
- struct route
- {
- u32 track_id;
- v4f colour;
-
- u32 start;
- mdl_submesh sm;
-
- int active;
- float factive;
-
- double best_lap, latest_pass; /* Session */
-
- m4x3f scoreboard_transform;
- }
- *routes;
- u32 route_count;
-
- struct route_gate
- {
- struct teleport_gate
- {
- v3f co[2];
- v4f q[2];
- v2f dims;
-
- m4x3f to_world, transport;
- }
- gate;
-
- u32 node_id;
-
- struct route_timing
- {
- u32 version; /* Incremented on every teleport */
- double time;
- }
- timing;
- }
- *gates;
- u32 gate_count;
-
- struct nonlocal_gate
- {
- struct teleport_gate gate;
- mdl_node *node;
-
- u32 target_map_index, working;
- }
- *nonlocal_gates;
- u32 nonlocalgate_count;
-
- struct route_collector
- {
- struct route_timing timing;
- }
- *collectors;
- u32 collector_count;
-#endif
+ ent_audio_clip,
+ ent_audio,
+ ent_volume;
+ ent_gate *rendering_gate;
/* logic
* ----------------------------------------------------
mesh_no_collide,
mesh_water;
- rigidbody rb_geo; /* todo.. ... */
+ rb_object rb_geo;
};
-VG_STATIC struct world_global
-{
+VG_STATIC struct world_global{
/*
* Allocated as system memory
* --------------------------------------------------------------------------
double time, rewind_from, rewind_to, last_use;
/* water rendering */
- struct
- {
+ struct{
struct framebuffer fbreflect, fbdepth;
}
water;
/* split flap display */
- struct
- {
+ struct{
glmesh mesh_base, mesh_display;
mdl_submesh sm_base;
u32 active_route_board;
world_instance worlds[4];
u32 world_count;
u32 active_world;
+
+ /* text particles */
+ font3d font;
+
+ struct timer_text{
+ char text[8];
+ m4x3f transform;
+ ent_gate *gate;
+ ent_route *route;
+ }
+ timer_texts[4];
+ u32 timer_text_count;
+
+ struct text_particle{
+ rb_object obj;
+ m4x3f mlocal;
+ ent_glyph *glyph;
+ v4f colour;
+
+ m4x3f mdl;
+ }
+ text_particles[6*4];
+ u32 text_particle_count;
+
}
world_global;
* Submodules
*/
+VG_STATIC float
+ k_day_length = 30.0f; /* minutes */
+
+VG_STATIC int k_debug_light_indices = 0,
+ k_debug_light_complexity = 0,
+ k_light_preview = 0;
+
#include "world_routes.h"
#include "world_sfd.h"
#include "world_render.h"
VG_STATIC void world_init(void)
{
+ VG_VAR_F32( k_day_length );
+ VG_VAR_I32( k_debug_light_indices );
+ VG_VAR_I32( k_debug_light_complexity );
+ VG_VAR_I32( k_light_preview );
+
world_global.sky_rate = 1.0;
world_global.sky_target_rate = 1.0;
VG_MEMORY_SYSTEM );
}
-VG_STATIC void world_update( world_instance *world, v3f pos )
+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 ){
+ float *co = alloca( sizeof(float)*3 );
+ 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 )
{
- /* TEMP!!!!!! */
- static double g_time = 0.0;
- g_time += vg.time_delta * (1.0/(k_day_length*60.0));
+ ent_audio *audio = mdl_arritm( &world->ent_audio, call->ent.index );
+ v3f sound_co;
- struct ub_world_lighting *state = &world->ub_lighting;
+ 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;
- 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;
+ for( u32 i=0; i<audio->clip_count; i++ ){
+ ent_audio_clip *clip = mdl_arritm( &world->ent_audio_clip,
+ audio->clip_start+i );
- state->g_time_of_day = vg_fractf( g_time );
- state->g_day_phase = cosf( state->g_time_of_day * VG_PIf * 2.0f );
- state->g_sunset_phase= cosf( state->g_time_of_day * VG_PIf * 4.0f + VG_PIf );
+ float mod = world->probabilities[ audio->probability_curve ],
+ p = clip->probability * mod;
- state->g_day_phase = state->g_day_phase * 0.5f + 0.5f;
- state->g_sunset_phase = powf( state->g_sunset_phase * 0.5f + 0.5f, 6.0f );
+ bar += p;
- float a = state->g_time_of_day * VG_PIf * 2.0f;
- state->g_sun_dir[0] = sinf( a );
- state->g_sun_dir[1] = cosf( a );
- state->g_sun_dir[2] = 0.2f;
- v3_normalize( state->g_sun_dir );
+ 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;
+ }
+ }
+}
- glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting );
- glBufferSubData( GL_UNIFORM_BUFFER, 0,
- sizeof(struct ub_world_lighting), &world->ub_lighting );
- /* TEMP!!!!!! */
+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 )
+{
world_global.sky_time += world_global.sky_rate * vg.time_delta;
world_global.sky_rate = vg_lerp( world_global.sky_rate,
world_global.sky_target_rate,
vg.time_delta * 5.0 );
+ world_routes_update_timer_texts( world );
world_routes_update( world );
- world_routes_debug( world );
+ //world_routes_debug( world );
/* ---- SFD ------------ */
}
}
sfd_update();
-
-#if 0
- /* TODO: Bvh */
static float random_accum = 0.0f;
random_accum += vg.time_delta;
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;
-
- packet.type = k_mdl_128bit_datatype_vec3;
- v3_copy( pos, packet.data._v4f );
+ 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;
- 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 );
}
}
-#endif
+ world_global.in_volume = in_volume;
#if 0
if( k_debug_light_indices )
}
}
- world_global.in_volume = in_volume;
#endif
#if 0
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 );
struct world_surface *world_tri_index_surface( world_instance *world,
u32 index )
{
- for( int i=1; i<world->surface_count; i++ )
- {
- struct world_surface *mat = &world->surfaces[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 surface */
return &world->surfaces[0];
}