{ .path="sound/tap3.ogg" }
};
+audio_clip audio_flips[] =
+{
+ { .path="sound/lf0.ogg" },
+ { .path="sound/lf1.ogg" },
+ { .path="sound/lf2.ogg" },
+ { .path="sound/lf3.ogg" },
+};
+
audio_clip audio_hits[] =
{
{ .path="sound/hit0.ogg" },
{ .path = "sound/objective_fail.ogg" }
};
+struct air_synth_data {
+ f32 speed;
+
+ /* internal */
+ f32 t;
+ struct dsp_biquad lpf;
+ SDL_SpinLock sl;
+}
+static air_data;
+
+static void audio_air_synth_get_samples( void *_data, f32 *buf, u32 count ){
+ struct air_synth_data *data = _data;
+
+ SDL_AtomicLock( &data->sl );
+ f32 spd = data->speed;
+ SDL_AtomicUnlock( &data->sl );
+
+ f32 s0 = sinf(data->t*2.0f),
+ s1 = sinf(data->t*0.43f),
+ s2 = sinf(data->t*1.333f),
+ sm = vg_clampf( data->speed / 45.0f, 0, 1 ),
+ ft = (s0*s1*s2)*0.5f+0.5f,
+ f = vg_lerpf( 200.0f, 1200.0f, sm*0.7f + ft*0.3f ),
+ vol = 0.25f * sm;
+
+ dsp_init_biquad_butterworth_lpf( &data->lpf, f );
+
+ for( u32 i=0; i<count; i ++ ){
+ f32 v = (vg_randf64(&vg_dsp.rand) * 2.0f - 1.0f) * vol;
+ v = dsp_biquad_process( &data->lpf, v );
+
+ buf[i*2+0] = v;
+ buf[i*2+1] = v;
+ }
+
+ data->t += (f32)(count)/44100.0f;
+};
+
+static audio_clip air_synth = {
+ .flags = k_audio_format_gen,
+ .size = 0,
+ .func = audio_air_synth_get_samples,
+ .data = &air_data
+};
+
static void audio_init(void)
{
audio_clip_loadn( audio_board, vg_list_size(audio_board), NULL );
audio_clip_loadn( audio_taps, vg_list_size(audio_taps), NULL );
+ audio_clip_loadn( audio_flips, vg_list_size(audio_flips), NULL );
audio_clip_loadn( audio_hits, vg_list_size(audio_hits), NULL );
audio_clip_loadn( audio_ambience, vg_list_size(audio_ambience), NULL );
audio_clip_loadn( &audio_splash, 1, NULL );
audio_lock();
audio_set_lfo_wave( 0, k_lfo_polynomial_bipolar, 80.0f );
audio_set_lfo_frequency( 0, 20.0f );
+
+ skaterift.aud_air = audio_get_first_idle_channel();
+ if( skaterift.aud_air )
+ audio_channel_init( skaterift.aud_air, &air_synth, 0 );
+
audio_unlock();
}
if( sprite_type != k_audio_sprite_type_none ){
if( sprite_type == k_audio_sprite_type_grass ){
- audio_ambient_sprite_play( sprite_pos, &audio_grass[vg_randu32()%4] );
+ audio_ambient_sprite_play( sprite_pos,
+ &audio_grass[vg_randu32(&vg.rand)%4] );
}
else if( sprite_type == k_audio_sprite_type_water ){
if( world->water.enabled ){
audio_ambient_sprite_play( sprite_pos,
- &audio_water[vg_randu32()%6] );
+ &audio_water[vg_randu32(&vg.rand)%6] );
}
}
}
};
struct bh_system{
+ u32 system_type;
void (*expand_bound)( void *user, boxf bound, u32 item_index );
float (*item_centroid)( void *user, u32 item_index, int axis );
void (*item_closest)( void *user, u32 item_index, v3f point, v3f closest );
int (*cast_ray)( void *user, u32 index, v3f co, v3f dir, ray_hit *hit );
};
+static float scene_bh_centroid( void *user, u32 item_index, int axis );
+static void scene_bh_swap( void *user, u32 ia, u32 ib );
+static void scene_bh_expand_bound( void *user, boxf bound, u32 item_index );
+
static void bh_update_bounds( bh_tree *bh, u32 inode ){
bh_node *node = &bh->nodes[ inode ];
box_init_inf( node->bbx );
for( u32 i=0; i<node->count; i++ ){
u32 idx = node->start+i;
- bh->system->expand_bound( bh->user, node->bbx, idx );
+ if( bh->system->system_type == 0x1 )
+ scene_bh_expand_bound( bh->user, node->bbx, idx );
+ else
+ bh->system->expand_bound( bh->user, node->bbx, idx );
}
}
float split = node->bbx[0][axis] + extent[axis]*0.5f;
float avg = 0.0;
- for( u32 t=0; t<node->count; t++ )
- {
+ for( u32 t=0; t<node->count; t++ ){
u32 idx = node->start+t;
- avg += bh->system->item_centroid( bh->user, idx, axis );
+
+ if( bh->system->system_type == 0x1 )
+ avg += scene_bh_centroid( bh->user, idx, axis );
+ else
+ avg += bh->system->item_centroid( bh->user, idx, axis );
}
avg /= (float)node->count;
split = avg;
j = i + node->count-1;
while( i <= j ){
- if( bh->system->item_centroid( bh->user, i, axis ) < split )
+ f32 centroid;
+
+ if( bh->system->system_type == 0x1 )
+ centroid = scene_bh_centroid( bh->user, i, axis );
+ else
+ centroid = bh->system->item_centroid( bh->user, i, axis );
+
+ if( centroid < split )
i ++;
else{
- bh->system->item_swap( bh->user, i, j );
+ if( bh->system->system_type == 0x1 )
+ scene_bh_swap( bh->user, i, j );
+ else
+ bh->system->item_swap( bh->user, i, j );
j --;
}
}
--- /dev/null
+#ifndef ENT_TRAFFIC_C
+#define ENT_TRAFFIC_C
+
+#include "world.h"
+
+static void ent_traffic_update( world_instance *world, v3f pos ){
+ for( u32 i=0; i<mdl_arrcount( &world->ent_traffic ); i++ ){
+ ent_traffic *traffic = mdl_arritm( &world->ent_traffic, i );
+
+ u32 i1 = traffic->index,
+ i0,
+ i2 = i1+1;
+
+ if( i1 == 0 ) i0 = traffic->node_count-1;
+ else i0 = i1-1;
+
+ if( i2 >= traffic->node_count ) i2 = 0;
+
+ i0 += traffic->start_node;
+ i1 += traffic->start_node;
+ i2 += traffic->start_node;
+
+ v3f h[3];
+
+ ent_route_node *rn0 = mdl_arritm( &world->ent_route_node, i0 ),
+ *rn1 = mdl_arritm( &world->ent_route_node, i1 ),
+ *rn2 = mdl_arritm( &world->ent_route_node, i2 );
+
+ v3_copy( rn1->co, h[1] );
+ v3_lerp( rn0->co, rn1->co, 0.5f, h[0] );
+ v3_lerp( rn1->co, rn2->co, 0.5f, h[2] );
+
+ float const k_sample_dist = 0.0025f;
+ v3f pc, pd;
+ eval_bezier3( h[0], h[1], h[2], traffic->t, pc );
+ eval_bezier3( h[0], h[1], h[2], traffic->t+k_sample_dist, pd );
+
+ v3f v0;
+ v3_sub( pd, pc, v0 );
+ float length = vg_maxf( 0.0001f, v3_length( v0 ) );
+ v3_muls( v0, 1.0f/length, v0 );
+
+ float mod = k_sample_dist / length;
+
+ traffic->t += traffic->speed * vg.time_delta * mod;
+
+ if( traffic->t > 1.0f ){
+ traffic->t -= 1.0f;
+
+ if( traffic->t > 1.0f ) traffic->t = 0.0f;
+
+ traffic->index ++;
+
+ if( traffic->index >= traffic->node_count )
+ traffic->index = 0;
+ }
+
+ v3_copy( pc, traffic->transform.co );
+
+ float a = atan2f( -v0[0], v0[2] );
+ q_axis_angle( traffic->transform.q, (v3f){0.0f,1.0f,0.0f}, -a );
+
+ vg_line_point( traffic->transform.co, 0.3f, VG__BLUE );
+ }
+}
+
+#endif /* ENT_TRAFFIC_C */
--- /dev/null
+#ifndef ENT_TRAFFIC_H
+#define ENT_TRAFFIC_H
+
+#include "world.h"
+static void ent_traffic_update( world_instance *world, v3f pos );
+
+#endif /* ENT_TRAFFIC_H */
#include "ent_portal.c"
#include "ent_miniworld.c"
#include "ent_region.c"
+#include "ent_traffic.c"
typedef void (*fn_entity_call_handler)( world_instance *, ent_call *);
#include "audio.h"
#include "input.h"
#include "workshop.h"
-#include "respawn.h"
+#include "world_map.h"
#include "gui.h"
#include "ent_miniworld.h"
if( MDL_CONST_PSTREQ( &menu.model, q, "quit" ) ){
vg.window_should_close = 1;
}
-
else if( MDL_CONST_PSTREQ( &menu.model, q, "map" ) ){
-
menu_close();
- respawn_begin_chooser();
+ world_map_enter();
}
else if( MDL_CONST_PSTREQ( &menu.model, q, "hub" ) ){
if( world_static.active_instance == k_world_purpose_client ){
v3_tangent_basis( dir, tx, ty );
v3f rand;
- vg_rand_cone( rand, angle );
+ vg_rand_cone( &vg.rand, rand, angle );
v3_muls( tx, rand[0]*speed, p->v );
v3_muladds( p->v, ty, rand[1]*speed, p->v );
v3_muladds( p->v, dir, rand[2]*speed, p->v );
#include "ent_miniworld.h"
#include "gui.h"
+#include "shaders/model_entity.h"
+#include "shaders/model_character_view.h"
+#include "shaders/model_board_view.h"
+
static int localplayer_cmd_respawn( int argc, const char *argv[] ){
ent_spawn *rp = NULL, *r;
world_instance *world = world_current_instance();
static void player_init(void){
for( u32 i=0; i<vg_list_size(player_subsystems); i++ ){
struct player_subsystem_interface *sys = player_subsystems[i];
-
if( sys->system_register ) sys->system_register();
}
vg_console_reg_var( "cinema_fixed", &k_cinema_fixed, k_var_dtype_i32, 0 );
vg_console_reg_var( "invert_y", &k_invert_y,
k_var_dtype_i32, VG_VAR_PERSISTENT );
+
+ shader_model_character_view_register();
+ shader_model_board_view_register();
+ shader_model_entity_register();
}
static void player__debugtext( int size, const char *fmt, ... ){
static void player__post_update(void){
if( player_subsystems[ localplayer.subsystem ]->post_update )
player_subsystems[ localplayer.subsystem ]->post_update();
+
+ SDL_AtomicLock( &air_data.sl );
+ air_data.speed = v3_length( localplayer.rb.v );
+ SDL_AtomicUnlock( &air_data.sl );
}
/*
}
static void player_apply_transport_to_cam( m4x3f transport ){
- /* FIXME: Applies to skaterift.cam directly! */
-
/* Pre-emptively edit the camera matrices so that the motion vectors
* are correct */
m4x3f transport_i;
[k_skaterift_replay] = "replay",
[k_skaterift_ent_focus] = "ent_focus",
[k_skaterift_default] = "default",
- [k_skaterift_respawning]= "map"
+ [k_skaterift_world_map] = "world map"
} [skaterift.activity] );
player__debugtext( 1, "time_rate: %.4f", skaterift.time_rate );
static void effect_blink_apply( effect_blink *ef, player_pose *pose, f32 dt ){
if( ef->t < 0.0f ){
- ef->t = (1.0f-powf(vg_randf64(),4.0f))*4.0f;
+ ef->t = (1.0f-powf(vg_randf64(&vg.rand),4.0f))*4.0f;
ef->l = 0.08f;
}
if( !ef->colour ) return;
if( ef->t < 0.0f ){
- ef->t = 0.05f+vg_randf64()*0.1f;
+ ef->t = 0.05f+vg_randf64(&vg.rand)*0.1f;
v3f dir;
v3_copy( v, dir );
if( stress ){
temp_filter = 20;
audio_lock();
- audio_oneshot_3d( &audio_hits[vg_randu32()%5], stress->co, 20.0f, 1.0f );
+ audio_oneshot_3d( &audio_hits[vg_randu32(&vg.rand)%5],
+ stress->co, 20.0f, 1.0f );
audio_unlock();
}
}
for( int i=0; i<NETWORK_MAX_PLAYERS; i ++ ){
struct network_player *player = &netplayers.list[i];
- player->active = (vg_randu32() & 0x1)? 2: 0;
- player->isfriend = vg_randu32() & vg_randu32() & 0x1;
- player->isblocked = vg_randu32() & vg_randu32() & vg_randu32() & 0x1;
- player->world_match[ 0 ] = vg_randu32() & 0x1;
+ player->active = (vg_randu32(&vg.rand) & 0x1)? 2: 0;
+ player->isfriend = vg_randu32(&vg.rand) & vg_randu32(&vg.rand) & 0x1;
+ player->isblocked = vg_randu32(&vg.rand) &
+ vg_randu32(&vg.rand) &
+ vg_randu32(&vg.rand) & 0x1;
+ player->world_match[ 0 ] = vg_randu32(&vg.rand) & 0x1;
player->world_match[ 1 ] = 0;
if( player->world_match[0] )
player->active_world = NULL;
for( int i=0; i<sizeof(player->username)-1; i ++ ){
- player->username[i] = 'a' + (vg_randu32() % 30);
+ player->username[i] = 'a' + (vg_randu32(&vg.rand) % 30);
player->username[i+1] = '\0';
- if( (vg_randu32() % 8) == 3 )
+ if( (vg_randu32(&vg.rand) % 8) == 3 )
break;
}
for( int i=0; i<3; i ++ ){
- player->medals[i] = vg_randu32() % 3;
+ player->medals[i] = vg_randu32(&vg.rand) % 3;
}
v3f pos;
- vg_rand_sphere( pos );
+ vg_rand_sphere( &vg.rand, pos );
v3_muladds( localplayer.rb.co, pos, 100.0f,
netplayers.final_mtx[ i*localplayer.skeleton.bone_count][3] );
}
if( v3_length2( state->trick_vel ) < 0.0001f )
return;
- int carry_on = player_skate_trick_input();
+ int carry_on = state->trick_type == player_skate_trick_input();
/* we assume velocities share a common divisor, in which case the
* interval is the minimum value (if not zero) */
}
float interval = 1.0f / min_rate,
- current = floorf( state->trick_time / interval ),
- next_end = (current+1.0f) * interval;
+ current = floorf( state->trick_time ),
+ next_end = current+1.0f;
/* integrate trick velocities */
v3_muladds( state->trick_euler, state->trick_vel, k_rb_delta,
state->trick_euler );
- if( !carry_on && (state->trick_time + k_rb_delta >= next_end) ){
+ if( !carry_on && (state->trick_time + k_rb_delta/interval >= next_end) ){
state->trick_time = 0.0f;
state->trick_euler[0] = roundf( state->trick_euler[0] );
state->trick_euler[1] = roundf( state->trick_euler[1] );
state->trick_euler[2] = roundf( state->trick_euler[2] );
v3_copy( state->trick_vel, state->trick_residualv );
v3_zero( state->trick_vel );
- }
- state->trick_time += k_rb_delta;
+ audio_lock();
+ audio_oneshot_3d( &audio_flips[vg_randu32(&vg.rand)%4],
+ localplayer.rb.co, 40.0f, 1.0f );
+ audio_unlock();
+ }
+ else
+ state->trick_time += k_rb_delta / interval;
}
else{
if( (v3_length2(state->trick_vel) >= 0.0001f ) &&
if( state->activity <= k_skate_activity_air_to_grind ){
enum trick_type trick = k_trick_type_none;
if( (trick = player_skate_trick_input()) ){
- if( (vg.time - state->jump_time) < 0.1f ){
+ if( state->trick_time == 0.0f ){
+ audio_lock();
+ audio_oneshot_3d( &audio_flips[vg_randu32(&vg.rand)%4],
+ localplayer.rb.co, 40.0f, 1.0f );
+ audio_unlock();
+ }
+
+ if( state->trick_time < 0.1f ){
v3_zero( state->trick_vel );
- state->trick_time = 0.0f;
if( trick == k_trick_type_kickflip ){
state->trick_vel[0] = 3.0f;
state->trick_vel[0],
state->trick_vel[1],
state->trick_vel[2] );
- player__debugtext( 1, "tricke: %.2f %.2f %.2f",
+ player__debugtext( 1, "tricke: %.2fs %.2f %.2f %.2f",
+ state->trick_time,
state->trick_euler[0],
state->trick_euler[1],
state->trick_euler[2] );
float curspeed = v3_length( localplayer.rb.v ),
kickspeed = vg_clampf( curspeed*(1.0f/40.0f), 0.0f, 1.0f ),
- kicks = (vg_randf64()-0.5f)*2.0f*kickspeed,
+ kicks = (vg_randf64(&vg.rand)-0.5f)*2.0f*kickspeed,
sign = vg_signf( kicks );
animator->wobble[0] = vg_lerpf( animator->wobble[0], kicks*kicks*sign,
animator->subslap = vg_lerpf( animator->subslap, slapm,
vg.time_delta*10.0f );
+#if 0
f32 l = ((state->activity < k_skate_activity_ground) &&
v3_length2(state->trick_vel) > 0.1f )? 1: 0;
animator->trick_foot = vg_lerpf( animator->trick_foot, l,
8.4f*vg.time_delta );
+#endif
+
+ animator->trick_foot = vg_exp_impulse( state->trick_time, 5.0f );
/* grab */
v2f grab_input;
kf_board->co[1] += animator->slap * animator->subslap;
kf_hip->co[1] += animator->slap * 0.25f;
+ /* kickflip and shuvit are in the wrong order for some reason */
if( animator->trick_type == k_trick_type_kickflip ){
- kf_foot_l->co[0] += animator->trick_foot * 0.2f;
+ kf_foot_l->co[0] += animator->trick_foot * 0.15f;
+ kf_foot_r->co[0] -= animator->trick_foot * 0.15f;
kf_foot_l->co[1] -= animator->trick_foot * 0.18f;
+ kf_foot_r->co[1] -= animator->trick_foot * 0.18f;
}
else if( animator->trick_type == k_trick_type_shuvit ){
- kf_foot_l->co[0] += animator->trick_foot * 0.1f;
- kf_foot_r->co[0] -= animator->trick_foot * 0.15f;
+ kf_foot_l->co[0] += animator->trick_foot * 0.2f;
kf_foot_l->co[1] -= animator->trick_foot * 0.18f;
- kf_foot_r->co[1] -= animator->trick_foot * 0.18f;
+ kf_foot_r->co[0] -= animator->trick_foot * 0.1f;
+ kf_foot_r->co[1] += animator->trick_foot * 0.09f;
}
else if( animator->trick_type == k_trick_type_treflip ){
kf_foot_l->co[0] += animator->trick_foot * 0.2f;
audio_lock();
if( id == k_player_skate_soundeffect_jump ){
- audio_oneshot_3d( &audio_jumps[vg_randu32()%2], pos, 40.0f, volume );
+ audio_oneshot_3d( &audio_jumps[vg_randu32(&vg.rand)%2],
+ pos, 40.0f, volume );
}
else if( id == k_player_skate_soundeffect_tap ){
- audio_oneshot_3d( &audio_taps[vg_randu32()%4], pos, 40.0f, volume );
+ audio_oneshot_3d( &audio_taps[vg_randu32(&vg.rand)%4],
+ pos, 40.0f, volume );
}
else if( id == k_player_skate_soundeffect_land_good ){
- audio_oneshot_3d( &audio_lands[vg_randu32()%3], pos, 40.0f, volume );
+ audio_oneshot_3d( &audio_lands[vg_randu32(&vg.rand)%3],
+ pos, 40.0f, volume );
}
else if( id == k_player_skate_soundeffect_land_bad ){
- audio_oneshot_3d( &audio_lands[vg_randu32()%2+3], pos, 40.0f, volume );
+ audio_oneshot_3d( &audio_lands[vg_randu32(&vg.rand)%2+3],
+ pos, 40.0f, volume );
}
else if( id == k_player_skate_soundeffect_grind_metal ){
audio_oneshot_3d( &audio_board[3], pos, 40.0f, volume );
audio_lock();
if( w->surface == k_surface_prop_concrete ){
audio_oneshot_3d(
- &audio_footsteps[vg_randu32()%vg_list_size(audio_footsteps)],
+ &audio_footsteps[vg_randu32(&vg.rand) %
+ vg_list_size(audio_footsteps)],
localplayer.rb.co, 40.0f, 1.0f
);
}
else if( w->surface == k_surface_prop_grass ){
audio_oneshot_3d(
- &audio_footsteps_grass[ vg_randu32()%
+ &audio_footsteps_grass[ vg_randu32(&vg.rand) %
vg_list_size(audio_footsteps_grass)],
localplayer.rb.co, 40.0f, 1.0f
);
}
else if( w->surface == k_surface_prop_wood ){
audio_oneshot_3d(
- &audio_footsteps_wood[ vg_randu32()%
+ &audio_footsteps_wood[ vg_randu32(&vg.rand) %
vg_list_size(audio_footsteps_wood)],
localplayer.rb.co, 40.0f, 1.0f
);
+++ /dev/null
-#ifndef RESPAWN_C
-#define RESPAWN_C
-
-#if 1
-#include "respawn.h"
-#include "skaterift.h"
-#include "world.h"
-#include "input.h"
-#include "gui.h"
-#include "menu.h"
-#include "scene.h"
-
-static void respawn_chooser_get_dir( v3f dir ){
- /* idk */
- dir[0] = -sqrtf(0.5f);
- dir[2] = sqrtf(0.5f);
- dir[1] = 1.0f;
- v3_normalize(dir);
-}
-
-static void respawn_chooser_get_plane( v4f plane ){
- world_instance *world = &world_static.instances[ respawn_chooser.world_id ];
- f32 h = localplayer.rb.co[1];
- if( respawn_chooser.world_id != world_static.active_instance )
- h = (world->scene_geo.bbx[0][1] + world->scene_geo.bbx[1][1]) * 0.5f;
-
- v4_copy( (v4f){0.0f,1.0f,0.0f,h}, plane );
-}
-
-static void respawn_world_to_plane_pos( v3f pos, v2f plane_pos ){
- v3f dir;
- respawn_chooser_get_dir( dir );
- v3_negate(dir,dir);
- v4f plane;
- respawn_chooser_get_plane( plane );
-
- v3f co;
- f32 t = ray_plane( plane, pos, dir );
- v3_muladds( pos, dir, t, co );
- plane_pos[0] = co[0];
- plane_pos[1] = co[2];
-}
-
-static void respawn_chooser_setworld( u32 next ){
- world_instance *nw = &world_static.instances[next];
- if( nw->status == k_world_status_loaded ){
- respawn_chooser.world_id = next;
-
- v3f target;
- if( next == world_static.active_instance )
- v3_copy( localplayer.rb.co, target );
- else {
- scene_context *sc = &nw->scene_geo;
- v3_lerp( sc->bbx[0], sc->bbx[1], 0.5f, target );
- }
- respawn_world_to_plane_pos( target, respawn_chooser.plane_pos );
- }
-}
-
-static void respawn_chooser_gohome(void){
- respawn_chooser_setworld(0);
- world_instance *world = &world_static.instances[ respawn_chooser.world_id ];
-
- const char **alias = respawn_homes[respawn_chooser.home_select];
- ent_spawn *spawn = world_find_spawn_by_name( world, alias[0] );
-
- if( spawn ){
- respawn_world_to_plane_pos( spawn->transform.co,
- respawn_chooser.plane_pos );
-
- gui_location_print_ccmd( 1, (const char *[]){ alias[1] } );
- }
- else
- gui_location_print_ccmd( 1, (const char *[]){ "Invalid home ID" } );
-}
-
-static void respawn_map_draw_icon( camera *cam,
- enum gui_icon icon, v3f pos ){
- v4f v;
- v3_copy( pos, v );
- v[3] = 1.0f;
- m4x4_mulv( cam->mtx.pv, v, v );
- v2_divs( v, v[3], v );
-
- gui_draw_icon( icon, (v2f){ v[0]*0.5f+0.5f,v[1]*0.5f+0.5f }, 1.0f );
-}
-
-static void respawn_chooser_pre_update(void){
- if( skaterift.activity != k_skaterift_respawning ) return;
-
- if( button_down( k_srbind_mback ) ){
- gui_helper_clear();
- srinput.state = k_input_state_resume;
- skaterift.activity = k_skaterift_menu;
- menu.page = 0xffffffff;
- menu_open_page( "Main Menu", k_ent_menuitem_stack_append );
- return;
- }
-
- if( button_down( k_srbind_maccept ) ){
- skaterift.activity = k_skaterift_default;
- srinput.state = k_input_state_resume;
-
- if( respawn_chooser.spawn ){
- world_static.active_instance = respawn_chooser.world_id;
- player__spawn( respawn_chooser.spawn );
- }
- return;
- }
-
- world_instance *world = &world_static.instances[ respawn_chooser.world_id ];
- v3f *bbx = world->scene_geo.bbx;
- f32 *pos = respawn_chooser.plane_pos;
-
- v2f steer;
- joystick_state( k_srjoystick_steer, steer );
- v2_normalize_clamp( steer );
-
- m2x2f rm;
- m2x2_create_rotation( rm, -0.25f*VG_PIf );
- m2x2_mulv( rm, steer, steer );
-
- v2_muladds( pos, steer, vg.time_frame_delta * 200.0f, pos );
- v2_minv( (v2f){ bbx[1][0], bbx[1][2] }, pos, pos );
- v2_maxv( (v2f){ bbx[0][0], bbx[0][2] }, pos, pos );
-
- /* update camera */
- camera *cam = &respawn_chooser.cam;
- v3f dir;
- respawn_chooser_get_dir(dir);
-
- v4f plane;
- respawn_chooser_get_plane( plane );
-
- v3f co = { pos[0], plane[3]*plane[1], pos[1] };
- v3_muladds( co, dir, respawn_chooser.boom_dist, cam->pos );
-
- vg_line_cross( co, VG__RED, 10.0f );
-
- cam->angles[0] = 0.25f * VG_PIf;
- cam->angles[1] = 0.25f * VG_PIf;
- cam->farz = 5000.0f;
- cam->nearz = 10.0f;
- cam->fov = 40.0f;
-
- camera_update_transform( cam );
- camera_update_view( cam );
- camera_update_projection( cam );
- camera_finalize( cam );
-
- /* pick spawn */
- respawn_chooser.spawn = NULL;
- f32 closest2 = INFINITY;
-
- for( u32 i=0; i<mdl_arrcount(&world->ent_spawn); i++ ){
- ent_spawn *spawn = mdl_arritm(&world->ent_spawn,i);
-
- v4f v;
- v3_copy( spawn->transform.co, v );
- v[3] = 1.0f;
- m4x4_mulv( cam->mtx.pv, v, v );
- v2_divs( v, v[3], v );
-
- f32 d2 = v2_length2(v);
- if( d2 < closest2 ){
- respawn_chooser.spawn = spawn;
- closest2 = d2;
- }
- }
-
- /* icons
- * ---------------------*/
- for( u32 i=0; i<mdl_arrcount(&world->ent_challenge); i++ ){
- ent_challenge *challenge = mdl_arritm( &world->ent_challenge, i );
-
- enum gui_icon icon = k_gui_icon_exclaim_2d;
- if( challenge->status )
- icon = k_gui_icon_tick_2d;
-
- respawn_map_draw_icon( cam, icon, challenge->transform.co );
- }
-
- for( u32 i=0; i<mdl_arrcount(&world->ent_skateshop); i++ ){
- ent_skateshop *shop = mdl_arritm( &world->ent_skateshop, i );
- if( shop->type == k_skateshop_type_boardshop ){
- respawn_map_draw_icon( cam, k_gui_icon_board, shop->transform.co );
- }
- else if( shop->type == k_skateshop_type_worldshop ){
- respawn_map_draw_icon( cam, k_gui_icon_world, shop->transform.co );
- }
- }
-
- for( u32 i=0; i<mdl_arrcount(&world->ent_gate); i++ ){
- ent_gate *gate = mdl_arritm( &world->ent_gate, i );
- if( gate->flags & k_ent_gate_nonlocal ){
- respawn_map_draw_icon( cam, k_gui_icon_rift, gate->co[0] );
- }
- }
-
- for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
- ent_route *route = mdl_arritm( &world->ent_route, i );
-
- v4f colour;
- v4_copy( route->colour, colour );
- v3_muls( colour, 1.6666f, colour );
- gui_icon_setcolour( colour );
- respawn_map_draw_icon( cam, k_gui_icon_rift_run_2d,
- route->board_transform[3] );
- }
-}
-
-static void respawn_begin_chooser(void){
- skaterift.activity = k_skaterift_respawning;
- respawn_chooser.world_id = world_static.active_instance;
-
- world_instance *world = &world_static.instances[ respawn_chooser.world_id ];
- v3f *bbx = world->scene_geo.bbx;
-
- respawn_world_to_plane_pos( localplayer.rb.co, respawn_chooser.plane_pos );
- respawn_chooser.boom_dist = 400.0f;
- respawn_chooser.home_select = 0;
-
- gui_helper_clear();
-
- vg_str text;
- if( gui_new_helper( input_joy_list[k_srjoystick_steer], &text ) )
- vg_strcat( &text, "move" );
-
- if( gui_new_helper( input_button_list[k_srbind_maccept], &text ) )
- vg_strcat( &text, "spawn" );
-
- if( gui_new_helper( input_button_list[k_srbind_mback], &text ) )
- vg_strcat( &text, "exit" );
-}
-
-#if 0
-static void respawn_chooser_shader_uniforms(void){
- v4f uPlayerPos, uSpawnPos;
- v4_zero( uPlayerPos );
- v4_zero( uSpawnPos );
-
- v3_copy( localplayer.rb.co, uPlayerPos );
-
- if( respawn_chooser.spawn )
- v3_copy( respawn_chooser.spawn->transform.co, uSpawnPos );
-
- uPlayerPos[3] = v3_dist(uPlayerPos,uSpawnPos);
- uSpawnPos[3] = 1.0f/uPlayerPos[3];
-
- shader_scene_override_uPlayerPos( uPlayerPos );
- shader_scene_override_uSpawnPos( uSpawnPos );
-}
-#endif
-#endif
-
-#endif /* RESPAWN_C */
+++ /dev/null
-#ifndef RESPAWN_H
-#define RESPAWN_H
-
-#include "skaterift.h"
-
-struct {
- v2f plane_pos;
- f32 boom_dist;
- u32 world_id;
- u32 home_select;
-
- ent_spawn *spawn;
- camera cam;
-}
-static respawn_chooser;
-
-static const char *respawn_homes[][2] = {
- { "skateshop", "Skateshop" },
- { "world_select", "World Selector" },
-};
-
-static void respawn_begin_chooser(void);
-static void respawn_chooser_shader_uniforms(void);
-
-#endif /* RESPAWN_H */
.item_closest = scene_bh_closest,
.item_swap = scene_bh_swap,
.item_debug = scene_bh_debug,
+ .system_type = 0x1
};
/*
* =============================================================================
*/
-#if 1
-
#define SR_NETWORKED
-#define SR_USE_LOCALHOST
+#define VG_AUDIO_FORCE_COMPRESSED
#ifndef VG_RELEASE
#define VG_DEVWINDOW
#include "addon.c"
#include "highscores.c"
#include "save.c"
-#include "respawn.c"
+#include "world_map.c"
#include "network.c"
#include "player_remote.c"
#include "vg/vg_audio_dsp.h"
vg_loader_step( network_init, network_end );
}
-static void load_playermodels(void){
- /* FIXME: hack */
- shader_model_character_view_register();
- shader_model_board_view_register();
- shader_model_entity_register();
-}
-
static void async_skaterift_player_start( void *payload, u32 size ){
world_switch_instance(0);
}
return reg;
}
+static void skaterift_load_world_content(void){
+ /* hub world */
+ addon_reg *hub = skaterift_mount_world_unloadable( "maps/dev_hub", 0 );
+ skaterift_mount_world_unloadable( "maps/mp_spawn",
+ ADDON_REG_CITY|ADDON_REG_PREMIUM );
+ skaterift_mount_world_unloadable( "maps/mp_mtzero",
+ ADDON_REG_MTZERO|ADDON_REG_PREMIUM );
+ skaterift_mount_world_unloadable( "maps/dev_tutorial", 0 );
+
+ world_static.load_state = k_world_loader_load;
+
+ struct world_load_args args = {
+ .purpose = k_world_purpose_hub,
+ .reg = hub
+ };
+ skaterift_world_load_thread( &args );
+}
+
+static void skaterift_load_player_content(void){
+ u32 bytes = 1024*1024*10;
+ skaterift.replay.data = vg_linear_alloc( vg_mem.rtmemory, bytes );
+ skaterift.replay.size = bytes;
+ replay_clear( &skaterift.replay );
+
+ particle_alloc( &particles_grind, 300 );
+
+ player_load_animation_reference( "models/ch_none.mdl" );
+ player_model_load( &localplayer.fallback_model, "models/ch_none.mdl" );
+ player__bind();
+ player_board_load( &localplayer.fallback_board, "models/board_none.mdl" );
+}
+
static void vg_load(void){
if( k_tools_mode ){
vg_async_call( async_call_ready, NULL, 0 );
vg_loader_step( addon_system_init, NULL );
vg_loader_step( workshop_init, NULL );
vg_loader_step( skateshop_init, NULL );
-
- /* ----------------- */
- vg_loader_step( load_playermodels, NULL );
- /* player setup */
- u32 bytes = 1024*1024*10;
- skaterift.replay.data = vg_linear_alloc( vg_mem.rtmemory, bytes );
- skaterift.replay.size = bytes;
- replay_clear( &skaterift.replay );
-
- particle_alloc( &particles_grind, 300 );
-
- player_load_animation_reference( "models/ch_none.mdl" );
- player_model_load( &localplayer.fallback_model, "models/ch_none.mdl" );
- player__bind();
-
- player_board_load( &localplayer.fallback_board, "models/board_none.mdl" );
+ vg_loader_step( skaterift_load_player_content, NULL );
/* --------------------- */
* -------------------------------------
*/
- /* hub world */
- addon_reg *hub = skaterift_mount_world_unloadable( "maps/dev_hub", 0 );
- skaterift_mount_world_unloadable( "maps/mp_spawn",
- ADDON_REG_CITY|ADDON_REG_PREMIUM );
- skaterift_mount_world_unloadable( "maps/mp_mtzero",
- ADDON_REG_MTZERO|ADDON_REG_PREMIUM );
- skaterift_mount_world_unloadable( "maps/dev_tutorial", 0 );
-
/* load home/permanent world manually */
- world_static.load_state = k_world_loader_load;
-
- struct world_load_args args = {
- .purpose = k_world_purpose_hub,
- .reg = hub
- };
- skaterift_world_load_thread( &args );
-
+ vg_loader_step( skaterift_load_world_content, NULL );
vg_async_call( async_skaterift_player_start, NULL, 0 );
vg_async_stall();
/* time rate */
f32 target = 1;
if( skaterift.activity & (k_skaterift_replay|k_skaterift_menu|
- k_skaterift_respawning) ){
+ k_skaterift_world_map) ){
target = 0;
}
world_update( world_current_instance(), localplayer.rb.co );
audio_ambient_sprites_update( world_current_instance(), localplayer.rb.co );
- respawn_chooser_pre_update();
+ world_map_pre_update();
}
static void vg_fixed_update(void){
}
}
- if( skaterift.activity == k_skaterift_respawning ){
+ if( skaterift.activity == k_skaterift_world_map ){
world_instance *world = world_current_instance();
glDrawBuffers( 1, (GLenum[]){ GL_COLOR_ATTACHMENT0 } );
m4x3f identity;
m4x3_identity( identity );
render_world_override( world, world, identity, &skaterift.cam,
- respawn_chooser.spawn,
+ world_map.spawn,
(v4f){world->tar_min, world->tar_max, 1.0f, 0.0f});
render_world_routes( world, world, identity, &skaterift.cam, 0, 1 );
return;
world_instance *view_world = get_view_world();
render_world( view_world, &skaterift.cam, 0, 0, 1, 1 );
-#if 0
- particle_spawn( &particles_grind, localplayer.rb.co,
- (v3f){vg_randf64()*2.0f,vg_randf64()*3.0f,vg_randf64()*2.0f},
- vg_randf64(), 0xff0000ff );
-#endif
particle_system_update( &particles_grind, vg.time_delta );
//particle_system_debug( &particles_grind );
particle_system_prerender( &particles_grind );
skaterift.cam.nearz = 0.1f;
skaterift.cam.farz = 2100.0f;
- if( skaterift.activity == k_skaterift_respawning ){
- camera_copy( &respawn_chooser.cam, &skaterift.cam );
+ if( skaterift.activity == k_skaterift_world_map ){
+ camera_copy( &world_map.cam, &skaterift.cam );
skaterift.cam.nearz = 4.0f;
skaterift.cam.farz = 3100.0f;
}
global_miniworld.t += s * dt;
if( (global_miniworld.t > 1.0f) || (global_miniworld.t < 0.0f) ){
- /* TODO: maybe next frame! */
global_miniworld.t = vg_clampf( global_miniworld.t, 0.0f, 1.0f );
global_miniworld.transition = 0;
}
- else {
- }
}
camera_update_transform( &skaterift.cam );
skaterift_composite_maincamera();
/* --------------------------------------------------------------------- */
- if( skaterift.activity != k_skaterift_respawning ){
+ if( skaterift.activity != k_skaterift_world_map ){
world_instance *world = world_current_instance();
render_world_cubemaps( world );
/* continue with variable rate */
if( !global_miniworld.transition &&
- (skaterift.activity != k_skaterift_respawning) ){
+ (skaterift.activity != k_skaterift_world_map) ){
render_fb_bind( gpipeline.fb_main, 1 );
render_world_gates( get_view_world(), &skaterift.cam );
}
render_view_framebuffer_ui();
remote_player_network_imgui( vg.pv );
- if( skaterift.activity == k_skaterift_respawning ){
+ if( skaterift.activity == k_skaterift_world_map ){
remote_players_imgui_world( world_current_instance(), vg.pv, 2000.0f, 0 );
remote_players_imgui_lobby();
}
remote_players_imgui_world( world_current_instance(), vg.pv, 100.0f, 1 );
}
}
-
-
-#else
-
-#include "skaterift_imgui_dev.c"
-
-#endif
k_skaterift_replay = 0x01,
k_skaterift_ent_focus = 0x02,
k_skaterift_menu = 0x04,
- k_skaterift_respawning = 0x08,
+ k_skaterift_world_map = 0x08,
}
activity;
u32 achievements;
int demo_mode;
+
+ audio_channel *aud_air;
}
static skaterift = {
.op = k_async_op_clientloading, .time_rate = 1.0f, .demo_mode = 1 };
#include "world_water.c"
#include "world_audio.c"
#include "world_routes.c"
-#include "world_traffic.c"
static void world_update( world_instance *world, v3f pos ){
world_render.sky_time += world_render.sky_rate * vg.time_delta;
world_routes_update_timer_texts( world );
world_routes_update( world );
- world_traffic_update( world, pos );
+ ent_traffic_update( world, pos );
world_sfd_update( world, pos );
world_volumes_update( world, pos );
}
k_debug_light_complexity= 0,
k_light_preview = 0;
+#define WORLD_SURFACE_HAS_TRAFFIC 0x1
+#define WORLD_SURFACE_HAS_PROPS 0x2
struct world_instance {
/* Fixed items
mdl_material info;
mdl_submesh sm_geo,
sm_no_collide;
+ u32 flags;
}
* surfaces;
u32 surface_count;
* Trace out a random point, near the player to try and determine water areas
*/
static
-enum audio_sprite_type world_audio_sample_sprite_random(v3f origin, v3f output)
-{
- v3f chance = { (vg_randf64()-0.5f) * 30.0f,
- 8.0f,
- (vg_randf64()-0.5f) * 30.0f };
+enum audio_sprite_type world_audio_sample_sprite_random(v3f origin, v3f output){
+ v3f chance = { (vg_randf64(&vg.rand)-0.5f) * 30.0f,
+ 8,
+ (vg_randf64(&vg.rand)-0.5f) * 30.0f };
v3f pos;
v3_add( chance, origin, pos );
#include "ent_challenge.h"
#include "ent_skateshop.h"
#include "ent_route.h"
+#include "ent_traffic.h"
static void world_entity_focus( u32 entity_id ){
localplayer.immobile = 1;
return rp;
}
-static void ent_volume_call( world_instance *world, ent_call *call )
-{
+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( 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;
+ co[0] = vg_randf64(&vg.rand)*2.0f-1.0f;
+ co[1] = vg_randf64(&vg.rand)*2.0f-1.0f;
+ co[2] = vg_randf64(&vg.rand)*2.0f-1.0f;
m4x3_mulv( volume->to_world, co, co );
call->function = k_ent_function_particle_spawn;
else
return;
- float chance = vg_randf64()*100.0f,
+ float chance = vg_randf64(&vg.rand)*100.0f,
bar = 0.0f;
for( u32 i=0; i<audio->clip_count; i++ ){
* | |
* |________|
*/
-static void world_gen_add_blob( world_instance *world,
+static void world_gen_add_blob( vg_rand *rand, world_instance *world,
scene_context *scene, ray_hit *hit )
{
m4x3f transform;
float angle = v3_dot(hit->normal,(v3f){0.0f,1.0f,0.0f});
q_axis_angle( qsurface, axis, angle );
- q_axis_angle( qrandom, (v3f){0.0f,1.0f,0.0f}, vg_randf64()*VG_TAUf );
+ q_axis_angle( qrandom, (v3f){0.0f,1.0f,0.0f}, vg_randf64(rand)*VG_TAUf );
q_mul( qsurface, qrandom, qsurface );
q_m3x3( qsurface, transform );
v3_copy( hit->pos, transform[3] );
float area = volume[0]*volume[2];
u32 particles = 0.08f * area;
- /* TODO: Quasirandom? */
vg_info( "Map area: %f. Max particles: %u\n", area, particles );
+ u64 t0 = SDL_GetPerformanceCounter();
+#if 0
for( u32 i=0; i<particles; i++ ){
v3f pos;
v3_mul( volume, (v3f){ vg_randf64(), 1000.0f, vg_randf64() }, pos );
}
}
}
+#else
- vg_info( "%d foliage models added\n", count );
+ vg_rand rand;
+ vg_rand_seed( &rand, 3030 );
+
+ const f32 tile_scale = 16.0f;
+ v2i tiles = { volume[0]/tile_scale, volume[2]/tile_scale };
+
+ u32 per_tile = particles/(tiles[0]*tiles[1]);
+
+ for( i32 x=0; x<tiles[0]; x ++ ){
+ for( i32 z=0; z<tiles[1]; z ++ ){
+ for( u32 i=0; i<per_tile; i ++ ){
+ v3f co = { (f32)x+vg_randf64(&rand), 0, (f32)z+vg_randf64(&rand) };
+ v3_muls( co, tile_scale, co );
+ co[1] = 1000.0f;
+ v3_add( co, world->scene_geo.bbx[0], co );
+
+ ray_hit hit;
+ hit.dist = INFINITY;
+
+ if( ray_world( world, co, (v3f){0.0f,-1.0f,0.0f}, &hit,
+ k_material_flag_ghosts )){
+ struct world_surface *m1 = ray_hit_surface( world, &hit );
+ if((hit.normal[1] > 0.8f) && (m1 == mat) &&
+ (hit.pos[1] > 0.0f+10.0f)){
+ world_gen_add_blob( &rand, world, scene, &hit );
+ count ++;
+ }
+ }
+
+ }
+ }
+ }
+
+#endif
+
+
+
+ u64 t1 = SDL_GetPerformanceCounter(),
+ utime_blobs = t1-t0,
+ ufreq = SDL_GetPerformanceFrequency();
+ f64 ftime_blobs = ((f64)utime_blobs / (f64)ufreq)*1000.0;
+
+ vg_info( "%d foliage models added. %f%% (%fms)\n", count,
+ 100.0*((f64)count/(f64)particles), ftime_blobs);
}
static
mdl_submesh *sm = mdl_arritm( &world->meta.submeshs,
vehc->submesh_start+j );
world_unpack_submesh_dynamic( world, &world->scene_no_collide, sm );
+ world->surfaces[ sm->material_id ].flags |= WORLD_SURFACE_HAS_TRAFFIC;
}
}
for( u32 j=0; j<prop->submesh_count; j ++ ){
mdl_submesh *sm = mdl_arritm( &world->meta.submeshs,
prop->submesh_start+j );
+ world->surfaces[ sm->material_id ].flags |= WORLD_SURFACE_HAS_PROPS;
world_unpack_submesh_dynamic( world, &world->scene_no_collide, sm );
}
}
memset( errmat, 0, sizeof(struct world_surface) );
for( u32 i=0; i<mdl_arrcount(&world->meta.materials); i++ ){
- world->surfaces[i+1].info =
- *(mdl_material *)mdl_arritm( &world->meta.materials, i );
+ struct world_surface *surf = &world->surfaces[i+1];
+ surf->info = *(mdl_material *)mdl_arritm( &world->meta.materials, i );
+ surf->flags = 0;
}
}
* load the .mdl file located in path as a world instance
*/
static void world_instance_load_mdl( u32 instance_id, const char *path ){
- vg_rand_seed( 9001 );
-
world_instance *world = &world_static.instances[ instance_id ];
world_init_blank( world );
world->status = k_world_status_loading;
world->time += (world->info.timezone/24.0);
/* process resources from pack */
+ u64 t4 = SDL_GetPerformanceCounter();
world_gen_load_surfaces( world );
+ u64 t5 = SDL_GetPerformanceCounter();
world_gen_routes_ent_init( world );
world_gen_entities_init( world );
+ u64 t6 = SDL_GetPerformanceCounter();
/* main bulk */
+ u64 t0 = SDL_GetPerformanceCounter();
world_gen_generate_meshes( world );
+ u64 t1 = SDL_GetPerformanceCounter();
world_gen_routes_generate( instance_id );
+ u64 t2 = SDL_GetPerformanceCounter();
world_gen_compute_light_indices( world );
+ u64 t3 = SDL_GetPerformanceCounter();
mdl_close( meta );
+ u64 utime_mesh = t1-t0,
+ utime_route = t2-t1,
+ utime_indices = t3-t2,
+ utime_tex = t5-t4,
+ utime_ent = t6-t5,
+ ufreq = SDL_GetPerformanceFrequency();
+
+ f64 ftime_mesh = ((f64)utime_mesh / (f64)ufreq)*1000.0,
+ ftime_route = ((f64)utime_route / (f64)ufreq)*1000.0,
+ ftime_ind = ((f64)utime_route / (f64)ufreq)*1000.0,
+ ftime_tex = ((f64)utime_tex / (f64)ufreq)*1000.0,
+ ftime_ent = ((f64)utime_ent / (f64)ufreq)*1000.0;
+
+ vg_info( "wtime:mesh %.2fms route %.2fms ind %.2fms tex %.2fms ent %.2fms\n",
+ ftime_mesh, ftime_route, ftime_ind, ftime_tex, ftime_ent );
+
/* init player position.
* - this is overriden by the save state when(if) it loads */
ent_spawn *rp = world_find_spawn_by_name( world, "start" );
--- /dev/null
+#ifndef RESPAWN_C
+#define RESPAWN_C
+
+#include "world_map.h"
+#include "skaterift.h"
+#include "world.h"
+#include "input.h"
+#include "gui.h"
+#include "menu.h"
+#include "scene.h"
+
+static void world_map_get_dir( v3f dir ){
+ /* idk */
+ dir[0] = -sqrtf(0.5f);
+ dir[2] = sqrtf(0.5f);
+ dir[1] = 1.0f;
+ v3_normalize(dir);
+}
+
+static void world_map_get_plane( v4f plane ){
+ world_instance *world = &world_static.instances[ world_map.world_id ];
+ f32 h = localplayer.rb.co[1];
+ if( world_map.world_id != world_static.active_instance )
+ h = (world->scene_geo.bbx[0][1] + world->scene_geo.bbx[1][1]) * 0.5f;
+
+ v4_copy( (v4f){0.0f,1.0f,0.0f,h}, plane );
+}
+
+static void respawn_world_to_plane_pos( v3f pos, v2f plane_pos ){
+ v3f dir;
+ world_map_get_dir( dir );
+ v3_negate(dir,dir);
+ v4f plane;
+ world_map_get_plane( plane );
+
+ v3f co;
+ f32 t = ray_plane( plane, pos, dir );
+ v3_muladds( pos, dir, t, co );
+ plane_pos[0] = co[0];
+ plane_pos[1] = co[2];
+}
+
+static void respawn_map_draw_icon( camera *cam,
+ enum gui_icon icon, v3f pos ){
+ v4f v;
+ v3_copy( pos, v );
+ v[3] = 1.0f;
+ m4x4_mulv( cam->mtx.pv, v, v );
+ v2_divs( v, v[3], v );
+
+ gui_draw_icon( icon, (v2f){ v[0]*0.5f+0.5f,v[1]*0.5f+0.5f }, 1.0f );
+}
+
+static void world_map_pre_update(void){
+ if( skaterift.activity != k_skaterift_world_map ) return;
+
+ if( button_down( k_srbind_mback ) ){
+ gui_helper_clear();
+ srinput.state = k_input_state_resume;
+ skaterift.activity = k_skaterift_menu;
+ menu.page = 0xffffffff;
+ menu_open_page( "Main Menu", k_ent_menuitem_stack_append );
+ return;
+ }
+
+ if( button_down( k_srbind_maccept ) ){
+ skaterift.activity = k_skaterift_default;
+ srinput.state = k_input_state_resume;
+
+ if( world_map.spawn ){
+ world_static.active_instance = world_map.world_id;
+ player__spawn( world_map.spawn );
+ }
+ return;
+ }
+
+ world_instance *world = &world_static.instances[ world_map.world_id ];
+ v3f *bbx = world->scene_geo.bbx;
+ f32 *pos = world_map.plane_pos;
+
+ v2f steer;
+ joystick_state( k_srjoystick_steer, steer );
+ v2_normalize_clamp( steer );
+
+ m2x2f rm;
+ m2x2_create_rotation( rm, -0.25f*VG_PIf );
+ m2x2_mulv( rm, steer, steer );
+
+ v2_muladds( pos, steer, vg.time_frame_delta * 200.0f, pos );
+ v2_minv( (v2f){ bbx[1][0], bbx[1][2] }, pos, pos );
+ v2_maxv( (v2f){ bbx[0][0], bbx[0][2] }, pos, pos );
+
+ /* update camera */
+ camera *cam = &world_map.cam;
+ v3f dir;
+ world_map_get_dir(dir);
+
+ v4f plane;
+ world_map_get_plane( plane );
+
+ v3f co = { pos[0], plane[3]*plane[1], pos[1] };
+ v3_muladds( co, dir, world_map.boom_dist, cam->pos );
+
+ vg_line_cross( co, VG__RED, 10.0f );
+
+ cam->angles[0] = 0.25f * VG_PIf;
+ cam->angles[1] = 0.25f * VG_PIf;
+ cam->farz = 5000.0f;
+ cam->nearz = 10.0f;
+ cam->fov = 40.0f;
+
+ camera_update_transform( cam );
+ camera_update_view( cam );
+ camera_update_projection( cam );
+ camera_finalize( cam );
+
+ /* pick spawn */
+ world_map.spawn = NULL;
+ f32 closest2 = INFINITY;
+
+ for( u32 i=0; i<mdl_arrcount(&world->ent_spawn); i++ ){
+ ent_spawn *spawn = mdl_arritm(&world->ent_spawn,i);
+
+ v4f v;
+ v3_copy( spawn->transform.co, v );
+ v[3] = 1.0f;
+ m4x4_mulv( cam->mtx.pv, v, v );
+ v2_divs( v, v[3], v );
+
+ f32 d2 = v2_length2(v);
+ if( d2 < closest2 ){
+ world_map.spawn = spawn;
+ closest2 = d2;
+ }
+ }
+
+ /* icons
+ * ---------------------*/
+ for( u32 i=0; i<mdl_arrcount(&world->ent_challenge); i++ ){
+ ent_challenge *challenge = mdl_arritm( &world->ent_challenge, i );
+
+ enum gui_icon icon = k_gui_icon_exclaim_2d;
+ if( challenge->status )
+ icon = k_gui_icon_tick_2d;
+
+ respawn_map_draw_icon( cam, icon, challenge->transform.co );
+ }
+
+ for( u32 i=0; i<mdl_arrcount(&world->ent_skateshop); i++ ){
+ ent_skateshop *shop = mdl_arritm( &world->ent_skateshop, i );
+ if( shop->type == k_skateshop_type_boardshop ){
+ respawn_map_draw_icon( cam, k_gui_icon_board, shop->transform.co );
+ }
+ else if( shop->type == k_skateshop_type_worldshop ){
+ respawn_map_draw_icon( cam, k_gui_icon_world, shop->transform.co );
+ }
+ }
+
+ for( u32 i=0; i<mdl_arrcount(&world->ent_gate); i++ ){
+ ent_gate *gate = mdl_arritm( &world->ent_gate, i );
+ if( gate->flags & k_ent_gate_nonlocal ){
+ respawn_map_draw_icon( cam, k_gui_icon_rift, gate->co[0] );
+ }
+ }
+
+ for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
+ ent_route *route = mdl_arritm( &world->ent_route, i );
+
+ v4f colour;
+ v4_copy( route->colour, colour );
+ v3_muls( colour, 1.6666f, colour );
+ gui_icon_setcolour( colour );
+ respawn_map_draw_icon( cam, k_gui_icon_rift_run_2d,
+ route->board_transform[3] );
+ }
+}
+
+static void world_map_enter(void){
+ skaterift.activity = k_skaterift_world_map;
+ world_map.world_id = world_static.active_instance;
+
+ world_instance *world = &world_static.instances[ world_map.world_id ];
+ v3f *bbx = world->scene_geo.bbx;
+
+ respawn_world_to_plane_pos( localplayer.rb.co, world_map.plane_pos );
+ world_map.boom_dist = 400.0f;
+ world_map.home_select = 0;
+
+ gui_helper_clear();
+
+ vg_str text;
+ if( gui_new_helper( input_joy_list[k_srjoystick_steer], &text ) )
+ vg_strcat( &text, "move" );
+
+ if( gui_new_helper( input_button_list[k_srbind_maccept], &text ) )
+ vg_strcat( &text, "spawn" );
+
+ if( gui_new_helper( input_button_list[k_srbind_mback], &text ) )
+ vg_strcat( &text, "exit" );
+}
+
+#endif /* RESPAWN_C */
--- /dev/null
+#ifndef RESPAWN_H
+#define RESPAWN_H
+
+#include "skaterift.h"
+
+struct {
+ v2f plane_pos;
+ f32 boom_dist;
+ u32 world_id;
+ u32 home_select;
+
+ ent_spawn *spawn;
+ camera cam;
+}
+static world_map;
+static void world_map_enter(void);
+
+#endif /* RESPAWN_H */
#include "world_render.h"
#include "font.h"
#include "gui.h"
-#include "respawn.h"
+#include "world_map.h"
#include "ent_miniworld.h"
#include "player_remote.h"
#include "ent_skateshop.h"
return 0;
}
-static void async_world_render_init( void *payload, u32 size )
-{
+static void async_world_render_init( void *payload, u32 size ){
vg_info( "Allocate uniform buffers\n" );
for( int i=0; i<k_world_max; i++ ){
world_instance *world = &world_static.instances[i];
}
}
-static void world_render_init(void)
-{
+static void world_render_init(void){
VG_VAR_F32( k_day_length );
VG_VAR_I32( k_debug_light_indices );
VG_VAR_I32( k_debug_light_complexity );
vg_async_call( async_world_render_init, NULL, 0 );
}
+/*
+ * standard uniform bindings
+ * ----------------------------------------------------------------------------
+ */
static void world_link_lighting_ub( world_instance *world, GLuint shader ){
GLuint idx = glGetUniformBlockIndex( shader, "ub_world_lighting" );
glUniformBlockBinding( shader, idx, world->ubo_bind_point );
glUniform1i( location, slot );
}
-static void render_world_depth( world_instance *world, camera *cam );
-
-/*
- * Rendering
- */
-
static void bind_terrain_noise(void){
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, world_render.tex_terrain_noise );
}
+/*
+ * Get OpenGL texture name from texture ID.
+ */
+static GLuint world_get_texture( world_instance *world, u32 id ){
+ if( id & 0x80000000 ) return skaterift.rt_textures[id & ~0x80000000];
+ else return world->textures[ id ];
+}
+
+static void bindpoint_diffuse_texture1( world_instance *world,
+ struct world_surface *mat ){
+ glActiveTexture( GL_TEXTURE1 );
+ glBindTexture( GL_TEXTURE_2D,
+ world_get_texture(world,mat->info.tex_diffuse) );
+}
+
+/*
+ * Passes Rendering
+ * ----------------------------------------------------------------------------
+ */
+
struct world_pass{
camera *cam;
enum mdl_shader shader;
void (*fn_set_uNormalMtx)( m3x3f mnorm );
};
-/* FIXME: we gotta do something about this crap, maybe batch lists. something..
- * anything but this. */
-static
-void world_render_props( world_instance *world, u32 material_id,
- struct world_pass *pass ){
- if( !mdl_arrcount( &world->ent_prop ) ) return;
+static void render_world_depth( world_instance *world, camera *cam );
+
+/*
+ * Render a run of submeshes, only of those which match material_id
+ */
+static void world_render_submeshes( world_instance *world,
+ struct world_pass *pass,
+ mdl_transform *transform,
+ u32 start, u32 count, u32 material_id ){
+ for( u32 k=0; k<count; k++ ){
+ mdl_submesh *sm = mdl_arritm( &world->meta.submeshs, start+k );
+ if( sm->material_id != material_id ) continue;
+
+ m4x3f mmdl;
+ mdl_transform_m4x3( transform, mmdl );
+ m4x4f m4mdl;
+ m4x3_expand( mmdl, m4mdl );
+ m4x4_mul( pass->cam->mtx_prev.pv, m4mdl, m4mdl );
+
+ pass->fn_set_mdl( mmdl );
+ pass->fn_set_uPvmPrev( m4mdl );
+
+ mdl_draw_submesh( sm );
+ }
+}
+/*
+ * Render props attached to this material
+ */
+static void world_render_props( world_instance *world, u32 material_id,
+ struct world_pass *pass ){
struct world_surface *mat = &world->surfaces[ material_id ];
+ if( !(mat->flags & WORLD_SURFACE_HAS_PROPS) ) return;
+
pass->fn_bind_textures( world, mat );
for( u32 j=0; j<mdl_arrcount( &world->ent_prop ); j++ ){
ent_prop *prop = mdl_arritm( &world->ent_prop, j );
if( prop->flags & 0x1 ) continue;
-
- for( u32 k=0; k<prop->submesh_count; k++ ){
- mdl_submesh *sm =
- mdl_arritm( &world->meta.submeshs, prop->submesh_start+k );
-
- if( sm->material_id != material_id ) continue;
-
- m4x3f mmdl;
- mdl_transform_m4x3( &prop->transform, mmdl );
-
- m4x4f m4mdl;
- m4x3_expand( mmdl, m4mdl );
- m4x4_mul( pass->cam->mtx_prev.pv, m4mdl, m4mdl );
-
- pass->fn_set_mdl( mmdl );
- pass->fn_set_uPvmPrev( m4mdl );
- mdl_draw_submesh( sm );
- }
+ world_render_submeshes( world, pass, &prop->transform,
+ prop->submesh_start, prop->submesh_count, material_id );
}
}
-static
-void world_render_traffic( world_instance *world, u32 material_id,
- struct world_pass *pass ){
- if( !mdl_arrcount( &world->ent_traffic ) ) return;
-
- /* HACK: use the first material for every traffic entity */
- ent_traffic *first = mdl_arritm( &world->ent_traffic, 0 );
- if( !first->submesh_count ) return;
-
- mdl_submesh *sm = mdl_arritm( &world->meta.submeshs, first->submesh_start );
- if( sm->material_id != material_id ) return;
-
+/*
+ * Render traffic models attactched to this material
+ */
+static void world_render_traffic( world_instance *world, u32 material_id,
+ struct world_pass *pass ){
struct world_surface *mat = &world->surfaces[ material_id ];
+ if( !(mat->flags & WORLD_SURFACE_HAS_TRAFFIC) ) return;
+
pass->fn_bind_textures( world, mat );
for( u32 j=0; j<mdl_arrcount( &world->ent_traffic ); j++ ){
ent_traffic *traffic = mdl_arritm( &world->ent_traffic, j );
-
- for( u32 k=0; k<traffic->submesh_count; k++ ){
- sm = mdl_arritm( &world->meta.submeshs,
- traffic->submesh_start+k );
-
- m4x3f mmdl;
- q_m3x3( traffic->transform.q, mmdl );
- v3_copy( traffic->transform.co, mmdl[3] );
-
- m4x4f m4mdl;
- m4x3_expand( mmdl, m4mdl );
- m4x4_mul( pass->cam->mtx_prev.pv, m4mdl, m4mdl );
- pass->fn_set_mdl( mmdl );
- pass->fn_set_uPvmPrev( m4mdl );
-
- mdl_draw_submesh( sm );
- }
+ world_render_submeshes( world, pass, &traffic->transform,
+ traffic->submesh_start, traffic->submesh_count,
+ material_id );
}
}
-static
-void world_render_pass( world_instance *world, struct world_pass *pass ){
+/*
+ * Iterate and render all materials which match the passes shader and geometry
+ * type. Includes props/traffic.
+ */
+static void world_render_pass( world_instance *world, struct world_pass *pass ){
for( int i=0; i<world->surface_count; i++ ){
struct world_surface *mat = &world->surfaces[i];
}
}
-static
-void world_render_both_stages( world_instance *world, struct world_pass *pass )
-{
+/*
+ * Specific shader instructions
+ * ----------------------------------------------------------------------------
+ */
+
+static void world_render_both_stages( world_instance *world,
+ struct world_pass *pass ){
mesh_bind( &world->mesh_geo );
pass->geo_type = k_world_geo_type_solid;
world_render_pass( world, pass );
glEnable( GL_CULL_FACE );
}
-static GLuint world_get_texture( world_instance *world, u32 id ){
- if( id & 0x80000000 )
- return skaterift.rt_textures[id & ~0x80000000];
- else
- return world->textures[ id ];
-}
-
-static void bindpoint_diffuse_texture1( world_instance *world,
- struct world_surface *mat ){
- glActiveTexture( GL_TEXTURE1 );
- glBindTexture( GL_TEXTURE_2D,
- world_get_texture(world,mat->info.tex_diffuse) );
-}
-
-static void bindpoint_diffuse1_and_cubemap10( world_instance *world,
- struct world_surface *mat ){
- glActiveTexture( GL_TEXTURE1 );
- glBindTexture( GL_TEXTURE_2D,
- world_get_texture(world,mat->info.tex_diffuse) );
-
- u32 cubemap_id = mat->info.tex_none0,
- cubemap_index = 0;
-
- if( mdl_entity_id_type( cubemap_id ) == k_ent_cubemap ){
- cubemap_index = mdl_entity_id_id( cubemap_id );
- }
-
- ent_cubemap *cm = mdl_arritm( &world->ent_cubemap, cubemap_index );
- glActiveTexture( GL_TEXTURE10 );
- glBindTexture( GL_TEXTURE_CUBE_MAP, cm->texture_id );
-
- shader_scene_cubemapped_uColour( mat->info.colour );
-}
-
static void render_world_vb( world_instance *world, camera *cam ){
shader_scene_vertex_blend_use();
shader_scene_vertex_blend_uTexGarbage(0);
shader_scene_vertex_blend_uTexGradients(1);
- world_link_lighting_ub( world, _shader_scene_vertex_blend.id );
- world_bind_position_texture( world, _shader_scene_vertex_blend.id,
- _uniform_scene_vertex_blend_g_world_depth, 2 );
- world_bind_light_array( world, _shader_scene_vertex_blend.id,
- _uniform_scene_vertex_blend_uLightsArray, 3 );
- world_bind_light_index( world, _shader_scene_vertex_blend.id,
- _uniform_scene_vertex_blend_uLightsIndex, 4 );
+ WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_vertex_blend );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, world_render.tex_terrain_noise );
shader_scene_standard_uTexGarbage(0);
shader_scene_standard_uTexMain(1);
shader_scene_standard_uPv( cam->mtx.pv );
-
- world_link_lighting_ub( world, _shader_scene_standard.id );
- world_bind_position_texture( world, _shader_scene_standard.id,
- _uniform_scene_standard_g_world_depth, 2 );
- world_bind_light_array( world, _shader_scene_standard.id,
- _uniform_scene_standard_uLightsArray, 3 );
- world_bind_light_index( world, _shader_scene_standard.id,
- _uniform_scene_standard_uLightsIndex, 4 );
+ WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_standard );
bind_terrain_noise();
shader_scene_standard_uCamera( cam->transform[3] );
world_render_both_stages( world, &pass );
}
+static void bindpoint_diffuse1_and_cubemap10( world_instance *world,
+ struct world_surface *mat ){
+ glActiveTexture( GL_TEXTURE1 );
+ glBindTexture( GL_TEXTURE_2D,
+ world_get_texture(world,mat->info.tex_diffuse) );
+
+ u32 cubemap_id = mat->info.tex_none0,
+ cubemap_index = 0;
+
+ if( mdl_entity_id_type( cubemap_id ) == k_ent_cubemap ){
+ cubemap_index = mdl_entity_id_id( cubemap_id );
+ }
+
+ ent_cubemap *cm = mdl_arritm( &world->ent_cubemap, cubemap_index );
+ glActiveTexture( GL_TEXTURE10 );
+ glBindTexture( GL_TEXTURE_CUBE_MAP, cm->texture_id );
+
+ shader_scene_cubemapped_uColour( mat->info.colour );
+}
+
static void render_world_cubemapped( world_instance *world, camera *cam,
int enabled ){
if( !mdl_arrcount( &world->ent_cubemap ) )
shader_scene_cubemapped_uTexCubemap(10);
shader_scene_cubemapped_uPv( cam->mtx.pv );
- world_link_lighting_ub( world, _shader_scene_cubemapped.id );
- world_bind_position_texture( world, _shader_scene_cubemapped.id,
- _uniform_scene_cubemapped_g_world_depth, 2 );
- world_bind_light_array( world, _shader_scene_cubemapped.id,
- _uniform_scene_cubemapped_uLightsArray, 3 );
- world_bind_light_index( world, _shader_scene_cubemapped.id,
- _uniform_scene_cubemapped_uLightsIndex, 4 );
+ WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_cubemapped );
bind_terrain_noise();
shader_scene_cubemapped_uCamera( cam->transform[3] );
shader_scene_standard_alphatest_uTexMain(1);
shader_scene_standard_alphatest_uPv( cam->mtx.pv );
- world_link_lighting_ub( world, _shader_scene_standard_alphatest.id );
- world_bind_position_texture( world, _shader_scene_standard_alphatest.id,
- _uniform_scene_standard_alphatest_g_world_depth, 2 );
- world_bind_light_array( world, _shader_scene_standard_alphatest.id,
- _uniform_scene_standard_alphatest_uLightsArray, 3 );
- world_bind_light_index( world, _shader_scene_standard_alphatest.id,
- _uniform_scene_standard_alphatest_uLightsIndex, 4 );
-
+ WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_standard_alphatest );
bind_terrain_noise();
-
-
shader_scene_standard_alphatest_uCamera( cam->transform[3] );
-
glDisable(GL_CULL_FACE);
struct world_pass pass = {
};
world_render_both_stages( world, &pass );
-
glEnable(GL_CULL_FACE);
}
shader_scene_fxglow_uUvOffset( (v2f){ 0.0f, 0.0f } );
shader_scene_fxglow_uTexMain(1);
shader_scene_fxglow_uPv( cam->mtx.pv );
-
- world_link_lighting_ub( host_world, _shader_scene_fxglow.id );
- world_bind_position_texture( host_world, _shader_scene_fxglow.id,
- _uniform_scene_fxglow_g_world_depth, 2 );
- world_bind_light_array( host_world, _shader_scene_fxglow.id,
- _uniform_scene_fxglow_uLightsArray, 3 );
- world_bind_light_index( host_world, _shader_scene_fxglow.id,
- _uniform_scene_fxglow_uLightsIndex, 4 );
+ WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, scene_fxglow );
shader_scene_fxglow_uCamera( cam->transform[3] );
glDisable(GL_CULL_FACE);
static void render_world_override_pass( world_instance *world,
struct world_pass *pass,
m4x3f mmdl, m3x3f mnormal,
- m4x4f mpvm_prev ){
+ m4x4f mpvm_prev ){
for( int i=0; i<world->surface_count; i++ ){
struct world_surface *mat = &world->surfaces[i];
-
if( mat->info.flags & k_material_flag_ghosts ) continue;
mdl_submesh *sm;
}
}
+/*
+ * Geo shaders
+ * ---------------------------------------------
+ */
+
static void render_world_depth( world_instance *world, camera *cam ){
m4x3f identity_matrix;
m4x3_identity( identity_matrix );
vg_info( "Generating route meshes\n" );
vg_async_stall();
- vg_rand_seed( 2000 );
vg_async_item *call_scene = scene_alloc_async( &world->scene_lines,
&world->mesh_route_lines,
200000, 300000 );
rb_presolve_contacts( rb_contact_buffer, rb_contact_count );
for( int i=0; i<rb_contact_count; i++ ){
- rb_contact_restitution( rb_contact_buffer+i, vg_randf64() );
+ rb_contact_restitution( rb_contact_buffer+i, vg_randf64(&vg.rand) );
}
for( int i=0; i<6; i++ ){
v3_muls( origin, -1.0f, particle->mlocal[3] );
v3_copy( world_co, particle->obj.rb.co );
- v3_muls( imp_v, 1.0f+vg_randf64(), particle->obj.rb.v );
+ v3_muls( imp_v, 1.0f+vg_randf64(&vg.rand), particle->obj.rb.v );
particle->obj.rb.v[1] += 2.0f;
v4_copy( q, particle->obj.rb.q );
- particle->obj.rb.w[0] = vg_randf64()*2.0f-1.0f;
- particle->obj.rb.w[1] = vg_randf64()*2.0f-1.0f;
- particle->obj.rb.w[2] = vg_randf64()*2.0f-1.0f;
+ particle->obj.rb.w[0] = vg_randf64(&vg.rand)*2.0f-1.0f;
+ particle->obj.rb.w[1] = vg_randf64(&vg.rand)*2.0f-1.0f;
+ particle->obj.rb.w[2] = vg_randf64(&vg.rand)*2.0f-1.0f;
particle->obj.type = k_rb_shape_sphere;
particle->obj.inf.sphere.radius = r*0.6f;
+++ /dev/null
-#ifndef WORLD_TRAFFIC_C
-#define WORLD_TRAFFIC_C
-
-#include "world.h"
-
-static void world_traffic_update( world_instance *world, v3f pos ){
- for( u32 i=0; i<mdl_arrcount( &world->ent_traffic ); i++ ){
- ent_traffic *traffic = mdl_arritm( &world->ent_traffic, i );
-
- u32 i1 = traffic->index,
- i0,
- i2 = i1+1;
-
- if( i1 == 0 ) i0 = traffic->node_count-1;
- else i0 = i1-1;
-
- if( i2 >= traffic->node_count ) i2 = 0;
-
- i0 += traffic->start_node;
- i1 += traffic->start_node;
- i2 += traffic->start_node;
-
- v3f h[3];
-
- ent_route_node *rn0 = mdl_arritm( &world->ent_route_node, i0 ),
- *rn1 = mdl_arritm( &world->ent_route_node, i1 ),
- *rn2 = mdl_arritm( &world->ent_route_node, i2 );
-
- v3_copy( rn1->co, h[1] );
- v3_lerp( rn0->co, rn1->co, 0.5f, h[0] );
- v3_lerp( rn1->co, rn2->co, 0.5f, h[2] );
-
- float const k_sample_dist = 0.0025f;
- v3f pc, pd;
- eval_bezier3( h[0], h[1], h[2], traffic->t, pc );
- eval_bezier3( h[0], h[1], h[2], traffic->t+k_sample_dist, pd );
-
- v3f v0;
- v3_sub( pd, pc, v0 );
- float length = vg_maxf( 0.0001f, v3_length( v0 ) );
- v3_muls( v0, 1.0f/length, v0 );
-
- float mod = k_sample_dist / length;
-
- traffic->t += traffic->speed * vg.time_delta * mod;
-
- if( traffic->t > 1.0f ){
- traffic->t -= 1.0f;
-
- if( traffic->t > 1.0f ) traffic->t = 0.0f;
-
- traffic->index ++;
-
- if( traffic->index >= traffic->node_count )
- traffic->index = 0;
- }
-
- v3_copy( pc, traffic->transform.co );
-
- float a = atan2f( -v0[0], v0[2] );
- q_axis_angle( traffic->transform.q, (v3f){0.0f,1.0f,0.0f}, -a );
-
- vg_line_point( traffic->transform.co, 0.3f, VG__BLUE );
- }
-}
-
-#endif /* WORLD_TRAFFIC_C */