update helpers/location to 'frosted' ui
[carveJwlIkooP6JGAAIwe30JlM.git] / player_ragdoll.h
index e4711634a218e6f3e79c60a105c4165ed070777c..08ab5e75d9ff56ce37129ed4b7ed248d7c3d913e 100644 (file)
@@ -1,30 +1,41 @@
-#ifndef PLAYER_RAGDOLL_H
-#define PLAYER_RAGDOLL_H
+#pragma once
 
-#define VG_GAME
-#include "vg/vg.h"
+/*
+ * Copyright (C) 2021-2024 Mt.ZERO Software - All Rights Reserved
+ *
+ * Ragdoll system
+ */
+
+#include "player_api.h"
 #include "skeleton.h"
-#include "rigidbody.h"
-#include "player_model.h"
-#include "world.h"
-#include "audio.h"
+#include "vg/vg_rigidbody.h"
+#include "vg/vg_rigidbody_constraints.h"
 
-struct player_ragdoll
-{
-   struct ragdoll_part
-   {
+struct player_ragdoll{
+   struct ragdoll_part{
       u32 bone_id;
       
       /* Collider transform relative to bone */
       m4x3f collider_mtx,
             inv_collider_mtx;
 
+      v4f prev_q;
+      v3f prev_co;
+
       u32 use_limits;
       v3f limits[2];
 
-      rigidbody  rb;
       u32 parent;
       u32 colour;
+
+      rigidbody rb;
+      enum bone_collider type;
+
+      union {
+         rb_capsule capsule;
+         boxf box;
+      }
+      inf;
    }
    parts[32];
    u32 part_count;
@@ -35,428 +46,26 @@ struct player_ragdoll
    rb_constr_swingtwist cone_constraints[32];
    u32                  cone_constraints_count;
 
+   /* TODO: Fix duplicated data */
+   u32 constraint_associations[32][2];
    int shoes[2];
 };
 
-VG_STATIC void player_init_ragdoll_bone_collider( struct skeleton_bone *bone,
-                                                  struct ragdoll_part *rp )
-{
-   m4x3_identity( rp->collider_mtx );
-
-   if( bone->collider == k_bone_collider_box ){
-      v3f delta;
-      v3_sub( bone->hitbox[1], bone->hitbox[0], delta );
-      v3_muls( delta, 0.5f, delta );
-      v3_add( bone->hitbox[0], delta, rp->collider_mtx[3] );
-
-      v3_copy( delta, rp->rb.bbx[1] );
-      v3_muls( delta, -1.0f, rp->rb.bbx[0] );
-
-      q_identity( rp->rb.q );
-      rp->rb.type = k_rb_shape_box;
-      rp->colour = 0xffcccccc;
-   }
-   else if( bone->collider == k_bone_collider_capsule ){
-      v3f v0, v1, tx, ty;
-      v3_sub( bone->hitbox[1], bone->hitbox[0], v0 );
-
-      int major_axis = 0;
-      float largest = -1.0f;
-
-      for( int i=0; i<3; i ++ ){
-         if( fabsf( v0[i] ) > largest ){
-            largest = fabsf( v0[i] );
-            major_axis = i;
-         }
-      }
-      
-      v3_zero( v1 );
-      v1[ major_axis ] = 1.0f;
-      rb_tangent_basis( v1, tx, ty );
-      
-      float r = (fabsf(v3_dot(tx,v0)) + fabsf(v3_dot(ty,v0))) * 0.25f,
-            l = fabsf(v0[ major_axis ]);
-      
-      /* orientation */
-      v3_muls( tx, -1.0f, rp->collider_mtx[0] );
-      v3_muls( v1, -1.0f, rp->collider_mtx[1] );
-      v3_muls( ty, -1.0f, rp->collider_mtx[2] );
-      v3_add( bone->hitbox[0], bone->hitbox[1], rp->collider_mtx[3] );
-      v3_muls( rp->collider_mtx[3], 0.5f, rp->collider_mtx[3] );
-
-      rp->rb.type = k_rb_shape_capsule;
-      rp->rb.inf.capsule.height = l;
-      rp->rb.inf.capsule.radius = r;
-
-      rp->colour = 0xff000000 | (0xff << (major_axis*8));
-   }
-   else{
-      vg_warn( "type: %u\n", bone->collider );
-      vg_fatal_exit_loop( "Invalid bone collider type" );
-   }
-
-   m4x3_invert_affine( rp->collider_mtx, rp->inv_collider_mtx );
-
-   /* Position collider into rest */
-   m3x3_q( rp->collider_mtx, rp->rb.q );
-   v3_add( rp->collider_mtx[3], bone->co, rp->rb.co );
-   rp->rb.is_world = 0;
-   rb_init( &rp->rb );
-}
-
-/*
- * Get parent index in the ragdoll
- */
-VG_STATIC u32 ragdoll_bone_parent( struct player_ragdoll *rd,
-                                   struct player_avatar *av, u32 bone_id )
-{
-   for( u32 j=0; j<rd->part_count; j++ )
-      if( rd->parts[ j ].bone_id == bone_id )
-         return j;
-
-   vg_fatal_exit_loop( "Referenced parent bone does not have a rigidbody" );
-   return 0;
-}
-
-/*
- * Setup ragdoll colliders 
- */
-VG_STATIC void player_setup_ragdoll_from_avatar( struct player_ragdoll *rd,
-                                                 struct player_avatar *av )
-{
-   rd->part_count = 0;
-
-   if( !av->sk.collider_count )
-      return;
-
-   rd->position_constraints_count = 0;
-   rd->cone_constraints_count = 0;
-
-   for( u32 i=1; i<av->sk.bone_count; i ++ ){
-      struct skeleton_bone *bone = &av->sk.bones[i];
-
-      /*
-       * Bones with colliders
-       */
-      if( !(bone->collider) )
-         continue;
-
-      if( rd->part_count > vg_list_size(rd->parts) )
-         vg_fatal_exit_loop( "Playermodel has too many colliders" );
-
-      struct ragdoll_part *rp = &rd->parts[ rd->part_count ++ ];
-      rp->bone_id = i;
-      rp->parent = 0xffffffff;
-
-      player_init_ragdoll_bone_collider( bone, rp );
-      
-      /*
-       * Bones with collider and parent
-       */
-      if( !bone->parent )
-         continue;
-
-      rp->parent = ragdoll_bone_parent( rd, av, bone->parent );
-      
-      
-      if( bone->orig_bone->flags & k_bone_flag_cone_constraint ){
-         struct rb_constr_pos *c = 
-            &rd->position_constraints[ rd->position_constraints_count ++ ];
-
-         struct skeleton_bone *bj = &av->sk.bones[rp->bone_id];
-         struct ragdoll_part  *pp = &rd->parts[rp->parent];
-         struct skeleton_bone *bp = &av->sk.bones[pp->bone_id];
-
-         /* Convention: rba -- parent, rbb -- child */
-         c->rba = &pp->rb;
-         c->rbb = &rp->rb;
-
-         v3f delta;
-         v3_sub( bj->co, bp->co, delta );
-         m4x3_mulv( rp->inv_collider_mtx, (v3f){0.0f,0.0f,0.0f}, c->lcb );
-         m4x3_mulv( pp->inv_collider_mtx, delta, c->lca );
-
-
-         mdl_bone *inf = bone->orig_bone;
-
-         struct rb_constr_swingtwist *a = 
-            &rd->cone_constraints[ rd->cone_constraints_count ++ ];
-
-         a->rba = &pp->rb;
-         a->rbb = &rp->rb;
-         a->conet = cosf( inf->conet )-0.0001f;
-         
-         /* Store constraint in local space vectors */
-         m3x3_mulv( c->rba->to_local, inf->conevx, a->conevx );
-         m3x3_mulv( c->rba->to_local, inf->conevy, a->conevy );
-         m3x3_mulv( c->rbb->to_local, inf->coneva, a->coneva );
-         v3_copy( c->lca, a->view_offset );
-         
-         v3_cross( inf->coneva, inf->conevy, a->conevxb );
-         m3x3_mulv( c->rbb->to_local, a->conevxb, a->conevxb );
-
-         v3_normalize( a->conevxb );
-         v3_normalize( a->conevx );
-         v3_normalize( a->conevy );
-         v3_normalize( a->coneva );
-
-         a->conevx[3] = v3_length( inf->conevx );
-         a->conevy[3] = v3_length( inf->conevy );
-
-         rp->use_limits = 1;
-      }
-   }
-}
-
-/*
- * Make avatar copy the ragdoll
- */
-VG_STATIC void copy_ragdoll_pose_to_avatar( struct player_ragdoll *rd,
-                                            struct player_avatar *av )
-{
-   for( int i=0; i<rd->part_count; i++ ){
-      struct ragdoll_part *part = &rd->parts[i];
-      m4x3f offset;
-      m3x3_identity(offset);
-      m4x3_mul( part->rb.to_world, part->inv_collider_mtx, 
-                  av->sk.final_mtx[part->bone_id] );
-   }
-
-   for( u32 i=1; i<av->sk.bone_count; i++ ){
-      struct skeleton_bone *sb = &av->sk.bones[i];
-
-      if( sb->parent && !sb->collider ){
-         v3f delta;
-         v3_sub( av->sk.bones[i].co, av->sk.bones[sb->parent].co, delta );
-
-         m4x3f posemtx;
-         m3x3_identity( posemtx );
-         v3_copy( delta, posemtx[3] );
-
-         /* final matrix */
-         m4x3_mul( av->sk.final_mtx[sb->parent], posemtx, av->sk.final_mtx[i] );
-      }
-   }
-
-   skeleton_apply_inverses( &av->sk );
-}
-
-/*
- * Make the ragdoll copy the player model
- */
-VG_STATIC void copy_avatar_pose_to_ragdoll( struct player_avatar *av,
-                                            struct player_ragdoll *rd,
-                                            v3f velocity )
-{
-   for( int i=0; i<rd->part_count; i++ ){
-      struct ragdoll_part *part = &rd->parts[i];
-
-      v3f pos, offset;
-      u32 bone = part->bone_id;
-
-      m4x3_mulv( av->sk.final_mtx[bone], av->sk.bones[bone].co, pos );
-      m3x3_mulv( av->sk.final_mtx[bone], part->collider_mtx[3], offset );
-      v3_add( pos, offset, part->rb.co );
-
-      m3x3f r;
-      m3x3_mul( av->sk.final_mtx[bone], part->collider_mtx, r );
-      m3x3_q( r, part->rb.q );
-
-      v3_copy( velocity, part->rb.v );
-      v3_zero( part->rb.w );
-      
-      rb_update_transform( &part->rb );
-   }
-}
-
-/*
- * Draw rigidbody colliders for ragdoll
- */
-VG_STATIC void player_debug_ragdoll(void)
-{
-}
-
-/*
- * Ragdoll physics step
- */
-VG_STATIC void player_ragdoll_iter( struct player_ragdoll *rd )
-{
-   world_instance *world = get_active_world();
-
-   int run_sim = 0;
-   ragdoll_frame ++;
-
-   if( ragdoll_frame >= k_ragdoll_div ){
-      ragdoll_frame = 0;
-      run_sim = 1;
-   }
-
-   rb_solver_reset();
-   
-   float contact_velocities[256];
-
-   for( int i=0; i<rd->part_count; i ++ ){
-      if( rb_global_has_space() ){
-         rb_ct *buf = rb_global_buffer();
-
-         int l;
-         
-         if( rd->parts[i].rb.type == k_rb_shape_capsule ){
-            l = rb_capsule__scene( rd->parts[i].rb.to_world,
-                                   &rd->parts[i].rb.inf.capsule,
-                                   NULL, &world->rb_geo.inf.scene, buf );
-         }
-         else if( rd->parts[i].rb.type == k_rb_shape_box ){
-            l = rb_box__scene( rd->parts[i].rb.to_world,
-                               rd->parts[i].rb.bbx,
-                               NULL, &world->rb_geo.inf.scene, buf );
-         }
-         else continue;
-
-         for( int j=0; j<l; j++ ){
-            buf[j].rba = &rd->parts[i].rb;
-            buf[j].rbb = &world->rb_geo;
-         }
-
-         rb_contact_count += l;
-      }
-   }
-
-   /* 
-    * self-collision
-    */
-   for( int i=0; i<rd->part_count-1; i ++ ){
-      for( int j=i+1; j<rd->part_count; j ++ ){
-         if( rd->parts[j].parent != i ){
-            if( !rb_global_has_space() )
-               break;
-
-            if( rd->parts[j].rb.type != k_rb_shape_capsule )
-               continue;
-
-            if( rd->parts[i].rb.type != k_rb_shape_capsule )
-               continue;
-
-            rb_ct *buf = rb_global_buffer();
-
-            int l = rb_capsule__capsule( rd->parts[i].rb.to_world,
-                                         &rd->parts[i].rb.inf.capsule,
-                                         rd->parts[j].rb.to_world,
-                                         &rd->parts[j].rb.inf.capsule,
-                                         buf );
-
-            for( int k=0; k<l; k++ ){
-               buf[k].rba = &rd->parts[i].rb;
-               buf[k].rbb = &rd->parts[j].rb;
-            }
-
-            rb_contact_count += l;
-         }
-      }
-   }
-
-   for( int j=0; j<rd->part_count; j++ ){
-      struct ragdoll_part *pj = &rd->parts[j];
-
-      if( run_sim ){
-         v4f plane = {0.0f,1.0f,0.0f,0.0f};
-         rb_effect_simple_bouyency( &pj->rb, plane, k_ragdoll_floatyiness,
-                                                    k_ragdoll_floatydrag );
-      }
-   }
-
-   /*
-    * PRESOLVE
-    */
-   for( u32 i=0; i<rb_contact_count; i++ ){
-      rb_ct *ct = &rb_contact_buffer[i];
-
-      v3f rv, ra, rb;
-      v3_sub( ct->co, ct->rba->co, ra );
-      v3_sub( ct->co, ct->rbb->co, rb );
-      rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
-      float     vn = v3_dot( rv, ct->n );
-
-      contact_velocities[i] = vn;
-   }
-
-   rb_presolve_contacts( rb_contact_buffer, rb_contact_count );
-   rb_presolve_swingtwist_constraints( rd->cone_constraints,
-                                       rd->cone_constraints_count );
-
-   /* 
-    * DEBUG
-    */
-   if( k_ragdoll_debug_collider ){
-      for( u32 i=0; i<rd->part_count; i ++ )
-         rb_debug( &rd->parts[i].rb, rd->parts[i].colour );
-   }
-
-   if( k_ragdoll_debug_constraints ){
-      rb_debug_position_constraints( rd->position_constraints, 
-                                     rd->position_constraints_count );
-
-      rb_debug_swingtwist_constraints( rd->cone_constraints,
-                                       rd->cone_constraints_count );
-   }
-
-   /*
-    * SOLVE CONSTRAINTS 
-    */
-   if( run_sim ){
-      for( int i=0; i<16; i++ ){
-         rb_solve_contacts( rb_contact_buffer, rb_contact_count );
-         rb_solve_swingtwist_constraints( rd->cone_constraints, 
-                                          rd->cone_constraints_count );
-         rb_solve_position_constraints( rd->position_constraints, 
-                                        rd->position_constraints_count );
-      }
-
-      for( int i=0; i<rd->part_count; i++ )
-         rb_iter( &rd->parts[i].rb );
-
-      for( int i=0; i<rd->part_count; i++ )
-         rb_update_transform( &rd->parts[i].rb );
-
-      rb_correct_swingtwist_constraints( rd->cone_constraints, 
-                                         rd->cone_constraints_count, 0.25f );
-
-      rb_correct_position_constraints( rd->position_constraints,
-                                       rd->position_constraints_count, 0.5f );
-   }
-
-   rb_ct *stress = NULL;
-   float max_stress = 1.0f;
-
-   for( u32 i=0; i<rb_contact_count; i++ ){
-      rb_ct *ct = &rb_contact_buffer[i];
-
-      v3f rv, ra, rb;
-      v3_sub( ct->co, ct->rba->co, ra );
-      v3_sub( ct->co, ct->rbb->co, rb );
-      rb_rcv( ct->rba, ct->rbb, ra, rb, rv );
-      float     vn = v3_dot( rv, ct->n );
-
-      float s = fabsf(vn - contact_velocities[i]);
-      if( s > max_stress ){
-         stress = ct;
-         max_stress = s;
-      }
-   }
-
-   static u32 temp_filter = 0;
-
-   if( temp_filter ){
-      temp_filter --;
-      return;
-   }
-
-   if( stress ){
-      temp_filter = 20;
-      audio_lock();
-      audio_oneshot_3d( &audio_hits[rand()%5], stress->co, 20.0f, 1.0f );
-      audio_unlock();
-   }
-}
+enum player_die_type {
+   k_player_die_type_generic,
+   k_player_die_type_head,
+   k_player_die_type_feet
+};
 
-#endif /* PLAYER_RAGDOLL_H */
+void player_ragdoll_init(void);
+void player_init_ragdoll_bone_collider( struct skeleton_bone *bone,
+                                           struct ragdoll_part *rp );
+u32 ragdoll_bone_parent( struct player_ragdoll *rd, u32 bone_id );
+void setup_ragdoll_from_skeleton( struct skeleton *sk,
+                                  struct player_ragdoll *rd );
+void copy_ragdoll_pose_to_localplayer( struct player_ragdoll *rd );
+void copy_localplayer_to_ragdoll( struct player_ragdoll *rd, 
+                                  enum player_die_type type );
+                                   
+void player_debug_ragdoll(void);
+void player_ragdoll_iter( struct player_ragdoll *rd );