libanim

diff src/anim.c @ 24:09e267e7ed4a

implemented high-level animation blending interface
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 30 Dec 2013 15:20:31 +0200
parents 203c11299586
children ebead35c9eb1
line diff
     1.1 --- a/src/anim.c	Fri Dec 27 11:29:42 2013 +0200
     1.2 +++ b/src/anim.c	Mon Dec 30 15:20:31 2013 +0200
     1.3 @@ -57,7 +57,6 @@
     1.4  	memset(node, 0, sizeof *node);
     1.5  
     1.6  	node->cur_anim[1] = -1;
     1.7 -	node->cur_mix = 0;
     1.8  
     1.9  	if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) {
    1.10  		return -1;
    1.11 @@ -222,6 +221,7 @@
    1.12  	node->cur_anim[0] = aidx;
    1.13  	node->cur_anim[1] = -1;
    1.14  	node->cur_mix = 0;
    1.15 +	node->blend_dur = -1;
    1.16  
    1.17  	invalidate_cache(node);
    1.18  	return 0;
    1.19 @@ -288,13 +288,40 @@
    1.20  
    1.21  }
    1.22  
    1.23 -int anm_get_active_animation_index(struct anm_node *node, int which)
    1.24 +void anm_set_node_animation_offset(struct anm_node *node, anm_time_t offs, int which)
    1.25 +{
    1.26 +	if(which < 0 || which >= 2) {
    1.27 +		return;
    1.28 +	}
    1.29 +	node->cur_anim_offset[which] = offs;
    1.30 +}
    1.31 +
    1.32 +anm_time_t anm_get_animation_offset(const struct anm_node *node, int which)
    1.33 +{
    1.34 +	if(which < 0 || which >= 2) {
    1.35 +		return 0;
    1.36 +	}
    1.37 +	return node->cur_anim_offset[which];
    1.38 +}
    1.39 +
    1.40 +void anm_set_animation_offset(struct anm_node *node, anm_time_t offs, int which)
    1.41 +{
    1.42 +	struct anm_node *c = node->child;
    1.43 +	while(c) {
    1.44 +		anm_set_animation_offset(c, offs, which);
    1.45 +		c = c->next;
    1.46 +	}
    1.47 +
    1.48 +	anm_set_node_animation_offset(node, offs, which);
    1.49 +}
    1.50 +
    1.51 +int anm_get_active_animation_index(const struct anm_node *node, int which)
    1.52  {
    1.53  	if(which < 0 || which >= 2) return -1;
    1.54  	return node->cur_anim[which];
    1.55  }
    1.56  
    1.57 -struct anm_animation *anm_get_active_animation(struct anm_node *node, int which)
    1.58 +struct anm_animation *anm_get_active_animation(const struct anm_node *node, int which)
    1.59  {
    1.60  	int idx = anm_get_active_animation_index(node, which);
    1.61  	if(idx < 0 || idx >= anm_get_animation_count(node)) {
    1.62 @@ -303,12 +330,12 @@
    1.63  	return node->animations + idx;
    1.64  }
    1.65  
    1.66 -float anm_get_active_animation_mix(struct anm_node *node)
    1.67 +float anm_get_active_animation_mix(const struct anm_node *node)
    1.68  {
    1.69  	return node->cur_mix;
    1.70  }
    1.71  
    1.72 -int anm_get_animation_count(struct anm_node *node)
    1.73 +int anm_get_animation_count(const struct anm_node *node)
    1.74  {
    1.75  	return dynarr_size(node->animations);
    1.76  }
    1.77 @@ -445,6 +472,50 @@
    1.78  	return 0;
    1.79  }
    1.80  
    1.81 +/* ---- high level animation blending ---- */
    1.82 +void anm_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
    1.83 +{
    1.84 +	struct anm_node *c = node->child;
    1.85 +	while(c) {
    1.86 +		anm_transition(c, anmidx, start, dur);
    1.87 +		c = c->next;
    1.88 +	}
    1.89 +
    1.90 +	anm_node_transition(node, anmidx, start, dur);
    1.91 +}
    1.92 +
    1.93 +void anm_node_transition(struct anm_node *node, int anmidx, anm_time_t start, anm_time_t dur)
    1.94 +{
    1.95 +	node->cur_anim[1] = anmidx;
    1.96 +	node->cur_anim_offset[1] = start;
    1.97 +	node->blend_dur = dur;
    1.98 +}
    1.99 +
   1.100 +
   1.101 +#define BLEND_START_TM	node->cur_anim_offset[1]
   1.102 +
   1.103 +static anm_time_t animation_time(struct anm_node *node, anm_time_t tm, int which)
   1.104 +{
   1.105 +	float t;
   1.106 +
   1.107 +	if(node->blend_dur >= 0) {
   1.108 +		/* we're in transition... */
   1.109 +		t = (float)(tm - BLEND_START_TM) / (float)node->blend_dur;
   1.110 +		if(t < 0.0) t = 0.0;
   1.111 +
   1.112 +		node->cur_mix = t;
   1.113 +
   1.114 +		if(t > 1.0) {
   1.115 +			/* switch completely over to the target animation and stop blending */
   1.116 +			anm_use_node_animation(node, node->cur_anim[1]);
   1.117 +			node->cur_anim_offset[0] = node->cur_anim_offset[1];
   1.118 +		}
   1.119 +	}
   1.120 +
   1.121 +	return tm - node->cur_anim_offset[which];
   1.122 +}
   1.123 +
   1.124 +
   1.125  void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm)
   1.126  {
   1.127  	struct anm_animation *anim = anm_get_active_animation(node, 0);
   1.128 @@ -456,9 +527,11 @@
   1.129  	invalidate_cache(node);
   1.130  }
   1.131  
   1.132 +
   1.133  vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm)
   1.134  {
   1.135  	vec3_t v;
   1.136 +	anm_time_t tm0 = animation_time(node, tm, 0);
   1.137  	struct anm_animation *anim0 = anm_get_active_animation(node, 0);
   1.138  	struct anm_animation *anim1 = anm_get_active_animation(node, 1);
   1.139  
   1.140 @@ -466,15 +539,16 @@
   1.141  		return v3_cons(0, 0, 0);
   1.142  	}
   1.143  
   1.144 -	v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm);
   1.145 -	v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm);
   1.146 -	v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm);
   1.147 +	v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm0);
   1.148 +	v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm0);
   1.149 +	v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm0);
   1.150  
   1.151  	if(anim1) {
   1.152  		vec3_t v1;
   1.153 -		v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm);
   1.154 -		v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm);
   1.155 -		v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm);
   1.156 +		anm_time_t tm1 = animation_time(node, tm, 1);
   1.157 +		v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm1);
   1.158 +		v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm1);
   1.159 +		v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm1);
   1.160  
   1.161  		v.x = v.x + (v1.x - v.x) * node->cur_mix;
   1.162  		v.y = v.y + (v1.y - v.y) * node->cur_mix;
   1.163 @@ -575,6 +649,7 @@
   1.164  quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
   1.165  {
   1.166  	quat_t q;
   1.167 +	anm_time_t tm0 = animation_time(node, tm, 0);
   1.168  	struct anm_animation *anim0 = anm_get_active_animation(node, 0);
   1.169  	struct anm_animation *anim1 = anm_get_active_animation(node, 1);
   1.170  
   1.171 @@ -582,10 +657,11 @@
   1.172  		return quat_identity();
   1.173  	}
   1.174  
   1.175 -	q = get_node_rotation(node, tm, anim0);
   1.176 +	q = get_node_rotation(node, tm0, anim0);
   1.177  
   1.178  	if(anim1) {
   1.179 -		quat_t q1 = get_node_rotation(node, tm, anim1);
   1.180 +		anm_time_t tm1 = animation_time(node, tm, 1);
   1.181 +		quat_t q1 = get_node_rotation(node, tm1, anim1);
   1.182  
   1.183  		q = quat_slerp(q, q1, node->cur_mix);
   1.184  	}
   1.185 @@ -606,6 +682,7 @@
   1.186  vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm)
   1.187  {
   1.188  	vec3_t v;
   1.189 +	anm_time_t tm0 = animation_time(node, tm, 0);
   1.190  	struct anm_animation *anim0 = anm_get_active_animation(node, 0);
   1.191  	struct anm_animation *anim1 = anm_get_active_animation(node, 1);
   1.192  
   1.193 @@ -613,15 +690,16 @@
   1.194  		return v3_cons(1, 1, 1);
   1.195  	}
   1.196  
   1.197 -	v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm);
   1.198 -	v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm);
   1.199 -	v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm);
   1.200 +	v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm0);
   1.201 +	v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm0);
   1.202 +	v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm0);
   1.203  
   1.204  	if(anim1) {
   1.205  		vec3_t v1;
   1.206 -		v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm);
   1.207 -		v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm);
   1.208 -		v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm);
   1.209 +		anm_time_t tm1 = animation_time(node, tm, 1);
   1.210 +		v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm1);
   1.211 +		v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm1);
   1.212 +		v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm1);
   1.213  
   1.214  		v.x = v.x + (v1.x - v.x) * node->cur_mix;
   1.215  		v.y = v.y + (v1.y - v.y) * node->cur_mix;