So variable interpolation was simpler than I expected. It's pretty coarse, but it works.
The struct is now like this:
typedef struct
{
bool uniform;
Uint8 arate[256];
Uint16 currentFrm;
Uint8 currentKeyFrm;
Uint8 startFrm;
Uint8 endFrm;
} animationControl;
Note arate, a 256 array of 8-bit values. The array size corresponds with the key frame data sizes.
For each frame of your animation area, if it is of non-uniform interpolation speed, you must define the arate for each key frame.
void anim_defs(void)
{
forward.uniform = false;
forward.arate[0] = 1;
forward.arate[1] = 4;
forward.arate[2] = 1;
forward.arate[3] = 1;
forward.arate[4] = 4;
forward.arate[5] = 1;
forward.arate[6] = 1;
forward.currentKeyFrm = 0;
forward.startFrm = 1;
forward.endFrm=7;
left.uniform = false;
left.arate[8] = 2;
left.arate[9] = 1;
left.arate[10] = 1;
left.arate[11] = 2;
left.currentKeyFrm = 8;
left.startFrm = 8;
left.endFrm = 11;
right.uniform = false;
right.arate[10] = 2;
right.arate[11] = 1;
right.arate[12] = 1;
right.arate[13] = 2;
right.currentKeyFrm = 10;
right.startFrm = 10;
right.endFrm = 13;
idle.uniform = false;
idle.arate[0] = 0;
idle.currentKeyFrm = 8;
idle.startFrm = 7;
idle.endFrm = 7;
}
And here's a slightly changed animation code.
/**XL2 Animation Interpolation system with ANORM.h lookup table**/
#include "anorm.h"
void display_animated_model(animationControl * animCtrl, entity_t * currentModel, bool UseRealtimeGouraud)
{
if(currentModel->nbMeshes < 1){
return;
}
Uint8 ANIM_SIZE = 6;
Uint8 ANIM_QUAL = 3;
XPDATA * currentPDATA = currentModel->pol[0];
/**Sets the animation data**/
///Variable interpolation set
if(animCtrl->uniform == false){
animCtrl->currentFrm += animCtrl->arate[animCtrl->currentKeyFrm];
} else {
animCtrl->currentFrm += 2;
}
///MATH: The below line increments the key-frame based on the current frame, which is incremented each frame by the arate.
///The arate in this case is 2. With an arate of 2, the current frame goes up twice for every frame of the game played...
///To compensate for this, we bitshift by 3 instead of 4 to increment the keyframe once every 30 iterations instead of once every 15 iterations.
///The ultimate control is the arate. XL2 set it up this way so it could be related to the game's frame-rate value, which at 30fps, is 2.
///It really does need to be this way or else the compression ratio does not work at all properly.
///This is, for all practical purposes, a fixed-function animation system with only 1 controllable variable of precise operation: the arate. (though creative souls could change the anim size variable)
animCtrl->currentKeyFrm = (animCtrl->currentFrm>>3); //should be >>currentModel->AnimInterpolation;
if (animCtrl->currentKeyFrm >= animCtrl->endFrm) {
animCtrl->currentFrm -= (animCtrl->endFrm - animCtrl->startFrm)<<3; //<<currentModel->AnimInterpolation;
animCtrl->currentKeyFrm = animCtrl->currentFrm>>3; //>>currentModel->AnimInterpolation;
} else if(animCtrl->currentKeyFrm < animCtrl->startFrm){
animCtrl->currentKeyFrm = animCtrl->startFrm;
animCtrl->currentFrm += (animCtrl->endFrm-animCtrl->startFrm)<<3;
}
Uint8 nextKeyFrm = animCtrl->currentKeyFrm+1;
if (nextKeyFrm >= animCtrl->endFrm){
nextKeyFrm = animCtrl->startFrm;
} else if (nextKeyFrm <= animCtrl->startFrm){
nextKeyFrm = animCtrl->startFrm;
}
compVert * curKeyFrame = (compVert*)currentModel->animation[animCtrl->currentKeyFrm]->cVert;
compVert * nextKeyFrame = (compVert*)currentModel->animation[nextKeyFrm]->cVert;
///Don't touch this!
Uint32 compHelp = (animCtrl->currentFrm)-(animCtrl->currentKeyFrm<<3);
/*if (nextKeyFrm>animCtrl->currentKeyFrm) compHelp = animCtrl->currentFrm-(animCtrl->currentKeyFrm<<3);
else compHelp = animCtrl->currentFrm-(animCtrl->currentKeyFrm<<3);*/
/**Uncompress the vertices and apply linear interpolation**/
register Uint32 i;
Sint32 *dst=currentPDATA->pntbl[0];
Sint16 *src=curKeyFrame[0];
Sint16 *nxt=nextKeyFrame[0];
///Decompression
for (i = 0; i < currentPDATA->nbPoint*sizeof(POINT); i+= sizeof(int)) {
*dst++=(*src+(((*nxt-*src)*compHelp)>>ANIM_QUAL))<<ANIM_SIZE;
*src++; *nxt++;
}
*dst=currentPDATA->pltbl[0].norm[0];
Uint8 *src2=currentModel->animation[animCtrl->currentKeyFrm]->cNorm;
///Interpolation
for (i = 0; i < currentPDATA->nbPolygon; i++) {
/**Not 100% sure which technique is faster**/
// currentPDATA->pltbl[i].norm[X]=ANORMS[*src2][X];
// currentPDATA->pltbl[i].norm[Y]=ANORMS[*src2][Y];
// currentPDATA->pltbl[i].norm[Z]=ANORMS[*src2++][Z];
*dst++=ANORMS[*src2][X];
*dst++=ANORMS[*src2][Y];
*dst++=ANORMS[*src2++][Z];
*dst++; *dst++;
}
jo_printf(0, 10, "(anim dat)");
jo_printf(0, 11, "(%i)", dst);
jo_printf(0, 12, "(%i)", src);
jo_printf(0, 13, "(%i)", dst);
jo_printf(0, 15, "(%i)", animCtrl->currentKeyFrm);
jo_printf(0, 16, "(%i)", animCtrl->currentFrm);
jo_printf(0, 17, "(%i)", animCtrl->startFrm);
jo_printf(0, 18, "(%i)", animCtrl->endFrm);
jo_printf(0, 19, "(%i)", compHelp);
if (UseRealtimeGouraud) slPutPolygonX(currentPDATA, light);
else slPutPolygon((PDATA*)currentPDATA);
}
http://www.mediafire.com/file/78rr5pc0zbvln52/proj_8118.zip/file