libanim

changeset 20:3c2428cb38f7

added the option of lightweight pre-pass top-down recursive calculation of matrices instead of going through the existing lazy thread-specific caching algorithm.
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 09 Dec 2013 04:06:30 +0200
parents 35b813d504e7
children 5993f405a1cb
files example/Makefile example/test.c src/anim.c src/anim.h
diffstat 4 files changed, 76 insertions(+), 6 deletions(-) [+]
line diff
     1.1 --- a/example/Makefile	Sat Nov 16 12:31:03 2013 +0200
     1.2 +++ b/example/Makefile	Mon Dec 09 04:06:30 2013 +0200
     1.3 @@ -3,7 +3,7 @@
     1.4  bin = test
     1.5  
     1.6  CFLAGS = -pedantic -Wall -g -I../src
     1.7 -LDFLAGS = -L.. -lanim -lvmath $(libgl) -lm
     1.8 +LDFLAGS = -L.. -lanim -lvmath $(libgl) -lm -lpthread
     1.9  
    1.10  ifeq ($(shell uname -s), Darwin)
    1.11  	libgl = -framework OpenGL -framework GLUT
     2.1 --- a/example/test.c	Sat Nov 16 12:31:03 2013 +0200
     2.2 +++ b/example/test.c	Mon Dec 09 04:06:30 2013 +0200
     2.3 @@ -184,6 +184,10 @@
     2.4  	glRotatef(cam_phi, 1, 0, 0);
     2.5  	glRotatef(cam_theta, 0, 1, 0);
     2.6  
     2.7 +	/* first render a character with bottom-up lazy matrix calculation */
     2.8 +	glPushMatrix();
     2.9 +	glTranslatef(-2.5, 0, 0);
    2.10 +
    2.11  	for(i=0; i<NUM_NODES; i++) {
    2.12  		float color[4] = {0, 0, 0, 1};
    2.13  		mat4_t xform, xform_transp;
    2.14 @@ -203,10 +207,39 @@
    2.15  
    2.16  		glScalef(parts[i].sz.x, parts[i].sz.y, parts[i].sz.z);
    2.17  		glutSolidCube(1.0);
    2.18 -		/*glutWireSphere(0.6, 16, 8);*/
    2.19  
    2.20  		glPopMatrix();
    2.21  	}
    2.22 +	glPopMatrix();
    2.23 +
    2.24 +	/* then render another one using simple top-down recursive evaluation */
    2.25 +	glPushMatrix();
    2.26 +	glTranslatef(2.5, 0, 0);
    2.27 +
    2.28 +	anm_eval(nodes[NODE_TORSO], msec);	/* calculate all matrices recursively */
    2.29 +
    2.30 +	for(i=0; i<NUM_NODES; i++) {
    2.31 +		float color[4] = {0, 0, 0, 1};
    2.32 +		mat4_t xform_transp;
    2.33 +
    2.34 +		color[0] = parts[i].color.x;
    2.35 +		color[1] = parts[i].color.y;
    2.36 +		color[2] = parts[i].color.z;
    2.37 +
    2.38 +		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
    2.39 +		glColor4fv(color);
    2.40 +
    2.41 +		m4_transpose(xform_transp, nodes[i]->matrix);
    2.42 +
    2.43 +		glPushMatrix();
    2.44 +		glMultMatrixf((float*)xform_transp);
    2.45 +
    2.46 +		glScalef(parts[i].sz.x, parts[i].sz.y, parts[i].sz.z);
    2.47 +		glutSolidCube(1.0);
    2.48 +
    2.49 +		glPopMatrix();
    2.50 +	}
    2.51 +	glPopMatrix();
    2.52  
    2.53  	glutSwapBuffers();
    2.54  	assert(glGetError() == GL_NO_ERROR);
     3.1 --- a/src/anim.c	Sat Nov 16 12:31:03 2013 +0200
     3.2 +++ b/src/anim.c	Mon Dec 09 04:06:30 2013 +0200
     3.3 @@ -381,6 +381,30 @@
     3.4  	m4_inverse(mat, tmp);
     3.5  }
     3.6  
     3.7 +void anm_eval_node(struct anm_node *node, anm_time_t tm)
     3.8 +{
     3.9 +	anm_get_node_matrix(node, node->matrix, tm);
    3.10 +}
    3.11 +
    3.12 +void anm_eval(struct anm_node *node, anm_time_t tm)
    3.13 +{
    3.14 +	struct anm_node *c;
    3.15 +
    3.16 +	anm_eval_node(node, tm);
    3.17 +
    3.18 +	if(node->parent) {
    3.19 +		/* due to post-order traversal, the parent matrix is already evaluated */
    3.20 +		m4_mult(node->matrix, node->parent->matrix, node->matrix);
    3.21 +	}
    3.22 +
    3.23 +	/* recersively evaluate all children */
    3.24 +	c = node->child;
    3.25 +	while(c) {
    3.26 +		anm_eval(c, tm);
    3.27 +		c = c->next;
    3.28 +	}
    3.29 +}
    3.30 +
    3.31  void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm)
    3.32  {
    3.33  	struct mat_cache *cache = pthread_getspecific(node->cache_key);
     4.1 --- a/src/anim.h	Sat Nov 16 12:31:03 2013 +0200
     4.2 +++ b/src/anim.h	Mon Dec 09 04:06:30 2013 +0200
     4.3 @@ -42,6 +42,9 @@
     4.4  	pthread_key_t cache_key;
     4.5  	pthread_mutex_t cache_list_lock;
     4.6  
     4.7 +	/* matrix calculated by anm_eval functions (no locking, meant as a pre-pass) */
     4.8 +	mat4_t matrix;
     4.9 +
    4.10  	struct anm_node *parent;
    4.11  	struct anm_node *child;
    4.12  	struct anm_node *next;
    4.13 @@ -95,10 +98,24 @@
    4.14  void anm_set_pivot(struct anm_node *node, vec3_t pivot);
    4.15  vec3_t anm_get_pivot(struct anm_node *node);
    4.16  
    4.17 +/* those return the start and end times of the whole tree */
    4.18 +anm_time_t anm_get_start_time(struct anm_node *node);
    4.19 +anm_time_t anm_get_end_time(struct anm_node *node);
    4.20 +
    4.21  /* these calculate the matrix and inverse matrix of this node alone */
    4.22  void anm_get_node_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm);
    4.23  void anm_get_node_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm);
    4.24  
    4.25 +/* ---- top-down matrix calculation interface ---- */
    4.26 +
    4.27 +/* calculate and set the matrix of this node */
    4.28 +void anm_eval_node(struct anm_node *node, anm_time_t tm);
    4.29 +/* calculate and set the matrix of this node and all its children recursively */
    4.30 +void anm_eval(struct anm_node *node, anm_time_t tm);
    4.31 +
    4.32 +
    4.33 +/* ---- bottom-up lazy matrix calculation interface ---- */
    4.34 +
    4.35  /* These calculate the matrix and inverse matrix of this node taking hierarchy
    4.36   * into account. The results are cached in thread-specific storage and returned
    4.37   * if there's no change in time or tracks from the last query...
    4.38 @@ -106,10 +123,6 @@
    4.39  void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm);
    4.40  void anm_get_inv_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm);
    4.41  
    4.42 -/* those return the start and end times of the whole tree */
    4.43 -anm_time_t anm_get_start_time(struct anm_node *node);
    4.44 -anm_time_t anm_get_end_time(struct anm_node *node);
    4.45 -
    4.46  #ifdef __cplusplus
    4.47  }
    4.48  #endif