libanim

changeset 58:fe017bde08bc

implemented multiple animations per node, and blending between two animations
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 27 Dec 2013 06:28:43 +0200
parents 2da758956e50
children dae22390c34c
files example/test.c src/anim.c src/anim.h
diffstat 3 files changed, 511 insertions(+), 90 deletions(-) [+]
line diff
     1.1 --- a/example/test.c	Mon Dec 09 04:06:30 2013 +0200
     1.2 +++ b/example/test.c	Fri Dec 27 06:28:43 2013 +0200
     1.3 @@ -48,6 +48,8 @@
     1.4  };
     1.5  
     1.6  int init(void);
     1.7 +static void set_walk_animation(int idx);
     1.8 +static void set_jump_animation(int idx);
     1.9  void disp(void);
    1.10  void idle(void);
    1.11  void reshape(int x, int y);
    1.12 @@ -60,6 +62,9 @@
    1.13  
    1.14  struct anm_node *nodes[NUM_NODES];
    1.15  
    1.16 +int cur_anim = 0, next_anim = 0;
    1.17 +unsigned int trans_start_tm;
    1.18 +
    1.19  int main(int argc, char **argv)
    1.20  {
    1.21  	glutInitWindowSize(800, 600);
    1.22 @@ -92,15 +97,11 @@
    1.23  	glEnable(GL_LIGHTING);
    1.24  	glEnable(GL_LIGHT0);
    1.25  
    1.26 -	root = nodes[0];
    1.27 -
    1.28  	for(i=0; i<NUM_NODES; i++) {
    1.29  		nodes[i] = anm_create_node();
    1.30 -
    1.31  		anm_set_pivot(nodes[i], parts[i].pivot);
    1.32 -		anm_set_position(nodes[i], parts[i].pos, 0);
    1.33 -		anm_set_extrapolator(nodes[i], ANM_EXTRAP_REPEAT);
    1.34  	}
    1.35 +	root = nodes[0];
    1.36  
    1.37  	anm_link_node(nodes[NODE_TORSO], nodes[NODE_HEAD]);
    1.38  	anm_link_node(nodes[NODE_TORSO], nodes[NODE_LEFT_UPPER_LEG]);
    1.39 @@ -112,6 +113,27 @@
    1.40  	anm_link_node(nodes[NODE_LEFT_UPPER_ARM], nodes[NODE_LEFT_LOWER_ARM]);
    1.41  	anm_link_node(nodes[NODE_RIGHT_UPPER_ARM], nodes[NODE_RIGHT_LOWER_ARM]);
    1.42  
    1.43 +	set_walk_animation(0);
    1.44 +
    1.45 +	anm_add_animation(root);	/* recursively add another animation slot to all nodes */
    1.46 +	set_jump_animation(1);
    1.47 +
    1.48 +	anm_use_animation(root, cur_anim);
    1.49 +
    1.50 +	return 0;
    1.51 +}
    1.52 +
    1.53 +static void set_walk_animation(int idx)
    1.54 +{
    1.55 +	int i;
    1.56 +
    1.57 +	anm_use_animation(root, idx);
    1.58 +
    1.59 +	for(i=0; i<NUM_NODES; i++) {
    1.60 +		anm_set_position(nodes[i], parts[i].pos, 0);
    1.61 +		anm_set_extrapolator(nodes[i], ANM_EXTRAP_REPEAT);
    1.62 +	}
    1.63 +
    1.64  	/* upper leg animation */
    1.65  	anm_set_rotation(nodes[NODE_LEFT_UPPER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(-15), 1, 0, 0), 0);
    1.66  	anm_set_rotation(nodes[NODE_LEFT_UPPER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(45), 1, 0, 0), 1000);
    1.67 @@ -163,8 +185,53 @@
    1.68  	anm_set_rotation(nodes[NODE_RIGHT_LOWER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 500);
    1.69  	anm_set_rotation(nodes[NODE_RIGHT_LOWER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(40), 1, 0, 0), 1000);
    1.70  	anm_set_rotation(nodes[NODE_RIGHT_LOWER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 2000);
    1.71 +}
    1.72  
    1.73 -	return 0;
    1.74 +static void set_jump_animation(int idx)
    1.75 +{
    1.76 +	int i;
    1.77 +
    1.78 +	anm_use_animation(root, idx);
    1.79 +
    1.80 +	for(i=0; i<NUM_NODES; i++) {
    1.81 +		anm_set_position(nodes[i], parts[i].pos, 0);
    1.82 +		anm_set_extrapolator(nodes[i], ANM_EXTRAP_REPEAT);
    1.83 +	}
    1.84 +
    1.85 +	anm_set_rotation(nodes[NODE_LEFT_UPPER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 0);
    1.86 +	anm_set_rotation(nodes[NODE_LEFT_UPPER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(40), 1, 0, 0), 1000);
    1.87 +	anm_set_rotation(nodes[NODE_LEFT_UPPER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 1500);
    1.88 +	anm_set_rotation(nodes[NODE_LEFT_UPPER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 2000);
    1.89 +	anm_set_rotation(nodes[NODE_RIGHT_UPPER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 0);
    1.90 +	anm_set_rotation(nodes[NODE_RIGHT_UPPER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(40), 1, 0, 0), 1000);
    1.91 +	anm_set_rotation(nodes[NODE_RIGHT_UPPER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 1500);
    1.92 +	anm_set_rotation(nodes[NODE_RIGHT_UPPER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 2000);
    1.93 +
    1.94 +	anm_set_rotation(nodes[NODE_LEFT_LOWER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 0);
    1.95 +	anm_set_rotation(nodes[NODE_LEFT_LOWER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(-80), 1, 0, 0), 1000);
    1.96 +	anm_set_rotation(nodes[NODE_LEFT_LOWER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 1500);
    1.97 +	anm_set_rotation(nodes[NODE_LEFT_LOWER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 2000);
    1.98 +	anm_set_rotation(nodes[NODE_RIGHT_LOWER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 0);
    1.99 +	anm_set_rotation(nodes[NODE_RIGHT_LOWER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(-80), 1, 0, 0), 1000);
   1.100 +	anm_set_rotation(nodes[NODE_RIGHT_LOWER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 1500);
   1.101 +	anm_set_rotation(nodes[NODE_RIGHT_LOWER_LEG], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 2000);
   1.102 +
   1.103 +	anm_set_position(nodes[NODE_TORSO], parts[NODE_TORSO].pos, 0);
   1.104 +	anm_set_position(nodes[NODE_TORSO], v3_add(parts[NODE_TORSO].pos, v3_cons(0, -1, 0)), 1000);
   1.105 +	anm_set_position(nodes[NODE_TORSO], v3_add(parts[NODE_TORSO].pos, v3_cons(0, 2, 0)), 1500);
   1.106 +	anm_set_position(nodes[NODE_TORSO], parts[NODE_TORSO].pos, 2000);
   1.107 +
   1.108 +	anm_set_rotation(nodes[NODE_LEFT_UPPER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 0);
   1.109 +	anm_set_rotation(nodes[NODE_LEFT_UPPER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(-20), 1, 0, 0), 1000);
   1.110 +	anm_set_rotation(nodes[NODE_LEFT_UPPER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(20), 1, 0, 0), 1200);
   1.111 +	anm_set_rotation(nodes[NODE_LEFT_UPPER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(170), 1, 0, 0), 1500);
   1.112 +	anm_set_rotation(nodes[NODE_LEFT_UPPER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 2000);
   1.113 +
   1.114 +	anm_set_rotation(nodes[NODE_RIGHT_UPPER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 0);
   1.115 +	anm_set_rotation(nodes[NODE_RIGHT_UPPER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(-20), 1, 0, 0), 1000);
   1.116 +	anm_set_rotation(nodes[NODE_RIGHT_UPPER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(20), 1, 0, 0), 1200);
   1.117 +	anm_set_rotation(nodes[NODE_RIGHT_UPPER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(170), 1, 0, 0), 1500);
   1.118 +	anm_set_rotation(nodes[NODE_RIGHT_UPPER_ARM], quat_rotate(quat_identity(), DEG_TO_RAD(0), 1, 0, 0), 2000);
   1.119  }
   1.120  
   1.121  void disp(void)
   1.122 @@ -184,6 +251,18 @@
   1.123  	glRotatef(cam_phi, 1, 0, 0);
   1.124  	glRotatef(cam_theta, 0, 1, 0);
   1.125  
   1.126 +	if(cur_anim != next_anim) {
   1.127 +		float t = (msec - trans_start_tm) / 1000.0;
   1.128 +
   1.129 +		if(t >= 1.0) {
   1.130 +			t = 1.0;
   1.131 +			cur_anim = next_anim;
   1.132 +			anm_use_animation(root, cur_anim);
   1.133 +		} else {
   1.134 +			anm_use_animations(root, cur_anim, next_anim, t);
   1.135 +		}
   1.136 +	}
   1.137 +
   1.138  	/* first render a character with bottom-up lazy matrix calculation */
   1.139  	glPushMatrix();
   1.140  	glTranslatef(-2.5, 0, 0);
   1.141 @@ -264,6 +343,11 @@
   1.142  	switch(key) {
   1.143  	case 27:
   1.144  		exit(0);
   1.145 +
   1.146 +	case ' ':
   1.147 +		next_anim = (cur_anim + 1) % 2;
   1.148 +		trans_start_tm = glutGet(GLUT_ELAPSED_TIME);
   1.149 +		break;
   1.150  	}
   1.151  }
   1.152  
     2.1 --- a/src/anim.c	Mon Dec 09 04:06:30 2013 +0200
     2.2 +++ b/src/anim.c	Fri Dec 27 06:28:43 2013 +0200
     2.3 @@ -8,7 +8,7 @@
     2.4  
     2.5  static void invalidate_cache(struct anm_node *node);
     2.6  
     2.7 -int anm_init_node(struct anm_node *node)
     2.8 +int anm_init_animation(struct anm_animation *anim)
     2.9  {
    2.10  	int i, j;
    2.11  	static const float defaults[] = {
    2.12 @@ -17,20 +17,49 @@
    2.13  		1.0f, 1.0f, 1.0f		/* default scale factor */
    2.14  	};
    2.15  
    2.16 +	anim->name = 0;
    2.17 +
    2.18 +	for(i=0; i<ANM_NUM_TRACKS; i++) {
    2.19 +		if(anm_init_track(anim->tracks + i) == -1) {
    2.20 +			for(j=0; j<i; j++) {
    2.21 +				anm_destroy_track(anim->tracks + i);
    2.22 +			}
    2.23 +		}
    2.24 +		anm_set_track_default(anim->tracks + i, defaults[i]);
    2.25 +	}
    2.26 +	return 0;
    2.27 +}
    2.28 +
    2.29 +void anm_destroy_animation(struct anm_animation *anim)
    2.30 +{
    2.31 +	int i;
    2.32 +	for(i=0; i<ANM_NUM_TRACKS; i++) {
    2.33 +		anm_destroy_track(anim->tracks + i);
    2.34 +	}
    2.35 +	free(anim->name);
    2.36 +}
    2.37 +
    2.38 +/* ---- node implementation ----- */
    2.39 +
    2.40 +int anm_init_node(struct anm_node *node)
    2.41 +{
    2.42  	memset(node, 0, sizeof *node);
    2.43  
    2.44 +	node->cur_anim[1] = -1;
    2.45 +	node->cur_mix = 0;
    2.46 +
    2.47 +	if(!(node->animations = dynarr_alloc(1, sizeof *node->animations))) {
    2.48 +		return -1;
    2.49 +	}
    2.50 +	if(anm_init_animation(node->animations) == -1) {
    2.51 +		dynarr_free(node->animations);
    2.52 +		return -1;
    2.53 +	}
    2.54 +
    2.55  	/* initialize thread-local matrix cache */
    2.56  	pthread_key_create(&node->cache_key, 0);
    2.57  	pthread_mutex_init(&node->cache_list_lock, 0);
    2.58  
    2.59 -	for(i=0; i<ANM_NUM_TRACKS; i++) {
    2.60 -		if(anm_init_track(node->tracks + i) == -1) {
    2.61 -			for(j=0; j<i; j++) {
    2.62 -				anm_destroy_track(node->tracks + i);
    2.63 -			}
    2.64 -		}
    2.65 -		anm_set_track_default(node->tracks + i, defaults[i]);
    2.66 -	}
    2.67  	return 0;
    2.68  }
    2.69  
    2.70 @@ -40,8 +69,9 @@
    2.71  	free(node->name);
    2.72  
    2.73  	for(i=0; i<ANM_NUM_TRACKS; i++) {
    2.74 -		anm_destroy_track(node->tracks + i);
    2.75 +		anm_destroy_animation(node->animations + i);
    2.76  	}
    2.77 +	dynarr_free(node->animations);
    2.78  
    2.79  	/* destroy thread-specific cache */
    2.80  	pthread_key_delete(node->cache_key);
    2.81 @@ -123,26 +153,6 @@
    2.82  	return node->name ? node->name : "";
    2.83  }
    2.84  
    2.85 -void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
    2.86 -{
    2.87 -	int i;
    2.88 -
    2.89 -	for(i=0; i<ANM_NUM_TRACKS; i++) {
    2.90 -		anm_set_track_interpolator(node->tracks + i, in);
    2.91 -	}
    2.92 -	invalidate_cache(node);
    2.93 -}
    2.94 -
    2.95 -void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
    2.96 -{
    2.97 -	int i;
    2.98 -
    2.99 -	for(i=0; i<ANM_NUM_TRACKS; i++) {
   2.100 -		anm_set_track_extrapolator(node->tracks + i, ex);
   2.101 -	}
   2.102 -	invalidate_cache(node);
   2.103 -}
   2.104 -
   2.105  void anm_link_node(struct anm_node *p, struct anm_node *c)
   2.106  {
   2.107  	c->next = p->child;
   2.108 @@ -175,40 +185,284 @@
   2.109  	return -1;
   2.110  }
   2.111  
   2.112 +void anm_set_pivot(struct anm_node *node, vec3_t piv)
   2.113 +{
   2.114 +	node->pivot = piv;
   2.115 +}
   2.116 +
   2.117 +vec3_t anm_get_pivot(struct anm_node *node)
   2.118 +{
   2.119 +	return node->pivot;
   2.120 +}
   2.121 +
   2.122 +
   2.123 +/* animation management */
   2.124 +
   2.125 +int anm_use_node_animation(struct anm_node *node, int aidx)
   2.126 +{
   2.127 +	if(aidx == node->cur_anim[0] && node->cur_anim[1] == -1) {
   2.128 +		return 0;	/* no change, no invalidation */
   2.129 +	}
   2.130 +
   2.131 +	if(aidx < 0 || aidx >= anm_get_animation_count(node)) {
   2.132 +		return -1;
   2.133 +	}
   2.134 +
   2.135 +	node->cur_anim[0] = aidx;
   2.136 +	node->cur_anim[1] = -1;
   2.137 +	node->cur_mix = 0;
   2.138 +
   2.139 +	invalidate_cache(node);
   2.140 +	return 0;
   2.141 +}
   2.142 +
   2.143 +int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t)
   2.144 +{
   2.145 +	int num_anim;
   2.146 +
   2.147 +	if(node->cur_anim[0] == aidx && node->cur_anim[1] == bidx &&
   2.148 +			fabs(t - node->cur_mix) < 1e-6) {
   2.149 +		return 0;	/* no change, no invalidation */
   2.150 +	}
   2.151 +
   2.152 +	num_anim = anm_get_animation_count(node);
   2.153 +	if(aidx < 0 || aidx >= num_anim) {
   2.154 +		return anm_use_animation(node, bidx);
   2.155 +	}
   2.156 +	if(bidx < 0 || bidx >= num_anim) {
   2.157 +		return anm_use_animation(node, aidx);
   2.158 +	}
   2.159 +	node->cur_anim[0] = aidx;
   2.160 +	node->cur_anim[1] = bidx;
   2.161 +	node->cur_mix = t;
   2.162 +
   2.163 +	invalidate_cache(node);
   2.164 +	return 0;
   2.165 +}
   2.166 +
   2.167 +int anm_use_animation(struct anm_node *node, int aidx)
   2.168 +{
   2.169 +	struct anm_node *child;
   2.170 +
   2.171 +	if(anm_use_node_animation(node, aidx) == -1) {
   2.172 +		return -1;
   2.173 +	}
   2.174 +
   2.175 +	child = node->child;
   2.176 +	while(child) {
   2.177 +		if(anm_use_animation(child, aidx) == -1) {
   2.178 +			return -1;
   2.179 +		}
   2.180 +		child = child->next;
   2.181 +	}
   2.182 +	return 0;
   2.183 +}
   2.184 +
   2.185 +int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t)
   2.186 +{
   2.187 +	struct anm_node *child;
   2.188 +
   2.189 +	if(anm_use_node_animations(node, aidx, bidx, t) == -1) {
   2.190 +		return -1;
   2.191 +	}
   2.192 +
   2.193 +	child = node->child;
   2.194 +	while(child) {
   2.195 +		if(anm_use_animations(child, aidx, bidx, t) == -1) {
   2.196 +			return -1;
   2.197 +		}
   2.198 +		child = child->next;
   2.199 +	}
   2.200 +	return 0;
   2.201 +
   2.202 +}
   2.203 +
   2.204 +int anm_get_active_animation_index(struct anm_node *node, int which)
   2.205 +{
   2.206 +	if(which < 0 || which >= 2) return -1;
   2.207 +	return node->cur_anim[which];
   2.208 +}
   2.209 +
   2.210 +struct anm_animation *anm_get_active_animation(struct anm_node *node, int which)
   2.211 +{
   2.212 +	int idx = anm_get_active_animation_index(node, which);
   2.213 +	if(idx < 0 || idx >= anm_get_animation_count(node)) {
   2.214 +		return 0;
   2.215 +	}
   2.216 +	return node->animations + idx;
   2.217 +}
   2.218 +
   2.219 +float anm_get_active_animation_mix(struct anm_node *node)
   2.220 +{
   2.221 +	return node->cur_mix;
   2.222 +}
   2.223 +
   2.224 +int anm_get_animation_count(struct anm_node *node)
   2.225 +{
   2.226 +	return dynarr_size(node->animations);
   2.227 +}
   2.228 +
   2.229 +int anm_add_node_animation(struct anm_node *node)
   2.230 +{
   2.231 +	struct anm_animation newanim;
   2.232 +	anm_init_animation(&newanim);
   2.233 +
   2.234 +	node->animations = dynarr_push(node->animations, &newanim);
   2.235 +	return 0;
   2.236 +}
   2.237 +
   2.238 +int anm_remove_node_animation(struct anm_node *node, int idx)
   2.239 +{
   2.240 +	fprintf(stderr, "anm_remove_animation: unimplemented!");
   2.241 +	abort();
   2.242 +	return 0;
   2.243 +}
   2.244 +
   2.245 +int anm_add_animation(struct anm_node *node)
   2.246 +{
   2.247 +	struct anm_node *child;
   2.248 +
   2.249 +	if(anm_add_node_animation(node) == -1) {
   2.250 +		return -1;
   2.251 +	}
   2.252 +
   2.253 +	child = node->child;
   2.254 +	while(child) {
   2.255 +		if(anm_add_animation(child)) {
   2.256 +			return -1;
   2.257 +		}
   2.258 +		child = child->next;
   2.259 +	}
   2.260 +	return 0;
   2.261 +}
   2.262 +
   2.263 +int anm_remove_animation(struct anm_node *node, int idx)
   2.264 +{
   2.265 +	struct anm_node *child;
   2.266 +
   2.267 +	if(anm_remove_node_animation(node, idx) == -1) {
   2.268 +		return -1;
   2.269 +	}
   2.270 +
   2.271 +	child = node->child;
   2.272 +	while(child) {
   2.273 +		if(anm_remove_animation(child, idx) == -1) {
   2.274 +			return -1;
   2.275 +		}
   2.276 +		child = child->next;
   2.277 +	}
   2.278 +	return 0;
   2.279 +}
   2.280 +
   2.281 +struct anm_animation *anm_get_animation(struct anm_node *node, int idx)
   2.282 +{
   2.283 +	if(idx < 0 || idx > anm_get_animation_count(node)) {
   2.284 +		return 0;
   2.285 +	}
   2.286 +	return node->animations + idx;
   2.287 +}
   2.288 +
   2.289 +struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name)
   2.290 +{
   2.291 +	return anm_get_animation(node, anm_find_animation(node, name));
   2.292 +}
   2.293 +
   2.294 +int anm_find_animation(struct anm_node *node, const char *name)
   2.295 +{
   2.296 +	int i, count = anm_get_animation_count(node);
   2.297 +	for(i=0; i<count; i++) {
   2.298 +		if(strcmp(node->animations[i].name, name) == 0) {
   2.299 +			return i;
   2.300 +		}
   2.301 +	}
   2.302 +	return -1;
   2.303 +}
   2.304 +
   2.305 +/* all the rest act on the current animation(s) */
   2.306 +
   2.307 +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in)
   2.308 +{
   2.309 +	int i;
   2.310 +	struct anm_animation *anim = anm_get_active_animation(node, 0);
   2.311 +	if(!anim) return;
   2.312 +
   2.313 +	for(i=0; i<ANM_NUM_TRACKS; i++) {
   2.314 +		anm_set_track_interpolator(anim->tracks + i, in);
   2.315 +	}
   2.316 +	invalidate_cache(node);
   2.317 +}
   2.318 +
   2.319 +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex)
   2.320 +{
   2.321 +	int i;
   2.322 +	struct anm_animation *anim = anm_get_active_animation(node, 0);
   2.323 +	if(!anim) return;
   2.324 +
   2.325 +	for(i=0; i<ANM_NUM_TRACKS; i++) {
   2.326 +		anm_set_track_extrapolator(anim->tracks + i, ex);
   2.327 +	}
   2.328 +	invalidate_cache(node);
   2.329 +}
   2.330 +
   2.331  void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm)
   2.332  {
   2.333 -	anm_set_value(node->tracks + ANM_TRACK_POS_X, tm, pos.x);
   2.334 -	anm_set_value(node->tracks + ANM_TRACK_POS_Y, tm, pos.y);
   2.335 -	anm_set_value(node->tracks + ANM_TRACK_POS_Z, tm, pos.z);
   2.336 +	struct anm_animation *anim = anm_get_active_animation(node, 0);
   2.337 +	if(!anim) return;
   2.338 +
   2.339 +	anm_set_value(anim->tracks + ANM_TRACK_POS_X, tm, pos.x);
   2.340 +	anm_set_value(anim->tracks + ANM_TRACK_POS_Y, tm, pos.y);
   2.341 +	anm_set_value(anim->tracks + ANM_TRACK_POS_Z, tm, pos.z);
   2.342  	invalidate_cache(node);
   2.343  }
   2.344  
   2.345  vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm)
   2.346  {
   2.347  	vec3_t v;
   2.348 -	v.x = anm_get_value(node->tracks + ANM_TRACK_POS_X, tm);
   2.349 -	v.y = anm_get_value(node->tracks + ANM_TRACK_POS_Y, tm);
   2.350 -	v.z = anm_get_value(node->tracks + ANM_TRACK_POS_Z, tm);
   2.351 +	struct anm_animation *anim0 = anm_get_active_animation(node, 0);
   2.352 +	struct anm_animation *anim1 = anm_get_active_animation(node, 1);
   2.353 +
   2.354 +	if(!anim0) {
   2.355 +		return v3_cons(0, 0, 0);
   2.356 +	}
   2.357 +
   2.358 +	v.x = anm_get_value(anim0->tracks + ANM_TRACK_POS_X, tm);
   2.359 +	v.y = anm_get_value(anim0->tracks + ANM_TRACK_POS_Y, tm);
   2.360 +	v.z = anm_get_value(anim0->tracks + ANM_TRACK_POS_Z, tm);
   2.361 +
   2.362 +	if(anim1) {
   2.363 +		vec3_t v1;
   2.364 +		v1.x = anm_get_value(anim1->tracks + ANM_TRACK_POS_X, tm);
   2.365 +		v1.y = anm_get_value(anim1->tracks + ANM_TRACK_POS_Y, tm);
   2.366 +		v1.z = anm_get_value(anim1->tracks + ANM_TRACK_POS_Z, tm);
   2.367 +
   2.368 +		v.x = v.x + (v1.x - v.x) * node->cur_mix;
   2.369 +		v.y = v.y + (v1.y - v.y) * node->cur_mix;
   2.370 +		v.z = v.z + (v1.z - v.z) * node->cur_mix;
   2.371 +	}
   2.372 +
   2.373  	return v;
   2.374  }
   2.375  
   2.376  void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm)
   2.377  {
   2.378 -	anm_set_value(node->tracks + ANM_TRACK_ROT_X, tm, rot.x);
   2.379 -	anm_set_value(node->tracks + ANM_TRACK_ROT_Y, tm, rot.y);
   2.380 -	anm_set_value(node->tracks + ANM_TRACK_ROT_Z, tm, rot.z);
   2.381 -	anm_set_value(node->tracks + ANM_TRACK_ROT_W, tm, rot.w);
   2.382 +	struct anm_animation *anim = anm_get_active_animation(node, 0);
   2.383 +	if(!anim) return;
   2.384 +
   2.385 +	anm_set_value(anim->tracks + ANM_TRACK_ROT_X, tm, rot.x);
   2.386 +	anm_set_value(anim->tracks + ANM_TRACK_ROT_Y, tm, rot.y);
   2.387 +	anm_set_value(anim->tracks + ANM_TRACK_ROT_Z, tm, rot.z);
   2.388 +	anm_set_value(anim->tracks + ANM_TRACK_ROT_W, tm, rot.w);
   2.389  	invalidate_cache(node);
   2.390  }
   2.391  
   2.392 -quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
   2.393 +static quat_t get_node_rotation(struct anm_node *node, anm_time_t tm, struct anm_animation *anim)
   2.394  {
   2.395  #ifndef ROT_USE_SLERP
   2.396  	quat_t q;
   2.397 -	q.x = anm_get_value(node->tracks + ANM_TRACK_ROT_X, tm);
   2.398 -	q.y = anm_get_value(node->tracks + ANM_TRACK_ROT_Y, tm);
   2.399 -	q.z = anm_get_value(node->tracks + ANM_TRACK_ROT_Z, tm);
   2.400 -	q.w = anm_get_value(node->tracks + ANM_TRACK_ROT_W, tm);
   2.401 +	q.x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm);
   2.402 +	q.y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm);
   2.403 +	q.z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm);
   2.404 +	q.w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm);
   2.405  	return q;
   2.406  #else
   2.407  	int idx0, idx1, last_idx;
   2.408 @@ -217,10 +471,10 @@
   2.409  	struct anm_track *track_x, *track_y, *track_z, *track_w;
   2.410  	quat_t q, q1, q2;
   2.411  
   2.412 -	track_x = node->tracks + ANM_TRACK_ROT_X;
   2.413 -	track_y = node->tracks + ANM_TRACK_ROT_Y;
   2.414 -	track_z = node->tracks + ANM_TRACK_ROT_Z;
   2.415 -	track_w = node->tracks + ANM_TRACK_ROT_W;
   2.416 +	track_x = anim->tracks + ANM_TRACK_ROT_X;
   2.417 +	track_y = anim->tracks + ANM_TRACK_ROT_Y;
   2.418 +	track_z = anim->tracks + ANM_TRACK_ROT_Z;
   2.419 +	track_w = anim->tracks + ANM_TRACK_ROT_W;
   2.420  
   2.421  	if(!track_x->count) {
   2.422  		q.x = track_x->def_val;
   2.423 @@ -277,20 +531,62 @@
   2.424  #endif
   2.425  }
   2.426  
   2.427 +quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm)
   2.428 +{
   2.429 +	quat_t q;
   2.430 +	struct anm_animation *anim0 = anm_get_active_animation(node, 0);
   2.431 +	struct anm_animation *anim1 = anm_get_active_animation(node, 1);
   2.432 +
   2.433 +	if(!anim0) {
   2.434 +		return quat_identity();
   2.435 +	}
   2.436 +
   2.437 +	q = get_node_rotation(node, tm, anim0);
   2.438 +
   2.439 +	if(anim1) {
   2.440 +		quat_t q1 = get_node_rotation(node, tm, anim1);
   2.441 +
   2.442 +		q = quat_slerp(q, q1, node->cur_mix);
   2.443 +	}
   2.444 +	return q;
   2.445 +}
   2.446 +
   2.447  void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm)
   2.448  {
   2.449 -	anm_set_value(node->tracks + ANM_TRACK_SCL_X, tm, scl.x);
   2.450 -	anm_set_value(node->tracks + ANM_TRACK_SCL_Y, tm, scl.y);
   2.451 -	anm_set_value(node->tracks + ANM_TRACK_SCL_Z, tm, scl.z);
   2.452 +	struct anm_animation *anim = anm_get_active_animation(node, 0);
   2.453 +	if(!anim) return;
   2.454 +
   2.455 +	anm_set_value(anim->tracks + ANM_TRACK_SCL_X, tm, scl.x);
   2.456 +	anm_set_value(anim->tracks + ANM_TRACK_SCL_Y, tm, scl.y);
   2.457 +	anm_set_value(anim->tracks + ANM_TRACK_SCL_Z, tm, scl.z);
   2.458  	invalidate_cache(node);
   2.459  }
   2.460  
   2.461  vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm)
   2.462  {
   2.463  	vec3_t v;
   2.464 -	v.x = anm_get_value(node->tracks + ANM_TRACK_SCL_X, tm);
   2.465 -	v.y = anm_get_value(node->tracks + ANM_TRACK_SCL_Y, tm);
   2.466 -	v.z = anm_get_value(node->tracks + ANM_TRACK_SCL_Z, tm);
   2.467 +	struct anm_animation *anim0 = anm_get_active_animation(node, 0);
   2.468 +	struct anm_animation *anim1 = anm_get_active_animation(node, 1);
   2.469 +
   2.470 +	if(!anim0) {
   2.471 +		return v3_cons(1, 1, 1);
   2.472 +	}
   2.473 +
   2.474 +	v.x = anm_get_value(anim0->tracks + ANM_TRACK_SCL_X, tm);
   2.475 +	v.y = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Y, tm);
   2.476 +	v.z = anm_get_value(anim0->tracks + ANM_TRACK_SCL_Z, tm);
   2.477 +
   2.478 +	if(anim1) {
   2.479 +		vec3_t v1;
   2.480 +		v1.x = anm_get_value(anim1->tracks + ANM_TRACK_SCL_X, tm);
   2.481 +		v1.y = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Y, tm);
   2.482 +		v1.z = anm_get_value(anim1->tracks + ANM_TRACK_SCL_Z, tm);
   2.483 +
   2.484 +		v.x = v.x + (v1.x - v.x) * node->cur_mix;
   2.485 +		v.y = v.y + (v1.y - v.y) * node->cur_mix;
   2.486 +		v.z = v.z + (v1.z - v.z) * node->cur_mix;
   2.487 +	}
   2.488 +
   2.489  	return v;
   2.490  }
   2.491  
   2.492 @@ -334,16 +630,6 @@
   2.493  	return v3_mul(s, ps);
   2.494  }
   2.495  
   2.496 -void anm_set_pivot(struct anm_node *node, vec3_t piv)
   2.497 -{
   2.498 -	node->pivot = piv;
   2.499 -}
   2.500 -
   2.501 -vec3_t anm_get_pivot(struct anm_node *node)
   2.502 -{
   2.503 -	return node->pivot;
   2.504 -}
   2.505 -
   2.506  void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
   2.507  {
   2.508  	int i;
   2.509 @@ -463,15 +749,20 @@
   2.510  
   2.511  anm_time_t anm_get_start_time(struct anm_node *node)
   2.512  {
   2.513 -	int i;
   2.514 +	int i, j;
   2.515  	struct anm_node *c;
   2.516  	anm_time_t res = LONG_MAX;
   2.517  
   2.518 -	for(i=0; i<ANM_NUM_TRACKS; i++) {
   2.519 -		if(node->tracks[i].count) {
   2.520 -			anm_time_t tm = node->tracks[i].keys[0].time;
   2.521 -			if(tm < res) {
   2.522 -				res = tm;
   2.523 +	for(j=0; j<2; j++) {
   2.524 +		struct anm_animation *anim = anm_get_active_animation(node, j);
   2.525 +		if(!anim) break;
   2.526 +
   2.527 +		for(i=0; i<ANM_NUM_TRACKS; i++) {
   2.528 +			if(anim->tracks[i].count) {
   2.529 +				anm_time_t tm = anim->tracks[i].keys[0].time;
   2.530 +				if(tm < res) {
   2.531 +					res = tm;
   2.532 +				}
   2.533  			}
   2.534  		}
   2.535  	}
   2.536 @@ -489,15 +780,20 @@
   2.537  
   2.538  anm_time_t anm_get_end_time(struct anm_node *node)
   2.539  {
   2.540 -	int i;
   2.541 +	int i, j;
   2.542  	struct anm_node *c;
   2.543  	anm_time_t res = LONG_MIN;
   2.544  
   2.545 -	for(i=0; i<ANM_NUM_TRACKS; i++) {
   2.546 -		if(node->tracks[i].count) {
   2.547 -			anm_time_t tm = node->tracks[i].keys[node->tracks[i].count - 1].time;
   2.548 -			if(tm > res) {
   2.549 -				res = tm;
   2.550 +	for(j=0; j<2; j++) {
   2.551 +		struct anm_animation *anim = anm_get_active_animation(node, j);
   2.552 +		if(!anim) break;
   2.553 +
   2.554 +		for(i=0; i<ANM_NUM_TRACKS; i++) {
   2.555 +			if(anim->tracks[i].count) {
   2.556 +				anm_time_t tm = anim->tracks[i].keys[anim->tracks[i].count - 1].time;
   2.557 +				if(tm > res) {
   2.558 +					res = tm;
   2.559 +				}
   2.560  			}
   2.561  		}
   2.562  	}
     3.1 --- a/src/anim.h	Mon Dec 09 04:06:30 2013 +0200
     3.2 +++ b/src/anim.h	Fri Dec 27 06:28:43 2013 +0200
     3.3 @@ -27,10 +27,18 @@
     3.4  	ANM_NUM_TRACKS
     3.5  };
     3.6  
     3.7 +struct anm_animation {
     3.8 +	char *name;
     3.9 +	struct anm_track tracks[ANM_NUM_TRACKS];
    3.10 +};
    3.11 +
    3.12  struct anm_node {
    3.13  	char *name;
    3.14  
    3.15 -	struct anm_track tracks[ANM_NUM_TRACKS];
    3.16 +	int cur_anim[2];
    3.17 +	float cur_mix;
    3.18 +
    3.19 +	struct anm_animation *animations;
    3.20  	vec3_t pivot;
    3.21  
    3.22  	/* matrix cache */
    3.23 @@ -54,6 +62,9 @@
    3.24  extern "C" {
    3.25  #endif
    3.26  
    3.27 +int anm_init_animation(struct anm_animation *anim);
    3.28 +void anm_destroy_animation(struct anm_animation *anim);
    3.29 +
    3.30  /* node constructor and destructor */
    3.31  int anm_init_node(struct anm_node *node);
    3.32  void anm_destroy_node(struct anm_node *node);
    3.33 @@ -74,13 +85,46 @@
    3.34  int anm_set_node_name(struct anm_node *node, const char *name);
    3.35  const char *anm_get_node_name(struct anm_node *node);
    3.36  
    3.37 -void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in);
    3.38 -void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex);
    3.39 -
    3.40  /* link and unlink nodes with parent/child relations */
    3.41  void anm_link_node(struct anm_node *parent, struct anm_node *child);
    3.42  int anm_unlink_node(struct anm_node *parent, struct anm_node *child);
    3.43  
    3.44 +void anm_set_pivot(struct anm_node *node, vec3_t pivot);
    3.45 +vec3_t anm_get_pivot(struct anm_node *node);
    3.46 +
    3.47 +/* set active animation(s) */
    3.48 +int anm_use_node_animation(struct anm_node *node, int aidx);
    3.49 +int anm_use_node_animations(struct anm_node *node, int aidx, int bidx, float t);
    3.50 +/* recursive variants */
    3.51 +int anm_use_animation(struct anm_node *node, int aidx);
    3.52 +int anm_use_animations(struct anm_node *node, int aidx, int bidx, float t);
    3.53 +
    3.54 +/* returns the requested current animation index, which can be 0 or 1 */
    3.55 +int anm_get_active_animation_index(struct anm_node *node, int which);
    3.56 +/* returns the requested current animation, which can be 0 or 1 */
    3.57 +struct anm_animation *anm_get_active_animation(struct anm_node *node, int which);
    3.58 +float anm_get_active_animation_mix(struct anm_node *node);
    3.59 +
    3.60 +int anm_get_animation_count(struct anm_node *node);
    3.61 +
    3.62 +/* add/remove an animation to the specified node */
    3.63 +int anm_add_node_animation(struct anm_node *node);
    3.64 +int anm_remove_node_animation(struct anm_node *node, int idx);
    3.65 +
    3.66 +/* add/remove an animation to the specified node and all it's descendants */
    3.67 +int anm_add_animation(struct anm_node *node);
    3.68 +int anm_remove_animation(struct anm_node *node, int idx);
    3.69 +
    3.70 +struct anm_animation *anm_get_animation(struct anm_node *node, int idx);
    3.71 +struct anm_animation *anm_get_animation_by_name(struct anm_node *node, const char *name);
    3.72 +
    3.73 +int anm_find_animation(struct anm_node *node, const char *name);
    3.74 +
    3.75 +/* set the interpolator for the (first) currently active animation */
    3.76 +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in);
    3.77 +/* set the extrapolator for the (first) currently active animation */
    3.78 +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex);
    3.79 +
    3.80  void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm);
    3.81  vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm);
    3.82  
    3.83 @@ -95,9 +139,6 @@
    3.84  quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm);
    3.85  vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm);
    3.86  
    3.87 -void anm_set_pivot(struct anm_node *node, vec3_t pivot);
    3.88 -vec3_t anm_get_pivot(struct anm_node *node);
    3.89 -
    3.90  /* those return the start and end times of the whole tree */
    3.91  anm_time_t anm_get_start_time(struct anm_node *node);
    3.92  anm_time_t anm_get_end_time(struct anm_node *node);