X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=player_ragdoll.h;h=08ab5e75d9ff56ce37129ed4b7ed248d7c3d913e;hb=HEAD;hp=e4711634a218e6f3e79c60a105c4165ed070777c;hpb=66b3ec9c538fefd79c2de08e0dcdf070b4331885;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/player_ragdoll.h b/player_ragdoll.h index e471163..08ab5e7 100644 --- a/player_ragdoll.h +++ b/player_ragdoll.h @@ -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; jpart_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; isk.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; ipart_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; isk.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; ipart_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; ipart_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; jparts[i].rb; - buf[j].rbb = &world->rb_geo; - } - - rb_contact_count += l; - } - } - - /* - * self-collision - */ - for( int i=0; ipart_count-1; i ++ ){ - for( int j=i+1; jpart_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; kparts[i].rb; - buf[k].rbb = &rd->parts[j].rb; - } - - rb_contact_count += l; - } - } - } - - for( int j=0; jpart_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; ico, 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; ipart_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; ipart_count; i++ ) - rb_iter( &rd->parts[i].rb ); - - for( int i=0; ipart_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; ico, 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 );