int collider;
boxf hitbox;
- char name[16];
+ const char *name;
}
*bones;
+ u32 bone_count;
+
+ struct skeleton_anim
+ {
+ const char *name;
+ u32 length;
+
+ float rate;
+ mdl_keyframe *anim_data;
+ }
+ *anims;
+ u32 anim_count;
+
m4x3f *final_mtx;
struct skeleton_ik
m3x3f ia, ib;
}
*ik;
+ u32 ik_count;
- struct skeleton_anim
- {
- float rate;
- u32 length;
- struct mdl_keyframe *anim_data;
- char name[32];
- }
- *anims;
-
- u32 bone_count,
- ik_count,
+ u32
collider_count,
- anim_count,
- bindable_count; /* TODO: try to place IK last in the rig from export
- so that we dont always upload transforms for
- useless cpu IK bones. */
+ bindable_count;
};
-static u32 skeleton_bone_id( struct skeleton *skele, const char *name )
+VG_STATIC u32 skeleton_bone_id( struct skeleton *skele, const char *name )
{
- for( u32 i=0; i<skele->bone_count; i++ )
+ for( u32 i=1; i<skele->bone_count; i++ )
{
if( !strcmp( skele->bones[i].name, name ))
return i;
return 0;
}
-static void keyframe_copy_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, int num )
+VG_STATIC void keyframe_copy_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, int num )
{
for( int i=0; i<num; i++ )
kfb[i] = kfa[i];
/*
* Lerp between two sets of keyframes and store in dest. Rotations use Nlerp.
*/
-static void keyframe_lerp_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, float t,
+VG_STATIC void keyframe_lerp_pose( mdl_keyframe *kfa, mdl_keyframe *kfb, float t,
mdl_keyframe *kfd, int count )
{
if( t <= 0.01f )
}
}
-static void skeleton_lerp_pose( struct skeleton *skele,
+VG_STATIC void skeleton_lerp_pose( struct skeleton *skele,
mdl_keyframe *kfa, mdl_keyframe *kfb, float t,
mdl_keyframe *kfd )
{
* Sample animation between 2 closest frames using time value. Output is a
* keyframe buffer that is allocated with an appropriate size
*/
-static void skeleton_sample_anim( struct skeleton *skele,
+VG_STATIC void skeleton_sample_anim( struct skeleton *skele,
struct skeleton_anim *anim,
float time,
mdl_keyframe *output )
skeleton_lerp_pose( skele, base, nbase, t, output );
}
-static int skeleton_sample_anim_clamped( struct skeleton *skele,
+VG_STATIC int skeleton_sample_anim_clamped( struct skeleton *skele,
struct skeleton_anim *anim,
float time,
mdl_keyframe *output )
}
anim_apply;
-static int should_apply_bone( struct skeleton *skele, u32 id, anim_apply type )
+VG_STATIC int should_apply_bone( struct skeleton *skele, u32 id, anim_apply type )
{
struct skeleton_bone *sb = &skele->bones[ id ],
*sp = &skele->bones[ sb->parent ];
/*
* Apply block of keyframes to skeletons final pose
*/
-static void skeleton_apply_pose( struct skeleton *skele, mdl_keyframe *pose,
+VG_STATIC void skeleton_apply_pose( struct skeleton *skele, mdl_keyframe *pose,
anim_apply passtype )
{
m4x3_identity( skele->final_mtx[0] );
* creates the reference inverse matrix for an IK bone, as it has an initial
* intrisic rotation based on the direction that the IK is setup..
*/
-static void skeleton_inverse_for_ik( struct skeleton *skele,
+VG_STATIC void skeleton_inverse_for_ik( struct skeleton *skele,
v3f ivaxis,
u32 id, m3x3f inverse )
{
/*
* Creates inverse rotation matrices which the IK system uses.
*/
-static void skeleton_create_inverses( struct skeleton *skele )
+VG_STATIC void skeleton_create_inverses( struct skeleton *skele )
{
/* IK: inverse 'plane-bone space' axis '(^axis,^bone,...)[base] */
for( int i=0; i<skele->ik_count; i++ )
m4x3f inverse;
v3f iv0, iv1, ivaxis;
v3_sub( skele->bones[ik->target].co, skele->bones[ik->lower].co, iv0 );
- v3_sub( skele->bones[ik->pole].co, skele->bones[ik->lower].co, iv1 );
+ v3_sub( skele->bones[ik->pole].co, skele->bones[ik->lower].co, iv1 );
v3_cross( iv0, iv1, ivaxis );
v3_normalize( ivaxis );
/*
* Apply a model matrix to all bones, should be done last
*/
-static void skeleton_apply_transform( struct skeleton *skele, m4x3f transform )
+VG_STATIC void skeleton_apply_transform( struct skeleton *skele, m4x3f transform )
{
for( int i=0; i<skele->bone_count; i++ )
{
* Apply an inverse matrix to all bones which maps vertices from bind space into
* bone relative positions
*/
-static void skeleton_apply_inverses( struct skeleton *skele )
+VG_STATIC void skeleton_apply_inverses( struct skeleton *skele )
{
for( int i=0; i<skele->bone_count; i++ )
{
/*
* Apply all IK modifiers (2 bone ik reference from blender is supported)
*/
-static void skeleton_apply_ik_pass( struct skeleton *skele )
+VG_STATIC void skeleton_apply_ik_pass( struct skeleton *skele )
{
for( int i=0; i<skele->ik_count; i++ )
{
* Applies the typical operations that you want for an IK rig:
* Pose, IK, Pose(deferred), Inverses, Transform
*/
-static void skeleton_apply_standard( struct skeleton *skele, mdl_keyframe *pose,
+VG_STATIC void skeleton_apply_standard( struct skeleton *skele, mdl_keyframe *pose,
m4x3f transform )
{
skeleton_apply_pose( skele, pose, k_anim_apply_defer_ik );
/*
* Get an animation by name
*/
-static struct skeleton_anim *skeleton_get_anim( struct skeleton *skele,
+VG_STATIC struct skeleton_anim *skeleton_get_anim( struct skeleton *skele,
const char *name )
{
for( int i=0; i<skele->anim_count; i++ )
return NULL;
}
-/* Setup an animated skeleton from model */
-static int skeleton_setup( struct skeleton *skele, mdl_header *mdl )
+VG_STATIC void skeleton_alloc_from( struct skeleton *skele,
+ void *lin_alloc,
+ struct classtype_skeleton *inf )
+{
+ skele->bone_count = inf->channels;
+ skele->ik_count = inf->ik_count;
+ skele->collider_count = inf->collider_count;
+ skele->anim_count = inf->anim_count;
+
+ u32 bone_size = sizeof(struct skeleton_bone) * skele->bone_count,
+ ik_size = sizeof(struct skeleton_ik) * skele->ik_count,
+ mtx_size = sizeof(m4x3f) * skele->bone_count,
+ anim_size = sizeof(struct skeleton_anim) * skele->anim_count;
+
+ skele->bones = vg_linear_alloc( lin_alloc, bone_size );
+ skele->ik = vg_linear_alloc( lin_alloc, ik_size );
+ skele->final_mtx = vg_linear_alloc( lin_alloc, mtx_size );
+ skele->anims = vg_linear_alloc( lin_alloc, anim_size );
+}
+
+VG_STATIC void skeleton_fatal_err(void)
+{
+ vg_fatal_exit_loop( "Skeleton setup failed" );
+}
+
+/* Setup an animated skeleton from model. mdl's metadata should stick around */
+VG_STATIC void skeleton_setup( struct skeleton *skele,
+ void *lin_alloc, mdl_context *mdl )
{
u32 bone_count = 1, skeleton_root = 0, ik_count = 0, collider_count = 0;
skele->bone_count = 0;
struct classtype_skeleton *inf = NULL;
- for( u32 i=0; i<mdl->node_count; i++ )
+ for( u32 i=0; i<mdl->info.node_count; i++ )
{
mdl_node *pnode = mdl_node_from_id( mdl, i );
if( pnode->classtype == k_classtype_skeleton )
{
inf = mdl_get_entdata( mdl, pnode );
- if( skele->bone_count )
- {
- vg_error( "Multiple skeletons in model file\n" );
- goto error_dealloc;
- }
-
- skele->bone_count = inf->channels;
- skele->ik_count = inf->ik_count;
- skele->collider_count = inf->collider_count;
- skele->bones =vg_alloc(sizeof(struct skeleton_bone)*skele->bone_count);
- skele->ik = vg_alloc(sizeof(struct skeleton_ik)*skele->ik_count);
+ skeleton_alloc_from( skele, lin_alloc, inf );
skeleton_root = i;
}
else if( skele->bone_count )
bone_count, skele->bone_count,
mdl_pstr( mdl, pnode->pstr_name ));
- goto error_dealloc;
+ skeleton_fatal_err();
}
struct skeleton_bone *sb = &skele->bones[bone_count];
v3_copy( pnode->co, sb->co );
v3_copy( pnode->s, sb->end );
sb->parent = pnode->parent-skeleton_root;
- strncpy( sb->name, mdl_pstr(mdl,pnode->pstr_name), 15 );
+ sb->name = mdl_pstr( mdl, pnode->pstr_name );
sb->deform = bone_inf->deform;
if( is_ik )
if( ik_count == skele->ik_count )
{
vg_error( "Too many ik bones, corrupt model file\n" );
- goto error_dealloc;
+ skeleton_fatal_err();
}
struct skeleton_ik *ik = &skele->ik[ ik_count ++ ];
if( collider_count == skele->collider_count )
{
vg_error( "Too many collider bones\n" );
- goto error_dealloc;
+ skeleton_fatal_err();
}
collider_count ++;
if( !inf )
{
vg_error( "No skeleton in model\n" );
- return 0;
+ skeleton_fatal_err();
}
if( collider_count != skele->collider_count )
{
vg_error( "Loaded %u colliders out of %u\n", collider_count,
- skele->collider_count );
- goto error_dealloc;
+ skele->collider_count );
+ skeleton_fatal_err();
}
if( bone_count != skele->bone_count )
{
vg_error( "Loaded %u bones out of %u\n", bone_count, skele->bone_count );
- goto error_dealloc;
+ vg_fatal_exit_loop( "Skeleton setup failed" );
+ skeleton_fatal_err();
}
if( ik_count != skele->ik_count )
{
vg_error( "Loaded %u ik bones out of %u\n", ik_count, skele->ik_count );
- goto error_dealloc;
+ skeleton_fatal_err();
}
/* fill in implicit root bone */
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].name = "[root]";
- skele->final_mtx = vg_alloc( sizeof(m4x3f) * skele->bone_count );
- skele->anim_count = inf->anim_count;
- skele->anims = vg_alloc( sizeof(struct skeleton_anim) * inf->anim_count);
-
- for( int i=0; i<inf->anim_count; i++ )
+ /* process animation quick refs */
+ for( int i=0; i<skele->anim_count; i++ )
{
- mdl_animation *anim =
- mdl_animation_from_id( mdl, inf->anim_start+i );
-
- skele->anims[i].rate = anim->rate;
- skele->anims[i].length = anim->length;
- strncpy( skele->anims[i].name, mdl_pstr(mdl, anim->pstr_name), 31 );
+ mdl_animation *anim = &mdl->anim_buffer[ inf->anim_start + i ];
- u32 total_keyframes = (skele->bone_count-1)*anim->length;
- size_t block_size = sizeof(mdl_keyframe) * total_keyframes;
- mdl_keyframe *dst = vg_alloc( block_size );
+ skele->anims[i].rate = anim->rate;
+ skele->anims[i].length = anim->length;
+ skele->anims[i].name = mdl_pstr(mdl, anim->pstr_name);
+ skele->anims[i].anim_data = &mdl->keyframe_buffer[ anim->offset ];
- skele->anims[i].anim_data = dst;
- memcpy( dst, mdl_get_animdata( mdl, anim ), block_size );
+ vg_info( "animation[ %f, %u ] '%s'\n", anim->rate,
+ anim->length,
+ skele->anims[i].name );
}
skeleton_create_inverses( skele );
vg_success( "Loaded skeleton with %u bones\n", skele->bone_count );
vg_success( " %u colliders\n", skele->collider_count );
- return 1;
-
-error_dealloc:
- vg_free( skele->bones );
- vg_free( skele->ik );
- return 0;
}
-static void skeleton_debug( struct skeleton *skele )
+VG_STATIC void skeleton_debug( struct skeleton *skele )
{
for( int i=0; i<skele->bone_count; i ++ )
{