#ifndef PLAYER_RAGDOLL_H
#define PLAYER_RAGDOLL_H
-#define VG_GAME
-#include "vg/vg.h"
+#include "player_api.h"
#include "skeleton.h"
#include "rigidbody.h"
-#include "player_model.h"
-#include "world.h"
+#include "player_render.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;
+ rb_object obj;
u32 parent;
u32 colour;
}
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->flags & k_bone_flag_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->flags & k_bone_flag_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_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=0; i<av->sk.bone_count; i ++ )
- {
- struct skeleton_bone *bone = &av->sk.bones[i];
-
- /*
- * Bones with colliders
- */
- if( !(bone->flags & k_bone_flag_collider_any) )
- 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 );
-
- struct mdl_node *pnode = mdl_node_from_id( &av->meta, bone->orig_node );
- struct classtype_bone *inf = mdl_get_entdata( &av->meta, pnode );
-
- /*
- * Bones with collider and parent
- */
- if( !bone->parent )
- continue;
-
- rp->parent = ragdoll_bone_parent( rd, av, bone->parent );
-
- /* Always assign a point-to-point 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 );
-
- if( inf->flags & k_bone_flag_cone_constraint )
- {
- 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] );
- }
-
- 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 )
-{
- int run_sim = 0;
- ragdoll_frame ++;
-
- if( ragdoll_frame >= k_ragdoll_div )
- {
- ragdoll_frame = 0;
- run_sim = 1;
- }
-
- rb_solver_reset();
- for( int i=0; i<rd->part_count; i ++ )
- rb_collide( &rd->parts[i].rb, &world.rb_geo );
-
- /*
- * COLLISION DETECTION
- */
- 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 )
- rb_collide( &rd->parts[i].rb, &rd->parts[j].rb );
- }
- }
-
- 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
- */
- 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<25; 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 );
- }
-
-}
+static float k_ragdoll_floatyiness = 20.0f,
+ k_ragdoll_floatydrag = 1.0f,
+ k_ragdoll_limit_scale = 1.0f;
+
+static int k_ragdoll_div = 1,
+ ragdoll_frame = 0,
+ k_ragdoll_debug_collider = 1,
+ k_ragdoll_debug_constraints = 0;
+
+static void player_ragdoll_init(void);
+static void player_init_ragdoll_bone_collider( struct skeleton_bone *bone,
+ struct ragdoll_part *rp );
+static u32 ragdoll_bone_parent( struct player_ragdoll *rd, u32 bone_id );
+static void setup_ragdoll_from_skeleton( struct skeleton *sk,
+ struct player_ragdoll *rd );
+static void copy_ragdoll_pose_to_localplayer( struct player_ragdoll *rd );
+static void copy_localplayer_to_ragdoll( struct player_ragdoll *rd, v3f v );
+static void player_debug_ragdoll(void);
+static void player_ragdoll_iter( struct player_ragdoll *rd );
#endif /* PLAYER_RAGDOLL_H */