/* * TODO: If you look at the usage of this function, radians is often * the same for each call, so optimise this to not recalc m if radians * hasn't changed. */ void vec3_axisRotate(vec3 axis, vec3 target, float radians) { float m[9]; vec3 t; int i; vec3_getRotationMatrix(axis, m, radians); vec3_cpy(target, t); #define M(row,col) m[row*3 + col] for (i = 0; i < 3; i++) target[i] = t[0]*M(0,i) + t[1]*M(1,i) + t[2]*M(2,i); #undef M }
/* * Create the vertex array with vertexes in mip level order. */ static void lsc_setupPatchVtxArr(lsc l, int m, int x0, int x1, int y0, int y1, float *vtxArr) { int i, j, k; vec3 v; unsigned char *hm = l->hm; int hmSize = l->hmSize; int patchSize = l->patchSize; float texScale = (float)l->texTile / (float)l->hmSize; float baseTexScale = (float)l->baseTexTile / (float)l->hmSize; int S = x0 % (l->hmSize / l->texTile); int T = y0 % (l->hmSize / l->texTile); unsigned short *patchIdx = l->patchIdx; if (hm) hm = &hm[x0 + y0*(hmSize+1)]; for (j = 0; j <= patchSize; j++) { for (i = 0; i <= patchSize; i++) { k = patchIdx[j*(patchSize + 1) + i]; v[0] = i + x0; v[1] = j + y0; /* Texture 0 */ vtxArr[8*k + 4] = (S + i) * texScale; vtxArr[8*k + 5] = (T + j) * texScale; /* Texture 1 */ vtxArr[8*k + 6] = v[0] * baseTexScale; vtxArr[8*k + 7] = v[1] * baseTexScale; /* Vertex */ if (hm) v[2] = hm[j*(hmSize + 1) + i]; else v[2] = 0.0f; vec3_mul(v, l->scale, v); vec3_cpy(v, (&vtxArr[8*k])); } } }
X42_EXPORT bool X42_CALL x42_LerpAnims( x42animLerp_t *lerp, const x42data_t *x42, const x42animFrames_t *anim, x42opts_t *opts ) { uint i, j; const vec3_t * RESTRICT pv; const vec3_t * RESTRICT sv; const quat_t * RESTRICT rv; vec3_t * RESTRICT po; vec3_t * RESTRICT so; quat_t * RESTRICT ro; REF_PARAM( opts ); #ifndef LIBX42_NO_PARAM_VALIDATION demand_rf( lerp != NULL, X42_ERR_BADPTR, "lerp is NULL" ); demand_rf( anim != NULL, X42_ERR_BADPTR, "anim is NULL" ); demand_rf( x42 != NULL, X42_ERR_BADPTR, "x42 is NULL" ); demand_rf( x42_ValidateHeader( &x42->header ), X42_ERR_BADDATA, "invalid x42 header data" ); #endif pv = x42->posValues; sv = x42->scaleValues; rv = x42->rotValues; po = lerp->p; so = lerp->s; ro = lerp->r; for( i = 0; i < x42->header.numAnimGroups; i++ ) { const x42ksBoneEntry_t * RESTRICT p; uint beginBone = x42->animGroups[i].beginBone; uint endBone = x42->animGroups[i].endBone; float target = anim->frames[i].targetFrame; for( j = beginBone; j < endBone; j++ ) { p = anim->kpairs[j][X42_KT_POSITION]; if( p[0].value == p[1].value ) vec3_cpy( po[j], pv[p[0].value] ); else { float s = (float)(int)p[0].frame; float e = (float)(int)p[1].frame; float t = (target - s) / (e - s); vec3_lerp( po[j], pv[p[0].value], pv[p[1].value], t ); } } for( j = beginBone; j < endBone; j++ ) { p = anim->kpairs[j][X42_KT_SCALE]; if( p[0].value == p[1].value ) vec3_cpy( so[j], sv[p[0].value] ); else { float s = (float)(int)p[0].frame; float e = (float)(int)p[1].frame; float t = (target - s) / (e - s); vec3_lerp( so[j], sv[p[0].value], sv[p[1].value], t ); } } for( j = beginBone; j < endBone; j++ ) { p = anim->kpairs[j][X42_KT_ROTATION]; if( p[0].value == p[1].value ) quat_cpy( ro[j], rv[p[0].value] ); else { float s = (float)(int)p[0].frame; float e = (float)(int)p[1].frame; float t = (target - s) / (e - s); quat_interp( ro[j], rv[p[0].value], rv[p[1].value], t ); } } } return true; }
X42_EXPORT affine_t* X42_CALL x42_GetAnimBoneMatrices( void *out_buffer, const x42data_t *x42, const x42animLerp_t *lerp, x42opts_t *opts ) { uint i; affine_t * RESTRICT ret; const vec3_t * RESTRICT pv; const vec3_t * RESTRICT sv; const quat_t * RESTRICT rv; REF_PARAM( opts ); #ifndef LIBX42_NO_PARAM_VALIDATION demand_rn( out_buffer != NULL, X42_ERR_BADPTR, "out_buffer is NULL" ); demand_rn( lerp != NULL, X42_ERR_BADPTR, "lerp is NULL" ); demand_rn( x42 != NULL, X42_ERR_BADPTR, "x42 is NULL" ); demand_rn( x42_ValidateHeader( &x42->header ), X42_ERR_BADDATA, "invalid x42 header data" ); #endif pv = lerp->p; sv = lerp->s; rv = lerp->r; ret = (affine_t*)out_buffer; for( i = 0; i < x42->header.numBones; i++ ) { affine_t * RESTRICT o = ret + i; const x42bone_t * RESTRICT b = x42->bones + i; if( b->parentIdx != X42_MODEL_BONE && (b->flags & X42_BF_USE_INV_PARENT_SCALE) ) { vec3_t ips; affine_t rs; quat_to_affine( &rs, rv[i] ); vec3_scale( rs.c[0], rs.c[0], sv[i][0] ); vec3_scale( rs.c[1], rs.c[1], sv[i][1] ); vec3_scale( rs.c[2], rs.c[2], sv[i][2] ); ips[0] = 1.0F / sv[b->parentIdx][0]; ips[1] = 1.0F / sv[b->parentIdx][1]; ips[2] = 1.0F / sv[b->parentIdx][2]; vec3_mul( o->c[0], rs.c[0], ips ); vec3_mul( o->c[1], rs.c[1], ips ); vec3_mul( o->c[2], rs.c[2], ips ); } else { quat_to_affine( o, rv[i] ); vec3_scale( o->c[0], o->c[0], sv[i][0] ); vec3_scale( o->c[1], o->c[1], sv[i][1] ); vec3_scale( o->c[2], o->c[2], sv[i][2] ); } vec3_cpy( o->c[3], pv[i] ); } for( i = 0; i < x42->header.numBones; i++ ) { const x42bone_t * RESTRICT b = x42->bones + i; if( b->parentIdx != X42_MODEL_BONE ) affine_mul( ret + i, ret + b->parentIdx, ret + i ); else if( x42->header.runFlags & X42_RF_ROOT_MATRIX ) affine_mul( ret + i, &x42->rootMatrix, ret + i ); } return ret; }
static void draw_screen( OBJSC * model ) { /* Our angle of rotation. */ /* * EXERCISE: * Replace this awful mess with vertex * arrays and a call to glDrawElements. * * EXERCISE: * After completing the above, change * it to use compiled vertex arrays. * * EXERCISE: * Verify my windings are correct here ;). */ static GLubyte red[] = { 255, 0, 0, 255 }; static GLubyte green[] = { 0, 255, 0, 255 }; static GLubyte blue[] = { 0, 0, 255, 255 }; static GLubyte white[] = { 255, 255, 255, 255 }; static GLubyte yellow[] = { 0, 255, 255, 255 }; static GLubyte black[] = { 0, 0, 0, 255 }; static GLubyte orange[] = { 255, 255, 0, 255 }; static GLubyte purple[] = { 255, 0, 255, 0 }; /* Clear the color and depth buffers. */ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); /* We don't want to modify the projection matrix. */ glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); /* Move down the z-axis. */ glRotatef( 20, 1.0, 0.0, 0.0 ); glTranslatef( 0.0, -100.0, -150.0 ); /* Rotate. */ glRotatef( angle*8, 0.0, 1.0, 0.0 ); /* Send our triangle data to the pipeline. */ int i; for(i = 0; i < model->vlen; i++) { calc_vertex(model, i, game_time, speed); calc_vertex_normal(model, i, model->vntable[i]); } glBegin( GL_TRIANGLES ); for(i = 0; i < model->flen; i++) { if(model->ftable[i].data == 2) { glColor4ubv( white ); } else if(model->ftable[i].data == 3) { glColor4ubv( black ); } else { glColor4ubv( black ); } vec3 normal; vec3 a; vec3 b; vec3 c; vec3 an; vec3 bn; vec3 cn; vec3_cpy(a, model->vtable[model->ftable[i].a]); vec3_cpy(b, model->vtable[model->ftable[i].b]); vec3_cpy(c, model->vtable[model->ftable[i].c]); vec3_cpy(an, model->vntable[model->ftable[i].a]); vec3_cpy(bn, model->vntable[model->ftable[i].b]); vec3_cpy(cn, model->vntable[model->ftable[i].c]); glColor3fv( an); glVertex3fv( a ); glColor3fv( bn); glVertex3fv( b ); glColor3fv( cn); glVertex3fv( c ); } glEnd( ); /* * EXERCISE: * Draw text telling the user that 'Spc' * pauses the rotation and 'Esc' quits. * Do it using vetors and textured quads. */ /* * Swap the buffers. This this tells the driver to * render the next frame from the contents of the * back-buffer, and to set all rendering operations * to occur on what was the front-buffer. * * Double buffering prevents nasty visual tearing * from the application drawing on areas of the * screen that are being updated at the same time. */ SDL_GL_SwapBuffers( ); }