From: hgn Date: Sun, 15 Jan 2023 19:48:24 +0000 (+0000) Subject: a fairly major physics update X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=2a238d32da833812e837cf38e16a7685c98db5c3;p=carveJwlIkooP6JGAAIwe30JlM.git a fairly major physics update --- diff --git a/blender_export.py b/blender_export.py index 8cd60ea..515acd7 100644 --- a/blender_export.py +++ b/blender_export.py @@ -548,13 +548,14 @@ class classtype_skeleton(Structure): class classtype_bone(Structure): #{ _pack_ = 1 - _fields_ = [("deform",c_uint32), + _fields_ = [("flags",c_uint32), ("ik_target",c_uint32), ("ik_pole",c_uint32), - ("collider",c_uint32), - ("use_limits",c_uint32), - ("angle_limits",(c_float*3)*2), - ("hitbox",(c_float*3)*2)] + ("hitbox",(c_float*3)*2), + ("conevx",c_float*3), + ("conevy",c_float*3), + ("coneva",c_float*3), + ("conet",c_float)] def encode_obj(_, node,node_def): #{ @@ -563,19 +564,24 @@ class classtype_bone(Structure): armature_def = node_def['linked_armature'] obj = node_def['bone'] - _.deform = node_def['deform'] + _.flags = node_def['deform'] if 'ik_target' in node_def: #{ + _.flags |= 0x2 _.ik_target = armature_def['bones'].index( node_def['ik_target'] ) _.ik_pole = armature_def['bones'].index( node_def['ik_pole'] ) #} # For ragdolls # - if obj.cv_data.collider: + if obj.cv_data.collider != 'collider_none': #{ - _.collider = 1 + if obj.cv_data.collider == 'collider_box': + _.flags |= 0x4 + else: + _.flags |= 0x8 + _.hitbox[0][0] = obj.cv_data.v0[0] _.hitbox[0][1] = obj.cv_data.v0[2] _.hitbox[0][2] = -obj.cv_data.v1[1] @@ -586,13 +592,17 @@ class classtype_bone(Structure): if obj.cv_data.con0: #{ - _.use_limits = 1 - _.angle_limits[0][0] = obj.cv_data.mins[0] - _.angle_limits[0][1] = obj.cv_data.mins[2] - _.angle_limits[0][2] = -obj.cv_data.maxs[1] - _.angle_limits[1][0] = obj.cv_data.maxs[0] - _.angle_limits[1][1] = obj.cv_data.maxs[2] - _.angle_limits[1][2] = -obj.cv_data.mins[1] + _.flags |= 0x100 + _.conevx[0] = obj.cv_data.conevx[0] + _.conevx[1] = obj.cv_data.conevx[2] + _.conevx[2] = -obj.cv_data.conevx[1] + _.conevy[0] = obj.cv_data.conevy[0] + _.conevy[1] = obj.cv_data.conevy[2] + _.conevy[2] = -obj.cv_data.conevy[1] + _.coneva[0] = obj.cv_data.coneva[0] + _.coneva[1] = obj.cv_data.coneva[2] + _.coneva[2] = -obj.cv_data.coneva[1] + _.conet = obj.cv_data.conet #} #} #} @@ -1279,7 +1289,7 @@ def encoder_build_scene_graph( collection ): #} #} - if n.cv_data.collider: + if n.cv_data.collider != 'collider_none': tree['collider_count'] += 1 btree['deform'] = n.use_deform @@ -2041,6 +2051,44 @@ def cv_draw_sphere( pos, radius, colour ): cv_draw_lines() #} +# Draw axis alligned sphere at position with radius +# +def cv_draw_halfsphere( pos, tx, ty, tz, radius, colour ): +#{ + global cv_view_verts, cv_view_colours + + ly = pos + tz*radius + lx = pos + ty*radius + lz = pos + tz*radius + + pi = 3.14159265358979323846264 + + for i in range(16): + #{ + t = ((i+1.0) * 1.0/16.0) * pi + s = math.sin(t) + c = math.cos(t) + + s1 = math.sin(t*2.0) + c1 = math.cos(t*2.0) + + py = pos + s*tx*radius + c *tz*radius + px = pos + s*tx*radius + c *ty*radius + pz = pos + s1*ty*radius + c1*tz*radius + + cv_view_verts += [ px, lx ] + cv_view_verts += [ py, ly ] + cv_view_verts += [ pz, lz ] + + cv_view_colours += [ colour, colour, colour, colour, colour, colour ] + + ly = py + lx = px + lz = pz + #} + cv_draw_lines() +#} + # Draw transformed -1 -> 1 cube # def cv_draw_ucube( transform, colour ): @@ -2096,9 +2144,9 @@ def cv_draw_line2( p0, p1, c0, c1 ): cv_draw_lines() #} -# Just the tx because we dont really need ty for this app +# # -def cv_tangent_basis_tx( n, tx ): +def cv_tangent_basis( n, tx, ty ): #{ if abs( n[0] ) >= 0.57735027: #{ @@ -2114,6 +2162,11 @@ def cv_tangent_basis_tx( n, tx ): #} tx.normalize() + _ty = n.cross( tx ) + + ty[0] = _ty[0] + ty[1] = _ty[1] + ty[2] = _ty[2] #} # Draw coloured arrow @@ -2127,7 +2180,8 @@ def cv_draw_arrow( p0, p1, c0 ): n.normalize() tx = Vector((1,0,0)) - cv_tangent_basis_tx( n, tx ) + ty = Vector((1,0,0)) + cv_tangent_basis( n, tx, ty ) cv_view_verts += [p0,p1, midpt+(tx-n)*0.15,midpt, midpt+(-tx-n)*0.15,midpt ] cv_view_colours += [c0,c0,c0,c0,c0,c0] @@ -2260,19 +2314,61 @@ def draw_limit( obj, center, major, minor, amin, amax, colour ): cv_draw_lines() #} +# Cone and twist limit +# +def draw_cone_twist( center, vx, vy, va ): +#{ + global cv_view_verts, cv_view_colours + axis = vy.cross( vx ) + axis.normalize() + + size = 0.12 + + cv_view_verts += [center, center+va*size] + cv_view_colours += [ (1,1,1,1), (1,1,1,1) ] + + for x in range(32): + #{ + t0 = (x/32) * math.tau + t1 = ((x+1)/32) * math.tau + + c0 = math.cos(t0) + s0 = math.sin(t0) + c1 = math.cos(t1) + s1 = math.sin(t1) + + p0 = center + (axis + vx*c0 + vy*s0).normalized() * size + p1 = center + (axis + vx*c1 + vy*s1).normalized() * size + + col0 = ( abs(c0), abs(s0), 0.0, 1.0 ) + col1 = ( abs(c1), abs(s1), 0.0, 1.0 ) + + cv_view_verts += [center, p0, p0, p1] + cv_view_colours += [ (0,0,0,0), col0, col0, col1 ] + #} + + cv_draw_lines() +#} + # Draws constraints and stuff for the skeleton. This isnt documented and wont be # def draw_skeleton_helpers( obj ): #{ global cv_view_verts, cv_view_colours + if obj.data.pose_position != 'REST': + #{ + return + #} + for bone in obj.data.bones: #{ - if bone.cv_data.collider and (obj.data.pose_position == 'REST'): + c = bone.head_local + a = Vector((bone.cv_data.v0[0], bone.cv_data.v0[1], bone.cv_data.v0[2])) + b = Vector((bone.cv_data.v1[0], bone.cv_data.v1[1], bone.cv_data.v1[2])) + + if bone.cv_data.collider == 'collider_box': #{ - c = bone.head_local - a = bone.cv_data.v0 - b = bone.cv_data.v1 vs = [None]*8 vs[0]=obj.matrix_world@Vector((c[0]+a[0],c[1]+a[1],c[2]+a[2])) @@ -2296,20 +2392,67 @@ def draw_skeleton_helpers( obj ): cv_view_verts += [(v1[0],v1[1],v1[2])] cv_view_colours += [(0.5,0.5,0.5,0.5),(0.5,0.5,0.5,0.5)] #} + #} + elif bone.cv_data.collider == 'collider_capsule': + #{ + v0 = b-a + major_axis = 0 + largest = -1.0 - center = obj.matrix_world @ c - if bone.cv_data.con0: + for i in range(3): #{ - draw_limit( obj, c, Vector((0,1,0)),Vector((0,0,1)), \ - bone.cv_data.mins[0], bone.cv_data.maxs[0], \ - (1,0,0,1)) - draw_limit( obj, c, Vector((0,0,1)),Vector((1,0,0)), \ - bone.cv_data.mins[1], bone.cv_data.maxs[1], \ - (0,1,0,1)) - draw_limit( obj, c, Vector((1,0,0)),Vector((0,1,0)), \ - bone.cv_data.mins[2], bone.cv_data.maxs[2], \ - (0,0,1,1)) + if abs(v0[i]) > largest: + #{ + largest = abs(v0[i]) + major_axis = i + #} #} + + v1 = Vector((0,0,0)) + v1[major_axis] = 1.0 + + tx = Vector((0,0,0)) + ty = Vector((0,0,0)) + + cv_tangent_basis( v1, tx, ty ) + r = (abs(tx.dot( v0 )) + abs(ty.dot( v0 ))) * 0.25 + l = v0[ major_axis ] - r*2 + + p0 = obj.matrix_world@Vector( c + (a+b)*0.5 + v1*l*-0.5 ) + p1 = obj.matrix_world@Vector( c + (a+b)*0.5 + v1*l* 0.5 ) + + colour = [0.2,0.2,0.2,1.0] + colour[major_axis] = 0.5 + + cv_draw_halfsphere( p0, -v1, ty, tx, r, colour ) + cv_draw_halfsphere( p1, v1, ty, tx, r, colour ) + cv_draw_line( p0+tx* r, p1+tx* r, colour ) + cv_draw_line( p0+tx*-r, p1+tx*-r, colour ) + cv_draw_line( p0+ty* r, p1+ty* r, colour ) + cv_draw_line( p0+ty*-r, p1+ty*-r, colour ) + #} + else: + #{ + continue + #} + + center = obj.matrix_world @ c + if bone.cv_data.con0: + #{ + vx = Vector([bone.cv_data.conevx[_] for _ in range(3)]) + vy = Vector([bone.cv_data.conevy[_] for _ in range(3)]) + va = Vector([bone.cv_data.coneva[_] for _ in range(3)]) + draw_cone_twist( center, vx, vy, va ) + + #draw_limit( obj, c, Vector((0,0,1)),Vector((0,-1,0)), \ + # bone.cv_data.mins[0], bone.cv_data.maxs[0], \ + # (1,0,0,1)) + #draw_limit( obj, c, Vector((0,-1,0)),Vector((1,0,0)), \ + # bone.cv_data.mins[1], bone.cv_data.maxs[1], \ + # (0,1,0,1)) + #draw_limit( obj, c, Vector((1,0,0)),Vector((0,0,1)), \ + # bone.cv_data.mins[2], bone.cv_data.maxs[2], \ + # (0,0,1,1)) #} #} #} @@ -2428,13 +2571,25 @@ class CV_OBJ_SETTINGS(bpy.types.PropertyGroup): class CV_BONE_SETTINGS(bpy.types.PropertyGroup): #{ - collider: bpy.props.BoolProperty(name="Collider",default=False) + collider: bpy.props.EnumProperty( + name="Collider Type", + items = [ + ('collider_none', "collider_none", "", 0), + ('collider_box', "collider_box", "", 1), + ('collider_capsule', "collider_capsule", "", 2), + ]) + v0: bpy.props.FloatVectorProperty(name="v0",size=3) v1: bpy.props.FloatVectorProperty(name="v1",size=3) con0: bpy.props.BoolProperty(name="Constriant 0",default=False) mins: bpy.props.FloatVectorProperty(name="mins",size=3) maxs: bpy.props.FloatVectorProperty(name="maxs",size=3) + + conevx: bpy.props.FloatVectorProperty(name="conevx",size=3) + conevy: bpy.props.FloatVectorProperty(name="conevy",size=3) + coneva: bpy.props.FloatVectorProperty(name="coneva",size=3) + conet: bpy.props.FloatProperty(name="conet") #} class CV_BONE_PANEL(bpy.types.Panel): @@ -2459,8 +2614,11 @@ class CV_BONE_PANEL(bpy.types.Panel): _.layout.label( text="Angle Limits" ) _.layout.prop( bone.cv_data, "con0" ) - _.layout.prop( bone.cv_data, "mins" ) - _.layout.prop( bone.cv_data, "maxs" ) + + _.layout.prop( bone.cv_data, "conevx" ) + _.layout.prop( bone.cv_data, "conevy" ) + _.layout.prop( bone.cv_data, "coneva" ) + _.layout.prop( bone.cv_data, "conet" ) #} #} diff --git a/bvh.h b/bvh.h index 41a4108..e79e3dd 100644 --- a/bvh.h +++ b/bvh.h @@ -5,7 +5,6 @@ #ifndef BVH_H #define BVH_H #include "common.h" -#include "distq.h" /* * Usage: @@ -178,7 +177,28 @@ VG_STATIC bh_tree *bh_create( void *lin_alloc, bh_system *system, return bh; } -VG_STATIC void bh_debug_node( bh_tree *bh, u32 inode, v3f pos, u32 colour ) +/* + * Draw items in this leaf node. + * *item_debug() must be set! + */ +VG_STATIC void bh_debug_leaf( bh_tree *bh, bh_node *node ) +{ + vg_line_boxf( node->bbx, 0xff00ff00 ); + + if( bh->system->item_debug ) + { + for( u32 i=0; icount; i++ ) + { + u32 idx = node->start+i; + bh->system->item_debug( bh->user, idx ); + } + } +} + +/* + * Trace the bh tree all the way down to the leaf nodes where pos is inside + */ +VG_STATIC void bh_debug_trace( bh_tree *bh, u32 inode, v3f pos, u32 colour ) { bh_node *node = &bh->nodes[ inode ]; @@ -189,21 +209,13 @@ VG_STATIC void bh_debug_node( bh_tree *bh, u32 inode, v3f pos, u32 colour ) { vg_line_boxf( node->bbx, colour ); - bh_debug_node( bh, node->il, pos, colour ); - bh_debug_node( bh, node->ir, pos, colour ); + bh_debug_trace( bh, node->il, pos, colour ); + bh_debug_trace( bh, node->ir, pos, colour ); } else { - vg_line_boxf( node->bbx, 0xff00ff00 ); - if( bh->system->item_debug ) - { - for( u32 i=0; icount; i++ ) - { - u32 idx = node->start+i; - bh->system->item_debug( bh->user, idx ); - } - } + bh_debug_leaf( bh, node ); } } } @@ -288,39 +300,39 @@ VG_STATIC int bh_next( bh_tree *bh, bh_iter *it, boxf box, int *em ) { bh_node *inode = &bh->nodes[ it->stack[it->depth].id ]; - if( box_overlap( inode->bbx, box ) ) + /* Only process overlapping nodes */ + if( !box_overlap( inode->bbx, box ) ) { - if( inode->count ) + it->depth --; + continue; + } + + if( inode->count ) + { + if( it->i < inode->count ) { - if( it->i < inode->count ) - { - *em = inode->start+it->i; - it->i ++; - return 1; - } - else - { - it->depth --; - it->i = 0; - } + *em = inode->start+it->i; + it->i ++; + return 1; } else { - if( it->depth+1 >= vg_list_size(it->stack) ) - { - vg_error( "Maximum stack reached!\n" ); - return 0; - } - - it->stack[it->depth ].id = inode->il; - it->stack[it->depth+1].id = inode->ir; - it->depth ++; + it->depth --; it->i = 0; } } else { - it->depth --; + if( it->depth+1 >= vg_list_size(it->stack) ) + { + vg_error( "Maximum stack reached!\n" ); + return 0; + } + + it->stack[it->depth ].id = inode->il; + it->stack[it->depth+1].id = inode->ir; + it->depth ++; + it->i = 0; } } diff --git a/distq.h b/distq.h deleted file mode 100644 index 1ae5436..0000000 --- a/distq.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef DISTQ_H -#define DISTQ_H - -#include "vg_m.h" - - -#endif /* DISTQ_H */ diff --git a/maps_src/mp_gridmap.mdl b/maps_src/mp_gridmap.mdl index 78b0dd0..1f1079f 100644 Binary files a/maps_src/mp_gridmap.mdl and b/maps_src/mp_gridmap.mdl differ diff --git a/model.h b/model.h index be0666a..287eefd 100644 --- a/model.h +++ b/model.h @@ -68,6 +68,26 @@ enum material_flag k_material_flag_grind_surface = 0x8 }; +enum bone_flag +{ + k_bone_flag_deform = 0x1, + k_bone_flag_ik = 0x2, + k_bone_flag_collider_box = 0x4, + k_bone_flag_collider_capsule = 0x8, + k_bone_flag_collider_reserved0 = 0x10, + k_bone_flag_collider_reserved1 = 0x20, + k_bone_flag_collider_reserved2 = 0x40, + k_bone_flag_collider_reserved3 = 0x80, + k_bone_flag_collider_any = k_bone_flag_collider_box | + k_bone_flag_collider_capsule | + k_bone_flag_collider_reserved0 | + k_bone_flag_collider_reserved1 | + k_bone_flag_collider_reserved2 | + k_bone_flag_collider_reserved3, + k_bone_flag_cone_constraint = 0x100, + k_bone_flag_force_u32 = 0xffffffff +}; + #pragma pack(push,1) struct mdl_vert @@ -200,14 +220,14 @@ struct classtype_route struct classtype_bone { - u32 deform, + u32 flags, ik_target, - ik_pole, - collider, - use_limits; + ik_pole; - v3f angle_limits[2]; boxf hitbox; + + v3f conevx, conevy, coneva; + float conet; }; struct classtype_skeleton diff --git a/models_src/ch_jordan.mdl b/models_src/ch_jordan.mdl index 7130ad0..0d147d1 100644 Binary files a/models_src/ch_jordan.mdl and b/models_src/ch_jordan.mdl differ diff --git a/models_src/ch_new.mdl b/models_src/ch_new.mdl index c11c27f..53b5900 100644 Binary files a/models_src/ch_new.mdl and b/models_src/ch_new.mdl differ diff --git a/models_src/ch_outlaw.mdl b/models_src/ch_outlaw.mdl index f3d7858..29609e7 100644 Binary files a/models_src/ch_outlaw.mdl and b/models_src/ch_outlaw.mdl differ diff --git a/player.h b/player.h index 2325f72..0e92f3a 100644 --- a/player.h +++ b/player.h @@ -194,17 +194,28 @@ VG_STATIC struct gplayer struct ragdoll_part { u32 bone_id; - v3f offset; + //v3f offset; + + /* Collider transform relative to bone */ + m4x3f collider_mtx, + inv_collider_mtx; u32 use_limits; v3f limits[2]; rigidbody rb; u32 parent; + u32 colour; } ragdoll[32]; u32 ragdoll_count; + rb_constr_pos position_constraints[32]; + u32 position_constraints_count; + + rb_constr_swingtwist cone_constraints[32]; + u32 cone_constraints_count; + int shoes[2]; } mdl; @@ -241,6 +252,8 @@ VG_STATIC void player_mouseview(void); * Events * ----------------------------------------------------------------------------- */ +VG_STATIC int kill_player( int argc, char const *argv[] ); +VG_STATIC int reset_player( int argc, char const *argv[] ); VG_STATIC void player_init(void) /* 1 */ { @@ -364,11 +377,51 @@ VG_STATIC void player_init(void) /* 1 */ .persistent = 1 }); + vg_convar_push( (struct vg_convar){ + .name = "k_ragdoll_limit_scale", + .data = &k_ragdoll_limit_scale, + .data_type = k_convar_dtype_f32, + .opt_f32 = { .clamp = 0 }, + .persistent = 1 + }); + + vg_convar_push( (struct vg_convar){ + .name = "k_ragdoll_div", + .data = &k_ragdoll_div, + .data_type = k_convar_dtype_i32, + .opt_i32 = { .clamp=0 }, + .persistent = 1 + }); + + vg_convar_push( (struct vg_convar){ + .name = "k_ragdoll_debug_collider", + .data = &k_ragdoll_debug_collider, + .data_type = k_convar_dtype_i32, + .opt_i32 = { .clamp=0 }, + .persistent = 1 + }); + + vg_convar_push( (struct vg_convar){ + .name = "k_ragdoll_debug_constraints", + .data = &k_ragdoll_debug_constraints, + .data_type = k_convar_dtype_i32, + .opt_i32 = { .clamp=0 }, + .persistent = 1 + }); + vg_function_push( (struct vg_cmd){ .name = "reset", .function = reset_player }); + vg_function_push( (struct vg_cmd){ + .name = "kill", + .function = kill_player + }); + + /* HACK */ + rb_register_cvar(); + player.rewind_length = 0; player.rewind_buffer = vg_linear_alloc( vg_mem.rtmemory, diff --git a/player_animation.h b/player_animation.h index 98aa256..08a5405 100644 --- a/player_animation.h +++ b/player_animation.h @@ -30,7 +30,6 @@ VG_STATIC void player_animate_offboard(void) mdl_keyframe apose[32], bpose[32]; struct skeleton *sk = &player.mdl.sk; - if( player.walk > 0.025f ) { /* TODO move */ @@ -88,6 +87,8 @@ VG_STATIC void player_animate(void) { struct player_phys *phys = &player.phys; rb_extrapolate_transform( &player.phys.rb, player.visual_transform ); + v3_muladds( player.visual_transform[3], phys->rb.up, -0.2f, + player.visual_transform[3] ); v4f qfake_rot; m3x3f fake_rot; diff --git a/player_physics.h b/player_physics.h index a2aabff..6a744e8 100644 --- a/player_physics.h +++ b/player_physics.h @@ -1366,6 +1366,12 @@ VG_STATIC void player_freecam(void) v3_add( move_vel, player.camera_pos, player.camera_pos ); } +VG_STATIC int kill_player( int argc, char const *argv[] ) +{ + player_kill(); + return 0; +} + VG_STATIC int reset_player( int argc, char const *argv[] ) { struct player_phys *phys = &player.phys; @@ -1428,10 +1434,12 @@ VG_STATIC int reset_player( int argc, char const *argv[] ) v3f delta = {1.0f,0.0f,0.0f}; m3x3_mulv( the_long_way, delta, delta ); - - player.angles[0] = atan2f( delta[0], -delta[2] ); - player.angles[1] = -asinf( delta[1] ); - + + if( !freecam ) + { + player.angles[0] = atan2f( delta[0], -delta[2] ); + player.angles[1] = -asinf( delta[1] ); + } v4_copy( rp->q, phys->rb.q ); v3_copy( rp->co, phys->rb.co ); diff --git a/player_ragdoll.h b/player_ragdoll.h index 6193bf7..0e48f0c 100644 --- a/player_ragdoll.h +++ b/player_ragdoll.h @@ -4,7 +4,94 @@ #include "player.h" VG_STATIC float k_ragdoll_floatyiness = 20.0f, - k_ragdoll_floatydrag = 1.0f; + k_ragdoll_floatydrag = 1.0f, + k_ragdoll_limit_scale = 1.0f; + +VG_STATIC int k_ragdoll_div = 1, + ragdoll_frame = 0, + k_ragdoll_debug_collider = 1, + k_ragdoll_debug_constraints = 0; + +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_model *mdl, u32 bone_id ) +{ + for( u32 j=0; jragdoll_count; j++ ) + if( mdl->ragdoll[ j ].bone_id == bone_id ) + return j; + + vg_fatal_exit_loop( "Referenced parent bone does not have a rigidbody" ); + return 0; +} /* * Setup ragdoll colliders @@ -21,54 +108,82 @@ VG_STATIC void player_init_ragdoll(void) } mdl->ragdoll_count = 0; + mdl->position_constraints_count = 0; + mdl->cone_constraints_count = 0; for( u32 i=0; isk.bone_count; i ++ ) { struct skeleton_bone *bone = &mdl->sk.bones[i]; - - if( bone->collider ) - { - if( mdl->ragdoll_count > vg_list_size(player.mdl.ragdoll) ) - vg_fatal_exit_loop( "Playermodel has too many colliders" ); - struct ragdoll_part *rp = &mdl->ragdoll[ mdl->ragdoll_count ++ ]; - rp->bone_id = i; - - v3f delta; - v3_sub( bone->hitbox[1], bone->hitbox[0], delta ); - v3_muls( delta, 0.5f, delta ); + /* + * Bones with colliders + */ + if( !(bone->flags & k_bone_flag_collider_any) ) + continue; - v3_add( bone->hitbox[0], delta, rp->offset ); + if( mdl->ragdoll_count > vg_list_size(player.mdl.ragdoll) ) + vg_fatal_exit_loop( "Playermodel has too many colliders" ); - v3_copy( delta, rp->rb.bbx[1] ); - v3_muls( delta, -1.0f, rp->rb.bbx[0] ); + struct ragdoll_part *rp = &mdl->ragdoll[ mdl->ragdoll_count ++ ]; + rp->bone_id = i; + rp->parent = 0xffffffff; - q_identity( rp->rb.q ); - v3_add( bone->co, rp->offset, rp->rb.co ); - rp->rb.type = k_rb_shape_box; - rp->rb.is_world = 0; - rp->parent = 0xffffffff; + player_init_ragdoll_bone_collider( bone, rp ); + + struct mdl_node *pnode = mdl_node_from_id( src, bone->orig_node ); + struct classtype_bone *inf = mdl_get_entdata( src, pnode ); + + /* + * Bones with collider and parent + */ + if( !bone->parent ) + continue; - if( bone->parent ) - { - for( u32 j=0; jragdoll_count; j++ ) - { - if( mdl->ragdoll[ j ].bone_id == bone->parent ) - { - rp->parent = j; - break; - } - } - } + rp->parent = ragdoll_bone_parent( mdl, bone->parent ); + + /* Always assign a point-to-point constraint */ + struct rb_constr_pos *c = + &mdl->position_constraints[ mdl->position_constraints_count ++ ]; + + struct skeleton_bone *bj = &mdl->sk.bones[rp->bone_id]; + struct ragdoll_part *pp = &mdl->ragdoll[rp->parent]; + struct skeleton_bone *bp = &mdl->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 = + &mdl->cone_constraints[ mdl->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 ); - struct mdl_node *pnode = mdl_node_from_id( src, bone->orig_node ); - struct classtype_bone *bone_inf = mdl_get_entdata( src, pnode ); + v3_cross( inf->coneva, inf->conevy, a->conevxb ); + m3x3_mulv( c->rbb->to_local, a->conevxb, a->conevxb ); - rp->use_limits = bone_inf->use_limits; - v3_copy( bone_inf->angle_limits[0], rp->limits[0] ); - v3_copy( bone_inf->angle_limits[1], rp->limits[1] ); + v3_normalize( a->conevxb ); + v3_normalize( a->conevx ); + v3_normalize( a->conevy ); + v3_normalize( a->coneva ); - rb_init( &rp->rb ); + a->conevx[3] = v3_length( inf->conevx ); + a->conevy[3] = v3_length( inf->conevy ); + + rp->use_limits = 1; } } } @@ -85,8 +200,8 @@ VG_STATIC void player_model_copy_ragdoll(void) struct ragdoll_part *part = &mdl->ragdoll[i]; m4x3f offset; m3x3_identity(offset); - v3_negate( part->offset, offset[3] ); - m4x3_mul( part->rb.to_world, offset, mdl->sk.final_mtx[part->bone_id] ); + m4x3_mul( part->rb.to_world, part->inv_collider_mtx, + mdl->sk.final_mtx[part->bone_id] ); } skeleton_apply_inverses( &mdl->sk ); @@ -105,11 +220,15 @@ VG_STATIC void player_ragdoll_copy_model( v3f v ) v3f pos, offset; u32 bone = part->bone_id; - + m4x3_mulv( mdl->sk.final_mtx[bone], mdl->sk.bones[bone].co, pos ); - m3x3_mulv( mdl->sk.final_mtx[bone], part->offset, offset ); + m3x3_mulv( mdl->sk.final_mtx[bone], part->collider_mtx[3], offset ); v3_add( pos, offset, part->rb.co ); - m3x3_q( mdl->sk.final_mtx[bone], part->rb.q ); + + m3x3f r; + m3x3_mul( mdl->sk.final_mtx[bone], part->collider_mtx, r ); + m3x3_q( r, part->rb.q ); + v3_copy( v, part->rb.v ); v3_zero( part->rb.w ); @@ -123,9 +242,6 @@ VG_STATIC void player_ragdoll_copy_model( v3f v ) VG_STATIC void player_debug_ragdoll(void) { struct player_model *mdl = &player.mdl; - - for( u32 i=0; iragdoll_count; i ++ ) - rb_debug( &mdl->ragdoll[i].rb, 0xff00ff00 ); } /* @@ -134,84 +250,99 @@ VG_STATIC void player_debug_ragdoll(void) VG_STATIC void player_ragdoll_iter(void) { struct player_model *mdl = &player.mdl; - rb_solver_reset(); + 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; iragdoll_count; i ++ ) rb_collide( &mdl->ragdoll[i].rb, &world.rb_geo ); + /* + * COLLISION DETECTION + */ + for( int i=0; iragdoll_count-1; i ++ ) + { + for( int j=i+1; jragdoll_count; j ++ ) + { + if( mdl->ragdoll[j].parent != i ) + rb_collide( &mdl->ragdoll[i].rb, &mdl->ragdoll[j].rb ); + } + } + + /* + * PRESOLVE + */ rb_presolve_contacts( rb_contact_buffer, rb_contact_count ); + rb_presolve_swingtwist_constraints( mdl->cone_constraints, + mdl->cone_constraints_count ); + + /* + * DEBUG + */ + if( k_ragdoll_debug_collider ) + { + for( u32 i=0; iragdoll_count; i ++ ) + rb_debug( &mdl->ragdoll[i].rb, mdl->ragdoll[i].colour ); + } - v3f rv; + if( k_ragdoll_debug_constraints ) + { + rb_debug_position_constraints( mdl->position_constraints, + mdl->position_constraints_count ); + + rb_debug_swingtwist_constraints( mdl->cone_constraints, + mdl->cone_constraints_count ); + } #if 0 - float shoe_vel[2] = {0.0f,0.0f}; - for( int i=0; i<2; i++ ) - if( mdl->shoes[i] ) - shoe_vel[i] = v3_length( mdl->ragdoll[i].rb.v ); -#endif - for( int j=0; jragdoll_count; j++ ) { struct ragdoll_part *pj = &mdl->ragdoll[j]; struct skeleton_bone *bj = &mdl->sk.bones[pj->bone_id]; - if( pj->parent != 0xffffffff ) + if( run_sim ) { - struct ragdoll_part *pp = &mdl->ragdoll[pj->parent]; - struct skeleton_bone *bp = &mdl->sk.bones[pp->bone_id]; - - v3f lca, lcb; - v3_negate( pj->offset, lca ); - v3_add( bp->co, pp->offset, lcb ); - v3_sub( bj->co, lcb, lcb ); - - rb_debug_constraint_position( &pj->rb, lca, &pp->rb, lcb ); - - if( pj->use_limits ) - { - rb_debug_constraint_limits( &pj->rb, &pp->rb, lca, pj->limits ); - } + v4f plane = {0.0f,1.0f,0.0f,0.0f}; + rb_effect_simple_bouyency( &pj->rb, plane, k_ragdoll_floatyiness, + k_ragdoll_floatydrag ); } - - v4f plane = {0.0f,1.0f,0.0f,0.0f}; - rb_effect_simple_bouyency( &pj->rb, plane, k_ragdoll_floatyiness, - k_ragdoll_floatydrag ); } +#endif - /* CONSTRAINTS */ - for( int i=0; i<10; i++ ) + /* + * SOLVE CONSTRAINTS + */ + if( run_sim ) { - rb_solve_contacts( rb_contact_buffer, rb_contact_count ); - - for( int j=0; jragdoll_count; j++ ) + for( int i=0; i<25; i++ ) { - struct ragdoll_part *pj = &mdl->ragdoll[j]; - struct skeleton_bone *bj = &mdl->sk.bones[pj->bone_id]; + rb_solve_contacts( rb_contact_buffer, rb_contact_count ); + rb_solve_swingtwist_constraints( mdl->cone_constraints, + mdl->cone_constraints_count ); + rb_solve_position_constraints( mdl->position_constraints, + mdl->position_constraints_count ); + } - if( (pj->parent != 0xffffffff) && pj->use_limits ) - { - struct ragdoll_part *pp = &mdl->ragdoll[pj->parent]; - struct skeleton_bone *bp = &mdl->sk.bones[pp->bone_id]; + for( int i=0; iragdoll_count; i++ ) + rb_iter( &mdl->ragdoll[i].rb ); - v3f lca, lcb; - v3_negate( pj->offset, lca ); - v3_add( bp->co, pp->offset, lcb ); - v3_sub( bj->co, lcb, lcb ); + for( int i=0; iragdoll_count; i++ ) + rb_update_transform( &mdl->ragdoll[i].rb ); - rb_constraint_position( &pj->rb, lca, &pp->rb, lcb ); + rb_correct_swingtwist_constraints( mdl->cone_constraints, + mdl->cone_constraints_count, 0.25f ); - rb_constraint_limits( &pj->rb, lca, &pp->rb, lcb, pj->limits ); - } - } + rb_correct_position_constraints( mdl->position_constraints, + mdl->position_constraints_count, 0.5f ); } - /* INTEGRATION */ - for( int i=0; iragdoll_count; i++ ) - rb_iter( &mdl->ragdoll[i].rb ); - - /* SHOES */ - for( int i=0; iragdoll_count; i++ ) - rb_update_transform( &mdl->ragdoll[i].rb ); } #endif /* PLAYER_RAGDOLL_H */ diff --git a/rigidbody.h b/rigidbody.h index aa8d4f8..f4d6ef9 100644 --- a/rigidbody.h +++ b/rigidbody.h @@ -10,7 +10,6 @@ #include "common.h" #include "bvh.h" #include "scene.h" -#include "distq.h" #include @@ -29,14 +28,41 @@ VG_STATIC bh_system bh_system_rigidbodies; VG_STATIC const float k_rb_rate = (1.0/VG_TIMESTEP_FIXED), k_rb_delta = (1.0/k_rb_rate), - k_friction = 0.6f, - k_damp_linear = 0.05f, /* scale velocity 1/(1+x) */ + k_friction = 0.4f, + k_damp_linear = 0.1f, /* scale velocity 1/(1+x) */ k_damp_angular = 0.1f, /* scale angular 1/(1+x) */ + k_penetration_slop = 0.01f, + k_inertia_scale = 8.0f, + k_phys_baumgarte = 0.2f; + +VG_STATIC float k_limit_bias = 0.02f, - k_joint_bias = 0.08f, /* positional joints */ k_joint_correction = 0.01f, - k_penetration_slop = 0.01f, - k_inertia_scale = 4.0f; + k_joint_impulse = 1.0f, + k_joint_bias = 0.08f; /* positional joints */ + +VG_STATIC void rb_register_cvar(void) +{ + vg_convar_push( (struct vg_convar){ + .name = "k_limit_bias", .data = &k_limit_bias, + .data_type = k_convar_dtype_f32, .opt_f32 = {.clamp = 0}, .persistent = 1 + }); + + vg_convar_push( (struct vg_convar){ + .name = "k_joint_bias", .data = &k_joint_bias, + .data_type = k_convar_dtype_f32, .opt_f32 = {.clamp = 0}, .persistent = 1 + }); + + vg_convar_push( (struct vg_convar){ + .name = "k_joint_correction", .data = &k_joint_correction, + .data_type = k_convar_dtype_f32, .opt_f32 = {.clamp = 0}, .persistent = 1 + }); + + vg_convar_push( (struct vg_convar){ + .name = "k_joint_impulse", .data = &k_joint_impulse, + .data_type = k_convar_dtype_f32, .opt_f32 = {.clamp = 0}, .persistent = 1 + }); +} /* * ----------------------------------------------------------------------------- @@ -112,6 +138,30 @@ VG_STATIC struct contact rb_contact_buffer[256]; VG_STATIC int rb_contact_count = 0; +typedef struct rb_constr_pos rb_constr_pos; +typedef struct rb_constr_swingtwist rb_constr_swingtwist; + +struct rb_constr_pos +{ + rigidbody *rba, *rbb; + v3f lca, lcb; +}; + +struct rb_constr_swingtwist +{ + rigidbody *rba, *rbb; + + v4f conevx, conevy; /* relative to rba */ + v3f view_offset, /* relative to rba */ + coneva, conevxb;/* relative to rbb */ + + int tangent_violation, axis_violation; + v3f axis, tangent_axis, tangent_target, axis_target; + + float conet; + float tangent_mass, axis_mass; +}; + /* * ----------------------------------------------------------------------------- * Math Utils @@ -155,8 +205,8 @@ VG_STATIC void rb_debug_contact( rb_ct *ct ) if( ct->type != k_contact_type_disabled ) { v3f p1; - v3_muladds( ct->co, ct->n, 0.1f, p1 ); - vg_line_pt3( ct->co, 0.025f, 0xff0000ff ); + v3_muladds( ct->co, ct->n, 0.05f, p1 ); + vg_line_pt3( ct->co, 0.0025f, 0xff0000ff ); vg_line( ct->co, p1, 0xffffffff ); } } @@ -397,8 +447,8 @@ VG_STATIC void rb_init( rigidbody *rb ) h = rb->inf.capsule.height; volume = sphere_volume( r ) + VG_PIf * r*r * (h - r*2.0f); - v3_fill( rb->bbx[0], -rb->inf.sphere.radius ); - v3_fill( rb->bbx[1], rb->inf.sphere.radius ); + v3_fill( rb->bbx[0], -r ); + v3_fill( rb->bbx[1], r ); rb->bbx[0][1] = -h; rb->bbx[1][1] = h; } @@ -778,7 +828,7 @@ struct capsule_manifold * on the oriented object which created this pair. */ VG_STATIC void rb_capsule_manifold( v3f pa, v3f pb, float t, float r, - capsule_manifold *manifold ) + capsule_manifold *manifold ) { v3f delta; v3_sub( pa, pb, delta ); @@ -911,6 +961,9 @@ VG_STATIC int rb_capsule_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf ) VG_STATIC int rb_capsule_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf ) { + if( !box_overlap( rba->bbx_world, rbb->bbx_world ) ) + return 0; + float ha = rba->inf.capsule.height, hb = rbb->inf.capsule.height, ra = rba->inf.capsule.radius, @@ -1483,10 +1536,147 @@ VG_STATIC int rb_box_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf ) return count; } +/* + * Generates up to two contacts; optimised for the most stable manifold + */ +VG_STATIC int rb_capsule_triangle( rigidbody *rba, rigidbody *rbb, + v3f tri[3], rb_ct *buf ) +{ + float h = rba->inf.capsule.height, + r = rba->inf.capsule.radius; + + v3f pc, p0w, p1w; + v3_muladds( rba->co, rba->up, -h*0.5f+r, p0w ); + v3_muladds( rba->co, rba->up, h*0.5f-r, p1w ); + + capsule_manifold manifold; + rb_capsule_manifold_init( &manifold ); + + v3f c0, c1; + closest_on_triangle_1( p0w, tri, c0 ); + closest_on_triangle_1( p1w, tri, c1 ); + + v3f d0, d1, da; + v3_sub( c0, p0w, d0 ); + v3_sub( c1, p1w, d1 ); + v3_sub( p1w, p0w, da ); + + v3_normalize(d0); + v3_normalize(d1); + v3_normalize(da); + + if( v3_dot( da, d0 ) <= 0.01f ) + rb_capsule_manifold( p0w, c0, 0.0f, r, &manifold ); + + if( v3_dot( da, d1 ) >= -0.01f ) + rb_capsule_manifold( p1w, c1, 1.0f, r, &manifold ); + + for( int i=0; i<3; i++ ) + { + int i0 = i, + i1 = (i+1)%3; + + v3f ca, cb; + float ta, tb; + closest_segment_segment( p0w, p1w, tri[i0], tri[i1], &ta, &tb, ca, cb ); + rb_capsule_manifold( ca, cb, ta, r, &manifold ); + } + + v3f v0, v1, n; + v3_sub( tri[1], tri[0], v0 ); + v3_sub( tri[2], tri[0], v1 ); + v3_cross( v0, v1, n ); + v3_normalize( n ); + + int count = rb_capsule_manifold_done( rba, rbb, &manifold, buf ); + for( int i=0; iinf.capsule.height, + r = rba->inf.capsule.radius, + g = 90.8f; + + v3f p[2]; + v3_muladds( rba->co, rba->up, -h*0.5f+r, p[0] ); + v3_muladds( rba->co, rba->up, h*0.5f-r, p[1] ); + + int count = 0; + + + for( int i=0; i<2; i++ ) + { + if( p[i][1] < g + r ) + { + rb_ct *ct = &buf[ count ++ ]; + + v3_copy( p[i], ct->co ); + ct->p = r - (p[i][1]-g); + ct->co[1] -= r; + v3_copy( (v3f){0.0f,1.0f,0.0f}, ct->n ); + ct->rba = rba; + ct->rbb = rbb; + ct->type = k_contact_type_default; + } + } + + return count; + +#else + scene *sc = rbb->inf.scene.bh_scene->user; + + bh_iter it; + bh_iter_init( 0, &it ); + int idx; + + int count = 0; + + while( bh_next( rbb->inf.scene.bh_scene, &it, rba->bbx_world, &idx ) ) + { + u32 *ptri = &sc->arrindices[ idx*3 ]; + v3f tri[3]; + + for( int j=0; j<3; j++ ) + v3_copy( sc->arrvertices[ptri[j]].co, tri[j] ); + + buf[ count ].element_id = ptri[0]; + +#if 0 + vg_line( tri[0],tri[1],0x70ff6000 ); + vg_line( tri[1],tri[2],0x70ff6000 ); + vg_line( tri[2],tri[0],0x70ff6000 ); +#endif + + int contact = rb_capsule_triangle( rba, rbb, tri, buf+count ); + count += contact; + + if( count == 16 ) + { + vg_warn("Exceeding capsule_vs_scene capacity. Geometry too dense!\n"); + return count; + } + } + + return count; +#endif +} + +VG_STATIC int rb_scene_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf ) +{ + return rb_capsule_scene( rbb, rba, buf ); +} + VG_STATIC int RB_MATRIX_ERROR( rigidbody *rba, rigidbody *rbb, rb_ct *buf ) { +#if 0 vg_error( "Collision type is unimplemented between types %d and %d\n", rba->type, rbb->type ); +#endif return 0; } @@ -1516,8 +1706,8 @@ VG_STATIC int (*rb_jump_table[4][4])( rigidbody *a, rigidbody *b, rb_ct *buf ) = /* box */ /* Sphere */ /* Capsule */ /* Mesh */ { RB_MATRIX_ERROR, rb_box_sphere, rb_box_capsule, rb_box_scene }, { rb_sphere_box, rb_sphere_sphere, rb_sphere_capsule, rb_sphere_scene }, - { rb_capsule_box, rb_capsule_sphere, rb_capsule_capsule, RB_MATRIX_ERROR }, - { rb_scene_box, RB_MATRIX_ERROR, RB_MATRIX_ERROR, RB_MATRIX_ERROR } + { rb_capsule_box, rb_capsule_sphere, rb_capsule_capsule, rb_capsule_scene }, + { rb_scene_box, RB_MATRIX_ERROR, rb_scene_capsule, RB_MATRIX_ERROR } }; VG_STATIC int rb_collide( rigidbody *rba, rigidbody *rbb ) @@ -1619,21 +1809,15 @@ VG_STATIC void rb_presolve_contacts( rb_ct *buffer, int len ) } /* - * Creates relative contact velocity vector, and offsets between each body + * Creates relative contact velocity vector */ -VG_STATIC void rb_rcv( rb_ct *ct, v3f rv, v3f da, v3f db ) +VG_STATIC void rb_rcv( rigidbody *rba, rigidbody *rbb, v3f ra, v3f rb, v3f rv ) { - rigidbody *rba = ct->rba, - *rbb = ct->rbb; - - v3_sub( ct->co, rba->co, da ); - v3_sub( ct->co, rbb->co, db ); - v3f rva, rvb; - v3_cross( rba->w, da, rva ); - v3_add( rba->v, rva, rva ); - v3_cross( rbb->w, db, rvb ); - v3_add( rbb->v, rvb, rvb ); + v3_cross( rba->w, ra, rva ); + v3_add( rba->v, rva, rva ); + v3_cross( rbb->w, rb, rvb ); + v3_add( rbb->v, rvb, rvb ); v3_sub( rva, rvb, rv ); } @@ -1663,10 +1847,10 @@ VG_STATIC void rb_solve_contacts( rb_ct *buf, int len ) { struct contact *ct = &buf[i]; - rigidbody *rb = ct->rba; - - v3f rv, da, db; - rb_rcv( ct, rv, da, db ); + 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 ); /* Friction */ for( int j=0; j<2; j++ ) @@ -1681,14 +1865,14 @@ VG_STATIC void rb_solve_contacts( rb_ct *buf, int len ) v3f impulse; v3_muls( ct->t[j], lambda, impulse ); - rb_linear_impulse( ct->rba, da, impulse ); + rb_linear_impulse( ct->rba, ra, impulse ); v3_muls( ct->t[j], -lambda, impulse ); - rb_linear_impulse( ct->rbb, db, impulse ); + rb_linear_impulse( ct->rbb, rb, impulse ); } /* Normal */ - rb_rcv( ct, rv, da, db ); + rb_rcv( ct->rba, ct->rbb, ra, rb, rv ); float vn = v3_dot( rv, ct->n ), lambda = ct->normal_mass * (-vn + ct->bias); @@ -1698,10 +1882,10 @@ VG_STATIC void rb_solve_contacts( rb_ct *buf, int len ) v3f impulse; v3_muls( ct->n, lambda, impulse ); - rb_linear_impulse( ct->rba, da, impulse ); + rb_linear_impulse( ct->rba, ra, impulse ); v3_muls( ct->n, -lambda, impulse ); - rb_linear_impulse( ct->rbb, db, impulse ); + rb_linear_impulse( ct->rbb, rb, impulse ); } } @@ -1711,220 +1895,468 @@ VG_STATIC void rb_solve_contacts( rb_ct *buf, int len ) * ----------------------------------------------------------------------------- */ -VG_STATIC void draw_angle_limit( v3f c, v3f major, v3f minor, - float amin, float amax, float measured, - u32 colour ) +VG_STATIC void rb_debug_position_constraints( rb_constr_pos *buffer, int len ) { - float f = 0.05f; - v3f ay, ax; - v3_muls( major, f, ay ); - v3_muls( minor, f, ax ); - - for( int x=0; x<16; x++ ) + for( int i=0; irba, *rbb = constr->rbb; + + v3f wca, wcb; + m3x3_mulv( rba->to_world, constr->lca, wca ); + m3x3_mulv( rbb->to_world, constr->lcb, wcb ); v3f p0, p1; - v3_muladds( c, ay, cosf(a0), p0 ); - v3_muladds( p0, ax, sinf(a0), p0 ); - v3_muladds( c, ay, cosf(a1), p1 ); - v3_muladds( p1, ax, sinf(a1), p1 ); + v3_add( wca, rba->co, p0 ); + v3_add( wcb, rbb->co, p1 ); + vg_line_pt3( p0, 0.0025f, 0xff000000 ); + vg_line_pt3( p1, 0.0025f, 0xffffffff ); + vg_line2( p0, p1, 0xff000000, 0xffffffff ); + } +} + +VG_STATIC void rb_presolve_swingtwist_constraints( rb_constr_swingtwist *buf, + int len ) +{ + float size = 0.12f; + + for( int i=0; irba->to_world, st->conevx, vx ); + m3x3_mulv( st->rbb->to_world, st->conevxb, vxb ); + m3x3_mulv( st->rba->to_world, st->conevy, vy ); + m3x3_mulv( st->rbb->to_world, st->coneva, va ); + m4x3_mulv( st->rba->to_world, st->view_offset, center ); + v3_cross( vy, vx, axis ); + + /* Constraint violated ? */ + float fx = v3_dot( vx, va ), /* projection world */ + fy = v3_dot( vy, va ), + fn = v3_dot( va, axis ), + + rx = st->conevx[3], /* elipse radii */ + ry = st->conevy[3], + + lx = fx/rx, /* projection local (fn==lz) */ + ly = fy/ry; + + st->tangent_violation = ((lx*lx + ly*ly) > fn*fn) || (fn <= 0.0f); + if( st->tangent_violation ) + { + /* Calculate a good position and the axis to solve on */ + v2f closest, tangent, + p = { fx/fabsf(fn), fy/fabsf(fn) }; + + closest_point_elipse( p, (v2f){rx,ry}, closest ); + tangent[0] = -closest[1] / (ry*ry); + tangent[1] = closest[0] / (rx*rx); + v2_normalize( tangent ); + + v3f v0, v1; + v3_muladds( axis, vx, closest[0], v0 ); + v3_muladds( v0, vy, closest[1], v0 ); + v3_normalize( v0 ); + + v3_muls( vx, tangent[0], v1 ); + v3_muladds( v1, vy, tangent[1], v1 ); + + v3_copy( v0, st->tangent_target ); + v3_copy( v1, st->tangent_axis ); + + /* calculate mass */ + v3f aIw, bIw; + m3x3_mulv( st->rba->iIw, st->tangent_axis, aIw ); + m3x3_mulv( st->rbb->iIw, st->tangent_axis, bIw ); + st->tangent_mass = 1.0f / (v3_dot( st->tangent_axis, aIw ) + + v3_dot( st->tangent_axis, bIw )); + + float angle = v3_dot( va, st->tangent_target ); + } + + v3f refaxis; + v3_cross( vy, va, refaxis ); /* our default rotation */ + v3_normalize( refaxis ); + + float angle = v3_dot( refaxis, vxb ); + st->axis_violation = fabsf(angle) < st->conet; - v3f p2; - v3_muladds( c, ay, cosf(measured)*1.2f, p2 ); - v3_muladds( p2, ax, sinf(measured)*1.2f, p2 ); - vg_line( c, p2, colour ); + if( st->axis_violation ) + { + v3f dir_test; + v3_cross( refaxis, vxb, dir_test ); + + if( v3_dot(dir_test, va) < 0.0f ) + st->axis_violation = -st->axis_violation; + + float newang = (float)st->axis_violation * acosf(st->conet-0.0001f); + + v3f refaxis_up; + v3_cross( va, refaxis, refaxis_up ); + v3_muls( refaxis_up, sinf(newang), st->axis_target ); + v3_muladds( st->axis_target, refaxis, -cosf(newang), st->axis_target ); + + /* calculate mass */ + v3_copy( va, st->axis ); + v3f aIw, bIw; + m3x3_mulv( st->rba->iIw, st->axis, aIw ); + m3x3_mulv( st->rbb->iIw, st->axis, bIw ); + st->axis_mass = 1.0f / (v3_dot( st->axis, aIw ) + + v3_dot( st->axis, bIw )); + } + } } -VG_STATIC void rb_debug_constraint_limits( rigidbody *ra, rigidbody *rb, v3f lca, - v3f limits[2] ) +VG_STATIC void rb_debug_swingtwist_constraints( rb_constr_swingtwist *buf, + int len ) { - v3f ax, ay, az, bx, by, bz; - m3x3_mulv( ra->to_world, (v3f){1.0f,0.0f,0.0f}, ax ); - m3x3_mulv( ra->to_world, (v3f){0.0f,1.0f,0.0f}, ay ); - m3x3_mulv( ra->to_world, (v3f){0.0f,0.0f,1.0f}, az ); - m3x3_mulv( rb->to_world, (v3f){1.0f,0.0f,0.0f}, bx ); - m3x3_mulv( rb->to_world, (v3f){0.0f,1.0f,0.0f}, by ); - m3x3_mulv( rb->to_world, (v3f){0.0f,0.0f,1.0f}, bz ); + float size = 0.12f; + + for( int i=0; irba->to_world, st->conevx, vx ); + m3x3_mulv( st->rbb->to_world, st->conevxb, vxb ); + m3x3_mulv( st->rba->to_world, st->conevy, vy ); + m3x3_mulv( st->rbb->to_world, st->coneva, va ); + m4x3_mulv( st->rba->to_world, st->view_offset, center ); + v3_cross( vy, vx, axis ); + + float rx = st->conevx[3], /* elipse radii */ + ry = st->conevy[3]; + + v3f p0, p1; + v3_muladds( center, va, size, p1 ); + vg_line( center, p1, 0xffffffff ); + vg_line_pt3( p1, 0.00025f, 0xffffffff ); + + if( st->tangent_violation ) + { + v3_muladds( center, st->tangent_target, size, p0 ); + + vg_line( center, p0, 0xff00ff00 ); + vg_line_pt3( p0, 0.00025f, 0xff00ff00 ); + vg_line( p1, p0, 0xff000000 ); + } + + for( int x=0; x<32; x++ ) + { + float t0 = ((float)x * (1.0f/32.0f)) * VG_TAUf, + t1 = (((float)x+1.0f) * (1.0f/32.0f)) * VG_TAUf, + c0 = cosf( t0 ), + s0 = sinf( t0 ), + c1 = cosf( t1 ), + s1 = sinf( t1 ); + + v3f v0, v1; + v3_muladds( axis, vx, c0*rx, v0 ); + v3_muladds( v0, vy, s0*ry, v0 ); + v3_muladds( axis, vx, c1*rx, v1 ); + v3_muladds( v1, vy, s1*ry, v1 ); + + v3_normalize( v0 ); + v3_normalize( v1 ); + + v3_muladds( center, v0, size, p0 ); + v3_muladds( center, v1, size, p1 ); + + u32 col0r = fabsf(c0) * 255.0f, + col0g = fabsf(s0) * 255.0f, + col1r = fabsf(c1) * 255.0f, + col1g = fabsf(s1) * 255.0f, + col = st->tangent_violation? 0xff0000ff: 0xff000000, + col0 = col | (col0r<<16) | (col0g << 8), + col1 = col | (col1r<<16) | (col1g << 8); + + vg_line2( center, p0, VG__NONE, col0 ); + vg_line2( p0, p1, col0, col1 ); + } - v2f px, py, pz; - px[0] = v3_dot( ay, by ); - px[1] = v3_dot( az, by ); + /* Draw twist */ + v3_muladds( center, va, size, p0 ); + v3_muladds( p0, vxb, size, p1 ); - py[0] = v3_dot( az, bz ); - py[1] = v3_dot( ax, bz ); + vg_line( p0, p1, 0xff0000ff ); - pz[0] = v3_dot( ax, bx ); - pz[1] = v3_dot( ay, bx ); + if( st->axis_violation ) + { + v3_muladds( p0, st->axis_target, size*1.25f, p1 ); + vg_line( p0, p1, 0xffffff00 ); + vg_line_pt3( p1, 0.0025f, 0xffffff80 ); + } - float r0 = atan2f( px[1], px[0] ), - r1 = atan2f( py[1], py[0] ), - r2 = atan2f( pz[1], pz[0] ); + v3f refaxis; + v3_cross( vy, va, refaxis ); /* our default rotation */ + v3_normalize( refaxis ); + v3f refaxis_up; + v3_cross( va, refaxis, refaxis_up ); + float newang = acosf(st->conet-0.0001f); - v3f c; - m4x3_mulv( ra->to_world, lca, c ); - draw_angle_limit( c, ay, az, limits[0][0], limits[1][0], r0, 0xff0000ff ); - draw_angle_limit( c, az, ax, limits[0][1], limits[1][1], r1, 0xff00ff00 ); - draw_angle_limit( c, ax, ay, limits[0][2], limits[1][2], r2, 0xffff0000 ); + v3_muladds( p0, refaxis_up, sinf(newang)*size, p1 ); + v3_muladds( p1, refaxis, -cosf(newang)*size, p1 ); + vg_line( p0, p1, 0xff000000 ); + + v3_muladds( p0, refaxis_up, sinf(-newang)*size, p1 ); + v3_muladds( p1, refaxis, -cosf(-newang)*size, p1 ); + vg_line( p0, p1, 0xff404040 ); + } } -VG_STATIC void rb_limit_cure( rigidbody *ra, rigidbody *rb, v3f axis, float d ) +/* + * Solve a list of positional constraints + */ +VG_STATIC void rb_solve_position_constraints( rb_constr_pos *buf, int len ) { - if( d != 0.0f ) + for( int i=0; iw, axis ) - v3_dot( rb->w, axis ); - float joint_mass = rb->inv_mass + ra->inv_mass; - joint_mass = 1.0f/joint_mass; + rb_constr_pos *constr = &buf[i]; + rigidbody *rba = constr->rba, *rbb = constr->rbb; - float bias = (k_limit_bias * k_rb_rate) * d, - lambda = -(avx + bias) * joint_mass; - - /* Angular velocity */ v3f wa, wb; - v3_muls( axis, lambda * ra->inv_mass, wa ); - v3_muls( axis, -lambda * rb->inv_mass, wb ); + m3x3_mulv( rba->to_world, constr->lca, wa ); + m3x3_mulv( rbb->to_world, constr->lcb, wb ); - v3_add( ra->w, wa, ra->w ); - v3_add( rb->w, wb, rb->w ); + m3x3f ssra, ssrat, ssrb, ssrbt; + + m3x3_skew_symetric( ssrat, wa ); + m3x3_skew_symetric( ssrbt, wb ); + m3x3_transpose( ssrat, ssra ); + m3x3_transpose( ssrbt, ssrb ); + + v3f b, b_wa, b_wb, b_a, b_b; + m3x3_mulv( ssra, rba->w, b_wa ); + m3x3_mulv( ssrb, rbb->w, b_wb ); + v3_add( rba->v, b_wa, b ); + v3_sub( b, rbb->v, b ); + v3_sub( b, b_wb, b ); + v3_muls( b, -1.0f, b ); + + m3x3f invMa, invMb; + m3x3_diagonal( invMa, rba->inv_mass ); + m3x3_diagonal( invMb, rbb->inv_mass ); + + m3x3f ia, ib; + m3x3_mul( ssra, rba->iIw, ia ); + m3x3_mul( ia, ssrat, ia ); + m3x3_mul( ssrb, rbb->iIw, ib ); + m3x3_mul( ib, ssrbt, ib ); + + m3x3f cma, cmb; + m3x3_add( invMa, ia, cma ); + m3x3_add( invMb, ib, cmb ); + + m3x3f A; + m3x3_add( cma, cmb, A ); + + /* Solve Ax = b ( A^-1*b = x ) */ + v3f impulse; + m3x3f invA; + m3x3_inv( A, invA ); + m3x3_mulv( invA, b, impulse ); + + v3f delta_va, delta_wa, delta_vb, delta_wb; + m3x3f iwa, iwb; + m3x3_mul( rba->iIw, ssrat, iwa ); + m3x3_mul( rbb->iIw, ssrbt, iwb ); + + m3x3_mulv( invMa, impulse, delta_va ); + m3x3_mulv( invMb, impulse, delta_vb ); + m3x3_mulv( iwa, impulse, delta_wa ); + m3x3_mulv( iwb, impulse, delta_wb ); + + v3_add( rba->v, delta_va, rba->v ); + v3_add( rba->w, delta_wa, rba->w ); + v3_sub( rbb->v, delta_vb, rbb->v ); + v3_sub( rbb->w, delta_wb, rbb->w ); } } -VG_STATIC void rb_constraint_limits( rigidbody *ra, v3f lca, - rigidbody *rb, v3f lcb, v3f limits[2] ) +VG_STATIC void rb_solve_swingtwist_constraints( rb_constr_swingtwist *buf, + int len ) { - v3f ax, ay, az, bx, by, bz; - m3x3_mulv( ra->to_world, (v3f){1.0f,0.0f,0.0f}, ax ); - m3x3_mulv( ra->to_world, (v3f){0.0f,1.0f,0.0f}, ay ); - m3x3_mulv( ra->to_world, (v3f){0.0f,0.0f,1.0f}, az ); - m3x3_mulv( rb->to_world, (v3f){1.0f,0.0f,0.0f}, bx ); - m3x3_mulv( rb->to_world, (v3f){0.0f,1.0f,0.0f}, by ); - m3x3_mulv( rb->to_world, (v3f){0.0f,0.0f,1.0f}, bz ); + float size = 0.12f; + + for( int i=0; iaxis_violation ) + continue; + + float rv = v3_dot( st->axis, st->rbb->w ) - + v3_dot( st->axis, st->rba->w ); + + if( rv * (float)st->axis_violation > 0.0f ) + continue; + + v3f impulse, wa, wb; + v3_muls( st->axis, rv*st->axis_mass, impulse ); + m3x3_mulv( st->rba->iIw, impulse, wa ); + v3_add( st->rba->w, wa, st->rba->w ); - v2f px, py, pz; - px[0] = v3_dot( ay, by ); - px[1] = v3_dot( az, by ); + v3_muls( impulse, -1.0f, impulse ); + m3x3_mulv( st->rbb->iIw, impulse, wb ); + v3_add( st->rbb->w, wb, st->rbb->w ); - py[0] = v3_dot( az, bz ); - py[1] = v3_dot( ax, bz ); + float rv2 = v3_dot( st->axis, st->rbb->w ) - + v3_dot( st->axis, st->rba->w ); + } - pz[0] = v3_dot( ax, bx ); - pz[1] = v3_dot( ay, bx ); + for( int i=0; itangent_violation ) + continue; - /* calculate angle deltas */ - float dx = 0.0f, dy = 0.0f, dz = 0.0f; + float rv = v3_dot( st->tangent_axis, st->rbb->w ) - + v3_dot( st->tangent_axis, st->rba->w ); - if( r0 < limits[0][0] ) dx = limits[0][0] - r0; - if( r0 > limits[1][0] ) dx = limits[1][0] - r0; - if( r1 < limits[0][1] ) dy = limits[0][1] - r1; - if( r1 > limits[1][1] ) dy = limits[1][1] - r1; - if( r2 < limits[0][2] ) dz = limits[0][2] - r2; - if( r2 > limits[1][2] ) dz = limits[1][2] - r2; + if( rv > 0.0f ) + continue; + + v3f impulse, wa, wb; + v3_muls( st->tangent_axis, rv*st->tangent_mass, impulse ); + m3x3_mulv( st->rba->iIw, impulse, wa ); + v3_add( st->rba->w, wa, st->rba->w ); - v3f wca, wcb; - m3x3_mulv( ra->to_world, lca, wca ); - m3x3_mulv( rb->to_world, lcb, wcb ); + v3_muls( impulse, -1.0f, impulse ); + m3x3_mulv( st->rbb->iIw, impulse, wb ); + v3_add( st->rbb->w, wb, st->rbb->w ); - rb_limit_cure( ra, rb, ax, dx ); - rb_limit_cure( ra, rb, ay, dy ); - rb_limit_cure( ra, rb, az, dz ); + float rv2 = v3_dot( st->tangent_axis, st->rbb->w ) - + v3_dot( st->tangent_axis, st->rba->w ); + } } -VG_STATIC void rb_debug_constraint_position( rigidbody *ra, v3f lca, - rigidbody *rb, v3f lcb ) +VG_STATIC void rb_solve_constr_angle( rigidbody *rba, rigidbody *rbb, + v3f ra, v3f rb ) { - v3f wca, wcb; - m3x3_mulv( ra->to_world, lca, wca ); - m3x3_mulv( rb->to_world, lcb, wcb ); + m3x3f ssra, ssrb, ssrat, ssrbt; + m3x3f cma, cmb; + + m3x3_skew_symetric( ssrat, ra ); + m3x3_skew_symetric( ssrbt, rb ); + m3x3_transpose( ssrat, ssra ); + m3x3_transpose( ssrbt, ssrb ); + + m3x3_mul( ssra, rba->iIw, cma ); + m3x3_mul( cma, ssrat, cma ); + m3x3_mul( ssrb, rbb->iIw, cmb ); + m3x3_mul( cmb, ssrbt, cmb ); + + m3x3f A, invA; + m3x3_add( cma, cmb, A ); + m3x3_inv( A, invA ); + + v3f b_wa, b_wb, b; + m3x3_mulv( ssra, rba->w, b_wa ); + m3x3_mulv( ssrb, rbb->w, b_wb ); + v3_add( b_wa, b_wb, b ); + v3_negate( b, b ); + + v3f impulse; + m3x3_mulv( invA, b, impulse ); + + v3f delta_wa, delta_wb; + m3x3f iwa, iwb; + m3x3_mul( rba->iIw, ssrat, iwa ); + m3x3_mul( rbb->iIw, ssrbt, iwb ); + m3x3_mulv( iwa, impulse, delta_wa ); + m3x3_mulv( iwb, impulse, delta_wb ); + v3_add( rba->w, delta_wa, rba->w ); + v3_sub( rbb->w, delta_wb, rbb->w ); +} - v3f p0, p1; - v3_add( wca, ra->co, p0 ); - v3_add( wcb, rb->co, p1 ); - vg_line_pt3( p0, 0.005f, 0xffffff00 ); - vg_line_pt3( p1, 0.005f, 0xffffff00 ); - vg_line( p0, p1, 0xffffff00 ); +/* + * Correct position constraint drift errors + * [ 0.0 <= amt <= 1.0 ]: the correction amount + */ +VG_STATIC void rb_correct_position_constraints( rb_constr_pos *buf, int len, + float amt ) +{ + for( int i=0; irba, *rbb = constr->rbb; + + v3f p0, p1, d; + m3x3_mulv( rba->to_world, constr->lca, p0 ); + m3x3_mulv( rbb->to_world, constr->lcb, p1 ); + v3_add( rba->co, p0, p0 ); + v3_add( rbb->co, p1, p1 ); + v3_sub( p1, p0, d ); + + v3_muladds( rbb->co, d, -1.0f * amt, rbb->co ); + rb_update_transform( rbb ); + } } -VG_STATIC void rb_constraint_position( rigidbody *ra, v3f lca, - rigidbody *rb, v3f lcb ) +VG_STATIC void rb_correct_swingtwist_constraints( rb_constr_swingtwist *buf, + int len, float amt ) { - /* C = (COa + Ra*LCa) - (COb + Rb*LCb) = 0 */ - v3f wca, wcb; - m3x3_mulv( ra->to_world, lca, wca ); - m3x3_mulv( rb->to_world, lcb, wcb ); + for( int i=0; iv, rb->v, rcv ); + if( !st->tangent_violation ) + continue; - v3f rcv_Ra, rcv_Rb; - v3_cross( ra->w, wca, rcv_Ra ); - v3_cross( rb->w, wcb, rcv_Rb ); - v3_add( rcv_Ra, rcv, rcv ); - v3_sub( rcv, rcv_Rb, rcv ); + v3f va; + m3x3_mulv( st->rbb->to_world, st->coneva, va ); - v3f delta; - v3f p0, p1; - v3_add( wca, ra->co, p0 ); - v3_add( wcb, rb->co, p1 ); - v3_sub( p1, p0, delta ); + float angle = v3_dot( va, st->tangent_target ); - float dist2 = v3_length2( delta ); + if( fabsf(angle) < 0.9999f ) + { + v3f axis; + v3_cross( va, st->tangent_target, axis ); - if( dist2 > 0.00001f ) + v4f correction; + q_axis_angle( correction, axis, acosf(angle) * amt ); + q_mul( correction, st->rbb->q, st->rbb->q ); + rb_update_transform( st->rbb ); + } + } + + for( int i=0; iinv_mass + ra->inv_mass; + if( !st->axis_violation ) + continue; - v3f raCn, rbCn, raCt, rbCt; - v3_cross( wca, delta, raCn ); - v3_cross( wcb, delta, rbCn ); - - /* orient inverse inertia tensors */ - v3f raCnI, rbCnI; - m3x3_mulv( ra->iIw, raCn, raCnI ); - m3x3_mulv( rb->iIw, rbCn, rbCnI ); - joint_mass += v3_dot( raCn, raCnI ); - joint_mass += v3_dot( rbCn, rbCnI ); - joint_mass = 1.0f/joint_mass; + v3f vxb; + m3x3_mulv( st->rbb->to_world, st->conevxb, vxb ); - float vd = v3_dot( rcv, delta ), - bias = -(k_joint_bias * k_rb_rate) * dist, - lambda = -(vd + bias) * joint_mass; + float angle = v3_dot( vxb, st->axis_target ); - v3f impulse; - v3_muls( delta, lambda, impulse ); - rb_linear_impulse( ra, wca, impulse ); - v3_muls( delta, -lambda, impulse ); - rb_linear_impulse( rb, wcb, impulse ); - - /* 'fake' snap */ - v3_muladds( ra->co, delta, dist * k_joint_correction, ra->co ); - v3_muladds( rb->co, delta, -dist * k_joint_correction, rb->co ); + if( fabsf(angle) < 0.9999f ) + { + v3f axis; + v3_cross( vxb, st->axis_target, axis ); + + v4f correction; + q_axis_angle( correction, axis, acosf(angle) * amt ); + q_mul( correction, st->rbb->q, st->rbb->q ); + rb_update_transform( st->rbb ); + } } } + /* * Effectors */ VG_STATIC void rb_effect_simple_bouyency( rigidbody *ra, v4f plane, - float amt, float drag ) + float amt, float drag ) { /* float */ float depth = v3_dot( plane, ra->co ) - plane[3], diff --git a/scene.h b/scene.h index 7fc29f3..8fffe97 100644 --- a/scene.h +++ b/scene.h @@ -4,7 +4,6 @@ #include "common.h" #include "model.h" #include "bvh.h" -#include "distq.h" typedef struct scene scene; diff --git a/skaterift.c b/skaterift.c index f31e1f6..9d72bec 100644 --- a/skaterift.c +++ b/skaterift.c @@ -2,7 +2,7 @@ * ============================================================================= * * Copyright . . . -----, ,----- ,---. .---. - * 2021-2022 |\ /| | / | | | | /| + * 2021-2023 |\ /| | / | | | | /| * | \ / | +-- / +----- +---' | / | * | \ / | | / | | \ | / | * | \/ | | / | | \ | / | diff --git a/skeleton.h b/skeleton.h index 9f715ef..4f35d58 100644 --- a/skeleton.h +++ b/skeleton.h @@ -14,16 +14,14 @@ struct skeleton v3f co, end; u32 parent; - int deform, ik; + u32 flags; int defer; mdl_keyframe kf; u32 orig_node; - int collider; boxf hitbox; - const char *name; } *bones; @@ -155,7 +153,8 @@ VG_STATIC int should_apply_bone( struct skeleton *skele, u32 id, anim_apply type if( type == k_anim_apply_defer_ik ) { - if( (sp->ik && !sb->ik) || sp->defer ) + if( ((sp->flags & k_bone_flag_ik) && !(sb->flags & k_bone_flag_ik)) + || sp->defer ) { sb->defer = 1; return 0; @@ -185,7 +184,7 @@ VG_STATIC void skeleton_apply_pose( struct skeleton *skele, mdl_keyframe *pose, { m4x3_identity( skele->final_mtx[0] ); skele->bones[0].defer = 0; - skele->bones[0].ik = 0; + skele->bones[0].flags &= ~k_bone_flag_ik; for( int i=1; ibone_count; i++ ) { @@ -454,18 +453,16 @@ VG_STATIC void skeleton_setup( struct skeleton *skele, struct skeleton_bone *sb = &skele->bones[bone_count]; struct classtype_bone *bone_inf = mdl_get_entdata( mdl, pnode ); - int is_ik = bone_inf->ik_target; v3_copy( pnode->co, sb->co ); v3_copy( pnode->s, sb->end ); sb->parent = pnode->parent-skeleton_root; sb->name = mdl_pstr( mdl, pnode->pstr_name ); - sb->deform = bone_inf->deform; + sb->flags = bone_inf->flags; - if( is_ik ) + if( sb->flags & k_bone_flag_ik ) { - sb->ik = 1; /* TODO: place into new IK array */ - skele->bones[ sb->parent ].ik = 1; + skele->bones[ sb->parent ].flags |= k_bone_flag_ik; if( ik_count == skele->ik_count ) { @@ -479,16 +476,11 @@ VG_STATIC void skeleton_setup( struct skeleton *skele, ik->target = bone_inf->ik_target; ik->pole = bone_inf->ik_pole; } - else - { - sb->ik = 0; - } - sb->collider = bone_inf->collider; sb->orig_node = i; box_copy( bone_inf->hitbox, sb->hitbox ); - if( bone_inf->collider ) + if( bone_inf->flags & k_bone_flag_collider_any ) { if( collider_count == skele->collider_count ) { @@ -538,7 +530,7 @@ VG_STATIC void skeleton_setup( struct skeleton *skele, v3_zero( skele->bones[0].co ); v3_copy( (v3f){0.0f,1.0f,0.0f}, skele->bones[0].end ); skele->bones[0].parent = 0xffffffff; - skele->bones[0].collider = 0; + skele->bones[0].flags = 0; skele->bones[0].name = "[root]"; /* process animation quick refs */ @@ -575,9 +567,9 @@ VG_STATIC void skeleton_debug( struct skeleton *skele ) m4x3_mulv( skele->final_mtx[i], p0, p0 ); m4x3_mulv( skele->final_mtx[i], p1, p1 ); - if( sb->deform ) + if( sb->flags & k_bone_flag_deform ) { - if( sb->ik ) + if( sb->flags & k_bone_flag_ik ) { vg_line( p0, p1, 0xff0000ff ); }