+
+ sfd_update( &world.sfd.tester );
+
+#if 0
+ rb_solver_reset();
+ rb_build_manifold_terrain_sphere( &world.mr_ball );
+
+ for( int i=0; i<5; i++ )
+ rb_solve_contacts( rb_contact_buffer, rb_contact_count );
+
+ rb_iter( &world.mr_ball );
+ rb_update_transform( &world.mr_ball );
+ rb_debug( &world.mr_ball, 0 );
+
+ for( int i=0; i<vg_list_size(world.van_man); i++ )
+ {
+ traffic_drive( &world.van_man[i] );
+ traffic_visualize_car( &world.van_man[i] );
+ }
+#endif
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * API implementation
+ * -----------------------------------------------------------------------------
+ */
+
+static void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
+{
+ for( int i=0; i<3; i++ )
+ v3_copy( world.geo.verts[ hit->tri[i] ].co, tri[i] );
+}
+
+static int ray_world( v3f pos, v3f dir, ray_hit *hit )
+{
+ return scene_raycast( &world.geo, pos, dir, hit );
+}
+
+static int ray_hit_is_terrain( ray_hit *hit )
+{
+ u32 valid_start = 0,
+ valid_end = world.sm_terrain.vertex_count;
+
+ return (hit->tri[0] >= valid_start) &&
+ (hit->tri[0] < valid_end);
+}
+
+static int ray_hit_is_ramp( ray_hit *hit )
+{
+ u32 valid_start = world.sm_geo_std.vertex_start,
+ valid_end = world.sm_geo_vb.vertex_start;