?
authorhgn <hgodden00@gmail.com>
Sat, 21 Jan 2023 22:25:54 +0000 (22:25 +0000)
committerhgn <hgodden00@gmail.com>
Sat, 21 Jan 2023 22:25:54 +0000 (22:25 +0000)
bvh.h
player_physics.h
skaterift.c
vehicle.h [new file with mode: 0644]
world_gen.h

diff --git a/bvh.h b/bvh.h
index e79e3ddc6866ab7d012bfd30952d0fc8eebc3230..8b6b0784785973f1adf89ddbbb01636d656f1d64 100644 (file)
--- a/bvh.h
+++ b/bvh.h
@@ -232,11 +232,16 @@ VG_STATIC int bh_ray( bh_tree *bh, v3f co, v3f dir, ray_hit *hit )
    stack[0] = 0;
    stack[1] = bh->nodes[0].il;
    stack[2] = bh->nodes[0].ir;
+
+   v3f dir_inv;
+   dir_inv[0] = 1.0f/dir[0];
+   dir_inv[1] = 1.0f/dir[1];
+   dir_inv[2] = 1.0f/dir[2];
    
    while(depth)
    {
       bh_node *inode = &bh->nodes[ stack[depth] ];
-      if( ray_aabb( inode->bbx, co, dir, hit->dist ) )
+      if( ray_aabb1( inode->bbx, co, dir_inv, hit->dist ) )
       {
          if( inode->count )
          {
index 6afc1b2c43b0f3e1cf560e83ca1baceb9836a05b..31590d8fb36bb34aab8c1cf75b67b8045b4837af 100644 (file)
@@ -80,6 +80,11 @@ VG_STATIC int spherecast_world( v3f pa, v3f pb, float r, float *t, v3f n )
    v3f dir;
    v3_sub( pb, pa, dir );
 
+   v3f dir_inv;
+   dir_inv[0] = 1.0f/dir[0];
+   dir_inv[1] = 1.0f/dir[1];
+   dir_inv[2] = 1.0f/dir[2];
+
    int hit = -1;
    float min_t = 1.0f;
 
@@ -100,7 +105,8 @@ VG_STATIC int spherecast_world( v3f pa, v3f pb, float r, float *t, v3f n )
 
       v3_add( (v3f){ r, r, r}, box[1], box[1] );
       v3_add( (v3f){-r,-r,-r}, box[0], box[0] );
-      if( !ray_aabb( box, pa, dir, 1.0f ) )
+
+      if( !ray_aabb1( box, pa, dir_inv, 1.0f ) )
          continue;
       
       float t;
index b72100a71e8a1da31eed74f41725eab2853d08ba..130bedfe14716564cb17662aa6e2f3d24bb4b75b 100644 (file)
@@ -21,6 +21,7 @@
 #include "player.h"
 #include "network.h"
 #include "menu.h"
+#include "vehicle.h"
 
 static int cl_ui      = 1,
            cl_view_id = 0,
@@ -98,6 +99,7 @@ VG_STATIC void vg_load(void)
    vg_loader_step( menu_init, NULL );
    vg_loader_step( world_init, NULL );
    vg_loader_step( player_init, NULL );
+   vg_loader_step( vehicle_init, NULL );
 
    vg_bake_shaders();
    vg_loader_step( audio_init, audio_free );
@@ -105,7 +107,7 @@ VG_STATIC void vg_load(void)
 
    /* 'systems' are completely loaded now */
    strcpy( world.world_name, "maps/mp_mtzero.mdl" );
-   //strcpy( world.world_name, "maps/mp_gridmap.mdl" );
+   strcpy( world.world_name, "maps/mp_gridmap.mdl" );
    world_load();
    vg_console_load_autos();
 }
@@ -141,6 +143,7 @@ VG_STATIC void vg_update_fixed(void)
    if( vg.is_loaded )
    {
       player_update_fixed();
+      vehicle_update_fixed();
    }
 }
 
@@ -150,6 +153,7 @@ VG_STATIC void vg_update_post(void)
    {
       player_update_post();
       menu_update();
+      vehicle_update_post();
    }
 }
 
diff --git a/vehicle.h b/vehicle.h
new file mode 100644 (file)
index 0000000..a08871c
--- /dev/null
+++ b/vehicle.h
@@ -0,0 +1,301 @@
+#ifndef VEHICLE_H
+#define VEHICLE_H
+
+#define VG_GAME
+#include "vg/vg.h"
+#include "rigidbody.h"
+#include "world.h"
+#include "player_physics.h"
+
+VG_STATIC float k_car_spring = 1.0f,
+                k_car_spring_damp = 0.001f,
+                k_car_spring_length = 0.5f,
+                k_car_wheel_radius = 0.2f,
+                k_car_friction_lat = 0.6f,
+                k_car_friction_roll = 0.01f,
+                k_car_drive_force = 1.0f,
+                k_car_air_resistance = 0.1f;
+
+VG_STATIC struct gvehicle
+{
+   int alive, inside;
+   rigidbody rb;
+
+   v3f wheels[4];
+
+   float tangent_mass[4][2],
+         normal_forces[4],
+         tangent_forces[4][2];
+
+   float steer, drive;
+   v3f steerv;
+
+   v3f   tangent_vectors[4][2];
+   v3f   wheels_local[4];
+}
+gzoomer =
+{
+   .rb = { .type = k_rb_shape_sphere, .inf.sphere.radius = 1.0f }
+};
+
+VG_STATIC int spawn_car( int argc, const char *argv[] )
+{
+   v3f ra, rb, rx;
+   v3_copy( main_camera.pos, ra );
+   v3_muladds( ra, main_camera.transform[2], -10.0f, rb );
+
+   float t;
+   if( spherecast_world( ra, rb, gzoomer.rb.inf.sphere.radius, &t, rx ) != -1 )
+   {
+      v3_lerp( ra, rb, t, gzoomer.rb.co );
+      gzoomer.rb.co[1] += 4.0f;
+      q_axis_angle( gzoomer.rb.q, (v3f){1.0f,0.0f,0.0f}, 0.001f );
+      v3_zero( gzoomer.rb.v );
+      v3_zero( gzoomer.rb.w );
+      
+      rb_update_transform( &gzoomer.rb );
+      gzoomer.alive = 1;
+
+      vg_success( "Spawned car\n" );
+   }
+   else
+   {
+      vg_error( "Can't spawn here\n" );
+   }
+
+   return 0;
+}
+
+VG_STATIC void vehicle_init(void)
+{
+   q_identity( gzoomer.rb.q );
+   rb_init( &gzoomer.rb );
+
+   VG_VAR_F32_PERSISTENT( k_car_spring );
+   VG_VAR_F32_PERSISTENT( k_car_spring_damp );
+   VG_VAR_F32_PERSISTENT( k_car_spring_length );
+   VG_VAR_F32_PERSISTENT( k_car_wheel_radius );
+   VG_VAR_F32_PERSISTENT( k_car_friction_lat );
+   VG_VAR_F32_PERSISTENT( k_car_friction_roll );
+   VG_VAR_F32_PERSISTENT( k_car_drive_force );
+   VG_VAR_F32_PERSISTENT( k_car_air_resistance );
+
+       vg_function_push( (struct vg_cmd){
+               .name = "spawn_car",
+               .function = spawn_car
+       });
+
+   v3_copy((v3f){ -1.0f, -0.25f, -1.0f }, gzoomer.wheels_local[0] );
+   v3_copy((v3f){  1.0f, -0.25f, -1.0f }, gzoomer.wheels_local[1] );
+   v3_copy((v3f){ -1.0f, -0.25f,  1.0f }, gzoomer.wheels_local[2] );
+   v3_copy((v3f){  1.0f, -0.25f,  1.0f }, gzoomer.wheels_local[3] );
+}
+
+VG_STATIC void vehicle_wheel_force( int index )
+{
+   v3f pa, pb, n;
+   m4x3_mulv( gzoomer.rb.to_world, gzoomer.wheels_local[index], pa );
+   v3_muladds( pa, gzoomer.rb.up, -k_car_spring_length, pb );
+
+
+#if 1
+   float t;
+   if( spherecast_world( pa, pb, k_car_wheel_radius, &t, n ) == -1 )
+      t = 1.0f;
+
+#else
+
+   v3f dir;
+   v3_muls( gzoomer.rb.up, -1.0f, dir );
+   
+   ray_hit hit;
+   hit.dist = k_car_spring_length;
+   ray_world( pa, dir, &hit );
+
+   float t = hit.dist / k_car_spring_length;
+
+#endif
+
+   v3f pc;
+   v3_lerp( pa, pb, t, pc );
+
+   m4x3f mtx;
+   m3x3_copy( gzoomer.rb.to_world, mtx );
+   v3_copy( pc, mtx[3] );
+   debug_sphere( mtx, k_car_wheel_radius, VG__BLACK );
+   vg_line( pa, pc, VG__WHITE );
+   v3_copy( pc, gzoomer.wheels[index] );
+
+   if( t < 1.0f )
+   {
+      /* spring force */
+      float Fv = (1.0f-t) * k_car_spring*k_rb_delta;
+      
+      v3f delta;
+      v3_sub( pa, gzoomer.rb.co, delta );
+
+      v3f rv;
+      v3_cross( gzoomer.rb.w, delta, rv );
+      v3_add( gzoomer.rb.v, rv, rv );
+
+      Fv += v3_dot( rv, gzoomer.rb.up ) * -k_car_spring_damp*k_rb_delta;
+
+      /* scale by normal incident */
+      Fv *= v3_dot( n, gzoomer.rb.up );
+
+      v3f F;
+      v3_muls( gzoomer.rb.up, Fv, F );
+
+      rb_linear_impulse( &gzoomer.rb, delta, F );
+
+      /* friction vectors
+       * -------------------------------------------------------------*/
+      v3f tx, ty;
+      
+      if( index <= 1 )
+         v3_cross( gzoomer.steerv, n, tx );
+      else
+         v3_cross( gzoomer.rb.forward, n, tx );
+      v3_cross( tx, n, ty );
+
+      v3_copy( tx, gzoomer.tangent_vectors[ index ][0] );
+      v3_copy( ty, gzoomer.tangent_vectors[ index ][1] );
+
+      gzoomer.normal_forces[ index ] = Fv;
+      gzoomer.tangent_forces[ index ][0] = 0.0f;
+      gzoomer.tangent_forces[ index ][1] = 0.0f;
+
+      /* orient inverse inertia tensors */
+      v3f raW;
+      m3x3_mulv( gzoomer.rb.to_world, gzoomer.wheels_local[index], raW );
+
+      v3f raCtx, raCtxI, raCty, raCtyI;
+      v3_cross( tx, raW, raCtx );
+      v3_cross( ty, raW, raCty );
+      m3x3_mulv( gzoomer.rb.iIw, raCtx, raCtxI );
+      m3x3_mulv( gzoomer.rb.iIw, raCty, raCtyI );
+
+      gzoomer.tangent_mass[index][0] = gzoomer.rb.inv_mass;
+      gzoomer.tangent_mass[index][0] += v3_dot( raCtx, raCtxI );
+      gzoomer.tangent_mass[index][0] = 1.0f/gzoomer.tangent_mass[index][0];
+      
+      gzoomer.tangent_mass[index][1] = gzoomer.rb.inv_mass;
+      gzoomer.tangent_mass[index][1] += v3_dot( raCty, raCtyI );
+      gzoomer.tangent_mass[index][1] = 1.0f/gzoomer.tangent_mass[index][1];
+
+      /* apply drive force */
+      if( index >= 2 )
+      {
+         v3_muls( ty, gzoomer.drive * k_car_drive_force * k_rb_delta, F );
+         rb_linear_impulse( &gzoomer.rb, raW, F );
+      }
+   }
+   else
+   {
+      gzoomer.normal_forces[ index ] = 0.0f;
+      gzoomer.tangent_forces[ index ][0] = 0.0f;
+      gzoomer.tangent_forces[ index ][1] = 0.0f;
+   }
+}
+
+VG_STATIC void vehicle_solve_friction(void)
+{
+   for( int i=0; i<4; i++ )
+   {
+      v3f raW;
+      m3x3_mulv( gzoomer.rb.to_world, gzoomer.wheels_local[i], raW );
+
+      v3f rv;
+      v3_cross( gzoomer.rb.w, raW, rv );
+      v3_add( gzoomer.rb.v, rv, rv );
+
+      float     fx = k_car_friction_lat * gzoomer.normal_forces[i],
+                fy = k_car_friction_roll * gzoomer.normal_forces[i],
+               vtx = v3_dot( rv, gzoomer.tangent_vectors[i][0] ),
+               vty = v3_dot( rv, gzoomer.tangent_vectors[i][1] ),
+           lambdax = gzoomer.tangent_mass[i][0] * -vtx,
+           lambday = gzoomer.tangent_mass[i][1] * -vty;
+      
+      float tempx = gzoomer.tangent_forces[i][0],
+            tempy = gzoomer.tangent_forces[i][1];
+      gzoomer.tangent_forces[i][0] = vg_clampf( tempx + lambdax, -fx, fx );
+      gzoomer.tangent_forces[i][1] = vg_clampf( tempy + lambday, -fy, fy );
+      lambdax = gzoomer.tangent_forces[i][0] - tempx;
+      lambday = gzoomer.tangent_forces[i][1] - tempy;
+
+      v3f impulsex, impulsey;
+      v3_muls( gzoomer.tangent_vectors[i][0], lambdax, impulsex );
+      v3_muls( gzoomer.tangent_vectors[i][1], lambday, impulsey );
+      rb_linear_impulse( &gzoomer.rb, raW, impulsex );
+      rb_linear_impulse( &gzoomer.rb, raW, impulsey );
+   }
+}
+
+VG_STATIC void vehicle_update_fixed(void)
+{
+   if( !gzoomer.alive )
+      return;
+
+   gzoomer.steer = vg_lerpf( gzoomer.steer, 
+                             player.input_walkh->axis.value * 0.2f,
+                             k_rb_delta * 8.0f );
+
+   gzoomer.drive = player.input_walkv->axis.value * k_car_drive_force;
+   v3_muls( gzoomer.rb.forward, cosf(gzoomer.steer), gzoomer.steerv );
+   v3_muladds( gzoomer.steerv, gzoomer.rb.right, 
+               sinf(gzoomer.steer), gzoomer.steerv );
+
+   /* apply air resistance */
+   v3_muladds( gzoomer.rb.v, gzoomer.rb.v, 
+               -k_car_air_resistance * k_rb_delta, gzoomer.rb.v );
+   
+   for( int i=0; i<4; i++ )
+      vehicle_wheel_force( i );
+
+   rb_ct manifold[64];
+
+   int len = rb_sphere_scene( &gzoomer.rb, &world.rb_geo, manifold );
+   rb_manifold_filter_coplanar( manifold, len, 0.05f );
+
+   if( len > 1 )
+   {
+      rb_manifold_filter_backface( manifold, len );
+      rb_manifold_filter_joint_edges( manifold, len, 0.05f );
+      rb_manifold_filter_pairs( manifold, len, 0.05f );
+   }
+   len = rb_manifold_apply_filtered( manifold, len );
+
+   rb_presolve_contacts( manifold, len );
+   for( int i=0; i<8; i++ )
+   {
+      rb_solve_contacts( manifold, len );
+      vehicle_solve_friction();
+   }
+
+   rb_iter( &gzoomer.rb );
+   rb_update_transform( &gzoomer.rb );
+}
+
+VG_STATIC void vehicle_update_post(void)
+{
+   if( !gzoomer.alive )
+      return;
+
+   rb_debug( &gzoomer.rb, VG__WHITE );
+   vg_line( player.phys.rb.co, gzoomer.rb.co, VG__WHITE );
+
+   /* draw friction vectors */
+   v3f p0, px, py;
+
+   for( int i=0; i<4; i++ )
+   {
+      v3_copy( gzoomer.wheels[i], p0 );
+      v3_muladds( p0, gzoomer.tangent_vectors[i][0], 0.5f, px );
+      v3_muladds( p0, gzoomer.tangent_vectors[i][1], 0.5f, py );
+
+      vg_line( p0, px, VG__RED );
+      vg_line( p0, py, VG__GREEN );
+   }
+}
+
+#endif /* VEHICLE_H */
index b5481c044f100effcb99f2ab15805e34616bd5d0..c0c4264898d1b6ef4db16c5255851d5cf47acbc7 100644 (file)
@@ -71,7 +71,7 @@ VG_STATIC void world_apply_procedural_foliage( struct world_material *mat )
       ray_hit hit;
       hit.dist = INFINITY;
 
-      if( ray_world( pos, (v3f){0.0001f,-1.0f,0.0001f}, &hit ))
+      if( ray_world( pos, (v3f){0.0f,-1.0f,0.0f}, &hit ))
       {
          struct world_material *m1 = ray_hit_material( &hit );
          if((hit.normal[1] > 0.8f) && (m1 == mat) && (hit.pos[1] > 0.0f+10.0f))