/* ==========================================================================
                            KEY.C
=============================================================================

    DESCRIPTION
    This module has keyframe animation and library routines. Maintains a binary 
	keyframe animation facility fro read, writing , interpolating , steping through
	and maintain keys. Also reading and writing keyframe animation files. As well
	as routines to read and write for face library files and filter face regions.
	All keys and library files have paramters as there main data block.

    HISTORY
	3/10   steve dipaola    update lip sync routines
	3/09   gary king        added multiple curve interpolation routines
	3/07   gary king        changed draw frame procedure to use floats, added linterpf procedure
	1/01   steve dipaola    ported from SGI


    FUNCTION NAMES


    C SPECIFICATIONS

============================================================================ */

#include <stdio.h>
#include <string.h>		/* For String compare 			     */
#include <stdlib.h>
#include "head.h"
#include <GL/glut.h>	    /* OpenGl headers - aadesche     */
#include <math.h>   // GCK 3.09.01
#include "perlin.h" // GCK 3.09.01

int frtf[40];    /* facial region track facility tmp array */

#define O80MAXPM 80
#define O110MAXPM 110

/* GCK 3.09.01 -----------------> */
#ifndef M_PI
#define M_PI 3.1415926538
#endif
#define noisyinterpf(a,b,c,d,e) linterpf(sin(((a)+PerlinNoise1D(a,2.0,2.0,2))*M_PI),b,c,d,e)
#define quadraticinterpf(a,b,c,d,e) linterpf((a)*(a),b,c,d,e)
/*  -----------> GCK 3.09.01 */

struct khdr {		/* key file header */
  int usrbit1;
  int usrbit2;
  int numkeys;
} keyhdr;

struct krec {		/* key record struct for key file */
   short keynum;
   char pmnum[MAXPM];
   float pmr[MAXPM];
   float pml[MAXPM];
} keyrec;

struct o80krec {		/* old 80 key record struct for old key file */
   short keynum;
   char pmnum[O80MAXPM];
   float pmr[O80MAXPM];
   float pml[O80MAXPM];
} o80keyrec;

struct o110krec {		/* old 110 key record struct for old key file */
   short keynum;
   char pmnum[O110MAXPM];
   float pmr[O110MAXPM];
   float pml[O110MAXPM];
} o110keyrec;

struct lhdr {		/* key file header */
  int nframes;
  int usrbit1;
} lipshdr;

struct lrec {		/* key record struct for key file */
   short fnum;
   short npms;
   char side[MAXPM];
   int pnum[MAXPM];
   float pval[MAXPM];
} lipsrec;


static char *keyfile="fas.keys";	/* file name for keys file */
static char *lipsfile="fas.lips";	/* file name for lip sync file */
static char *tempfile="fas.tmp";
static int lipsframes;

int khdrlen=sizeof(struct khdr);
int kreclen=sizeof(struct krec);
int o80kreclen=sizeof(struct o80krec);
int o110kreclen=sizeof(struct o110krec);

int lhdrlen=sizeof(struct lhdr);
int lreclen=sizeof(struct lrec);


void PrintKeys(int f)		/* print out all key frames */
{
int i;
   printf("keys: ");
   for (i=0; i<g_nkeys; i++)
      printf(" %d",g_keys[i]);
   printf(", Current Frame is %d\n",f);
}


int SetUpKeys()      /* if keyfile exists, set up key list, else InitKeys */
{
FILE *kfp;
int i,f;
   if ((kfp = fopen(keyfile,"rb"))==NULL) {
      InitKeys();
      f=0;
   }
   else {	/* set up key list from key file */
      if( fread(&keyhdr ,khdrlen,1,kfp)!=1) Ferr('r',101,keyfile);
      g_nkeys=keyhdr.numkeys;
      if (keyhdr.usrbit1 != MAXPM) {
         printf(" old style anim list [%d]\n", keyhdr.usrbit1);
         printf(" converting to new style\n");
	 fclose(kfp);
      if (keyhdr.usrbit1 == O80MAXPM) ConvertKeys80();
      if (keyhdr.usrbit1 == O110MAXPM) ConvertKeys110();
         kfp = fopen(keyfile,"rb");
         if( fread(&keyhdr ,khdrlen,1,kfp)!=1) Ferr('r',111,keyfile);
         g_nkeys=keyhdr.numkeys;

      }
      for (i=0;i<g_nkeys;i++) {
         if( fread(&keyrec.keynum ,sizeof(short),1,kfp)!=1) Ferr('r',12,keyfile);
         fseek(kfp,kreclen - sizeof(short),1);
	 g_keys[i]=keyrec.keynum;
      printf(" %d",g_keys[i]);
      }
      printf(" \n");
      f=g_keys[0];	/* set up first key */
      ReadKey(f);
      UpdateObject();
	  glutPostRedisplay();
     /* SetFrameInfoParams(f); */
      fclose(kfp);
   }
   return(f);
}

void InitKeys()	/* initialize key list, and key file. Write out key 0 */
{
int f;
FILE *kfp;
   printf("Creating \"%s\".\n",keyfile);
   if ((kfp = fopen(keyfile,"wb"))==NULL) Ferr('f',1,keyfile);
   /* init keyfile header */
   keyhdr.usrbit1=MAXPM; keyhdr.usrbit2=1; keyhdr.numkeys=1;
   if( fwrite(&keyhdr ,khdrlen,1,kfp)!=1) Ferr('w',1,keyfile);
   f=0;			/* write default key 0) */
   g_nkeys=1;
   WriteKeyData(kfp,f);
   g_keys[0]=f;
   fclose(kfp);
   /*
   SetFrameInfoParams(f);
   SetSliderHeaderParams(1,TEXTCOLOR2,PAGE);
   */
}

/* linear interp key  calculates: right and left frame data into cpm */
/* int f,f0,f1;         frame you want, low frame ,high frame */
/* float lv0[],lv1[];	left data 0-low 1-high */
/* float rv0[],rv1[];	right data 0-low 1-high */
void linterp(int f,int f0,int f1,float lv0[],float lv1[],float rv0[],float rv1[])
{
int i;
/*	lerp	(x0 + ((t - t0) / (t1 - t0)) * (x1 - x0)) */

    for(i=1;i<MAXPM;i++) {			/* for all pms */
       cpml[i] = ( lv0[i] + (( (float) f - (float) f0) /  ( (float) f1 - (float) f0 )) * (lv1[i]-lv0[i] ));
       cpmr[i] = ( rv0[i] + (( (float) f - (float) f0) /  ( (float) f1 - (float) f0 )) * (rv1[i]-rv0[i] ));
    }
}

/********************* -------------->
  GCK 3/07/01 */

void linterpf(float a, float t0_L[], float t0_R[], float t1_L[], float t1_R[])
{
	int i;
	for (i=1; i<MAXPM; i++)
	{
		cpml[i] = (1-a)*t0_L[i] + a*t1_L[i];
		cpmr[i] = (1-a)*t0_R[i] + a*t1_R[i];
	}
}
/* -------------------> */

int ReadKey(int f)		/* read in key frame */
{
FILE *kfp;
int k,stat;
   k = LookKey(f);
   if (k != -1) {		/* valid keyframe: */
      if ((kfp = fopen(keyfile,"rb"))==NULL) Ferr('f',2,keyfile);
      fseek(kfp, k * kreclen + khdrlen,0);
      if( fread(&keyrec ,kreclen,1,kfp)!=1) Ferr('r',1,keyfile);
#ifdef DEBUG
      printf("Reading key frame %d.\n",keyrec.keynum);
#endif
      memmove(cpml,keyrec.pml,sizeof(cpml));
      memmove(cpmr,keyrec.pmr,sizeof(cpmr));
      memmove(bpml,cpml,sizeof(bpml));
      memmove(bpmr,cpmr,sizeof(bpmr));
      memmove(wpml,cpml,sizeof(wpml));
      memmove(wpmr,cpmr,sizeof(wpmr));
      stat=TRUE;
      fclose(kfp);
   }
   else if (f > g_keys[0] && f < g_keys[g_nkeys-1]) { /* not key frame, interp it */
      ReadFrame(f);
      stat=TRUE;
   }
   else {
      printf("%d is not a frame.\n",f);
      stat=FALSE;
   }
   if (stat && g_lipsync) AddLipParams(f);
   return(stat);
}

int ReadFrame(int f)	/* use interp to get new frame */
{

   int lk,hk;		/* low key, high key */
   float lowkeyl[MAXPM],highkeyl[MAXPM];
   float lowkeyr[MAXPM],highkeyr[MAXPM];

#ifdef DEBUG
   printf("Reading (interping) frame %d.\n",f);
#endif
   lk=LowKey(f);
   hk=lk+1;
   GetKey(lk,lowkeyl,lowkeyr);
   GetKey(hk,highkeyl,highkeyr);
   linterp(f,g_keys[lk],g_keys[hk],lowkeyl,highkeyl,lowkeyr,highkeyr);
   return(TRUE);
}

int WriteKey(int f)	/* write out key frame , ie change, insert or append key file */
{
int i,k;
FILE *kfp, *tfp;
char sfile[MAX_LINE];
   k = LookKey(f);
   if (k == -1 && g_nkeys >= MAXKEYS) {		/* not valid frame: */
      printf("Too many key frames.\n");
      return(FALSE);
   }
   if (k == -1 && f < 0) {
      printf("Key frame must be >= 0.\n");
      return(FALSE);
   }
   /*	valid frame: */
   if ((kfp = fopen(keyfile,"rb+"))==NULL) Ferr('f',1,keyfile);

   if (k != -1) {			/* update key in place */
      fseek(kfp, k * kreclen + khdrlen,0);
      WriteKeyData(kfp,f);
      printf("changed %d\n",f);
	  fclose(kfp);
   }
   else if ( f > g_keys[g_nkeys-1]) {		/* append key */
      fseek(kfp,0,2);
      WriteKeyData(kfp,f);
      g_keys[g_nkeys++]=f;
      keyhdr.numkeys=g_nkeys;
      fseek(kfp, 0,0);
      if ( fwrite(&keyhdr ,khdrlen,1,kfp)!=1) Ferr('w',1,keyfile);
      printf("appended %d\n",f);
	  fclose(kfp);
   }
   else {				/* insert key */
      for (k=0;g_keys[k]<f;k++);
      if ((tfp = fopen(tempfile,"wb"))==NULL) Ferr('f',1,tempfile);
      fseek(kfp, 0,0);
      if( fread(&keyhdr ,khdrlen,1,kfp)!=1) Ferr('r',2,keyfile);
      keyhdr.numkeys++;
      if( fwrite(&keyhdr ,khdrlen,1,tfp)!=1) Ferr('w',2,tempfile);
      for (i=0;i<k;i++) {
         if( fread(&keyrec ,kreclen,1,kfp)!=1) Ferr('r',3,keyfile);
         if( fwrite(&keyrec ,kreclen,1,tfp)!=1) Ferr('w',3,tempfile);
      }
      /* fseek(tfp,(k+1) * kreclen + khdrlen,0); */ /* write new rec to tmp */
      WriteKeyData(tfp,f);
      for (i=g_nkeys;i>k;i--) {		/* cp after recs to tmp */
	 g_keys[i]=g_keys[i-1];
         if( fread(&keyrec ,kreclen,1,kfp)!=1) Ferr('r',4,keyfile);
         if( fwrite(&keyrec ,kreclen,1,tfp)!=1) Ferr('w',4,tempfile);
      }
      g_keys[i]=f;
      g_nkeys++;
      fclose(tfp);
      /* rename(tempfile,keyfile); */
	  fclose(kfp);
      sprintf(sfile,"copy %s %s",tempfile,keyfile);
	  system(sfile); 

      printf("inserted %d\n",f);
   }
;
   return(TRUE);
}

int DeleteKey(int f)		/* Delete Key frame */
{
int i,k;
FILE *kfp, *tfp;
char sfile[MAX_LINE];
   k = LookKey(f);
   if (k == 0) {
      fprintf(stderr," Can not delete key frame 0.\n");
      return (FALSE);
   }
   if (k != -1) {
      if ((kfp = fopen(keyfile,"rb+"))==NULL) Ferr('f',1,keyfile);
      if ((tfp = fopen(tempfile,"wb"))==NULL) Ferr('f',1,tempfile);

      fseek(kfp, 0,0);	/* cp header to tmp */
      if( fread(&keyhdr ,khdrlen,1,kfp)!=1) Ferr('r',1,keyfile);
      keyhdr.numkeys--;
      if( fwrite(&keyhdr ,khdrlen,1,tfp)!=1) Ferr('w',1,tempfile);
      for (i=0;i<k;i++) {		/* cp previous recs to tmp */
         if( fread(&keyrec ,kreclen,1,kfp)!=1) Ferr('r',2,keyfile);
         if( fwrite(&keyrec ,kreclen,1,tfp)!=1) Ferr('w',2,tempfile);
      }
      fseek(kfp,kreclen,1);		/* skip over "deleted" rec */
      for (i=k;i<g_nkeys-1;i++) {		/* cp after recs to tmp */
	 g_keys[i]=g_keys[i+1];
         if( fread(&keyrec ,kreclen,1,kfp)!=1) Ferr('r',3,tempfile);
         if( fwrite(&keyrec ,kreclen,1,tfp)!=1) Ferr('w',3,tempfile);
      }
      g_nkeys--;
      fclose(tfp);
      /* rename(tempfile,keyfile); */
      fclose(kfp);
      sprintf(sfile,"copy %s %s",tempfile,keyfile);
	  system(sfile);
	  printf("deleted %d\n",f);

   } else {
	   printf("%d is not a key frame.\n",f);
	   
   }
   return(TRUE);	//KLL
}


void WriteKeyData(FILE *fp, int f)  /*   write key data to file  */
{
   keyrec.keynum=f;
   memmove(keyrec.pml,cpml,sizeof (keyrec.pml));
   memmove(keyrec.pmr,cpmr,sizeof (keyrec.pmr));
   memmove(wpml,cpml,sizeof (wpml));
   memmove(wpmr,cpmr,sizeof (wpmr));
   if( fwrite(&keyrec ,kreclen,1,fp)!=1) Ferr('w',0,keyfile);
}

int LookKey(int f)	/* lookup table for key element address given key num */
{
int i;
for (i=0; i<g_nkeys; i++)
	if (g_keys[i] == f) return(i);
return(-1);
}

int LowKey(int f)	/* lookup table for key element address below frame num */
{
int i;
for (i=0; i<g_nkeys; i++)
	if (g_keys[i] > f) return(i-1);
return(-1);
}

int NextHigherKey(int f)  /* lookup table for next higher key given key num */
{
int i;
for (i=0; i<g_nkeys; i++) {
	if (g_keys[i] == f) return(i+1);
	if (g_keys[i] > f) return(i);
	}
return(-1);
}

int NextLowerKey(int f)  /* lookup table for next lower key given key num */
{
int i;
for (i=0; i<g_nkeys; i++) {
	if (g_keys[i] == f) return(i-1);
	if (g_keys[i] > f) return(i-1);
	}
return(-1);
}

int GetKey(int k,float keypml[],float keypmr[])		/* read in key frame to keypm, for interp */
{
struct krec tkeyrec;
FILE *gkfp;
   if ((gkfp = fopen(keyfile,"rb"))==NULL) Ferr('f',2,keyfile);
   fseek(gkfp, k * kreclen + khdrlen,0);
   if( fread(&tkeyrec ,kreclen,1,gkfp)!=1) Ferr('r',1,keyfile);
   memmove(keypml,tkeyrec.pml,sizeof(cpml));
   memmove(keypmr,tkeyrec.pmr,sizeof(cpmr));
   fclose(gkfp);
   return(TRUE);
}

void Ferr(char type,int num,char *fname)	/* print File ERRors */
{
char mess[80];
   switch(type) {
      case 'f': sprintf(mess,"open\"%s\". [%d]\n",num,fname);
		perror(mess);
		exit(1);
		break;
      case 'r': sprintf(mess,"read[%d]: \"%s\".\n",num,fname);
		perror(mess);
		break;
      case 'w': sprintf(mess,"write[%d]: \"%s\".\n",num,fname);
		perror(mess);
		break;
   }
}

/* ScaleKeys - expand, contract keys
/* nlf,ff,lf = new last frame; first frame ,last frame in scale region */
int ScaleKeys(int nlf,int ff,int lf)
{
int i,fk,lk,offset,lastknum;
float scfactor;
char sfile[MAX_LINE];
FILE *kfp, *tfp;
	/* error checks */
   if (g_keys[g_nkeys-1] == 0) {		/* no keys */
      printf("No keys to scale.\n");
      return(FALSE);
   }
   fk = LookKey(ff);
   lk = LookKey(lf);
   if (fk == -1 ||  lk == -1) {
      printf("Not Valid key frame(s).\n");
      return(FALSE);
   }
   if ( ff >= lf) {
      printf("ff must be less than lf\n");
      return(FALSE);
   }
   if ( nlf < ff) {
      printf("nlf must be greater than ff\n");
      return(FALSE);
   }
   /*	all is valid , open files */
   fprintf(stderr,"Rescaling keys from %d-%d to %d-%d\n",ff,lf,ff,nlf);
   if ((kfp = fopen(keyfile,"rb+"))==NULL) Ferr('f',1,keyfile);
   if ((tfp = fopen(tempfile,"wb"))==NULL) Ferr('f',1,tempfile);
   fseek(kfp, 0,0);
   /* cp header */
   if( fread(&keyhdr ,khdrlen,1,kfp)!=1) Ferr('r',2,keyfile);
   if( fwrite(&keyhdr ,khdrlen,1,tfp)!=1) Ferr('w',2,tempfile);
   /* cp  unchanged keys */
   for (i=0;i<=fk;i++) {
      if( fread(&keyrec ,kreclen,1,kfp)!=1) Ferr('r',3,keyfile);
      if( fwrite(&keyrec ,kreclen,1,tfp)!=1) Ferr('w',3,tempfile);
   }
   /* scale keys in scale region then cp */
   lastknum=ff;
   for (i=fk+1;i<=lk;i++) {
      if( fread(&keyrec ,kreclen,1,kfp)!=1) Ferr('r',3,keyfile);
      scfactor=((((keyrec.keynum-ff)*(nlf-ff))/(lf-ff))+ff);
      keyrec.keynum=(int)scfactor;
      if (keyrec.keynum==lastknum) keyrec.keynum++; /* if same key #, add 1 */
      lastknum=keyrec.keynum;
      if( fwrite(&keyrec ,kreclen,1,tfp)!=1) Ferr('w',3,tempfile);
   }
   /* cp remaining keys, if any */
   if (lk != g_nkeys-1) {
      offset=nlf-lf;
      for (i=lk+1;i<g_nkeys;i++) {
         if( fread(&keyrec ,kreclen,1,kfp)!=1) Ferr('r',4,keyfile);
	 keyrec.keynum+=offset;
         if( fwrite(&keyrec ,kreclen,1,tfp)!=1) Ferr('w',4,tempfile);
      }
   }
   fclose(tfp);
   /* rename(tempfile,keyfile); */
   fclose(kfp);
   sprintf(sfile,"copy %s %s",tempfile,keyfile);
   system(sfile);
   /* resetup keys array, print out new keys */
   if ((kfp = fopen(keyfile,"rb+"))==NULL) Ferr('f',1,keyfile);
      if( fread(&keyhdr ,khdrlen,1,kfp)!=1) Ferr('r',1,keyfile);
      g_nkeys=keyhdr.numkeys;
      printf("%d keys: ",g_nkeys);
      for (i=0;i<g_nkeys;i++) {
         if( fread(&keyrec.keynum ,sizeof(short),1,kfp)!=1) Ferr('r',2,keyfile);
         fseek(kfp,kreclen - sizeof(short),1);
	 g_keys[i]=keyrec.keynum;
      printf(" %d",g_keys[i]);
      }
      printf(" \n");
   return(TRUE);
}

int DumpKeyFile()  /* Dump all info of key file (debugging) */
{
FILE *kfp;
int i;
   if ((kfp = fopen(keyfile,"rb"))==NULL)
      fprintf(stderr,"No File");
   else {	/* read, dump key file */
      if( fread(&keyhdr ,khdrlen,1,kfp)!=1) Ferr('r',1,keyfile);
      fprintf(stderr,"header: numkeys %d,usrb1 %d,usrb2 %d\n",keyhdr.numkeys,keyhdr.usrbit1,keyhdr.usrbit2);
      for (i=0;i<keyhdr.numkeys;i++) {
      if( fread(&keyrec ,kreclen,1,kfp)!=1) Ferr('r',1,keyfile);
      fprintf(stderr,"rec: %d,pm1 %g,pm80 %g\n",keyrec.keynum,keyrec.pmr[1],keyrec.pmr[MAXPM]);
      }
   }
   fclose(kfp);
   return(TRUE);
}

/* WriteParam - write specific param from lkey to hkey */
int WriteParam(int lf,int hf,int pnum,float lpval,float rpval)
{
int f,i,lk,hk;
FILE *kfp;
   lk = LookKey(lf);
   hk = LookKey(hf);
   printf("lf %d ,hf %d,lk %d,hk %d\n",lf,hf,lk,hk);
   if (lk == -1) { printf("Frame %d not a key frames.\n",lf); return(FALSE); }
   if (hk == -1) { printf("Frame %d not a key frames.\n",hf); return(FALSE); }
   /*	valid frame: change first key*/
   if ((kfp = fopen(keyfile,"rb+"))==NULL) Ferr('f',1,keyfile);
      fseek(kfp, lk * kreclen + khdrlen,0);
      if( fread(&keyrec ,kreclen,1,kfp)!=1) Ferr('r',1,keyfile);
      printf("b,kr.pmr %g,kr.pml %g\n",keyrec.pmr[pnum],keyrec.pml[pnum]);
      keyrec.pmr[pnum]=rpval;
      keyrec.pml[pnum]=lpval;
      f=keyrec.keynum;
      printf("a,kr.pmr %g,kr.pml %g\n",keyrec.pmr[pnum],keyrec.pml[pnum]);
      fseek(kfp, lk * kreclen + khdrlen,0);
   if( fwrite(&keyrec ,kreclen,1,kfp)!=1) Ferr('w',0,keyfile);
      printf("key %d , parameter %d changed l %g,r %g\n",f,pnum,lpval,rpval);
   for (i=lk+1; i<=hk; i++) {  /* change next keys */
      fseek(kfp, i * kreclen + khdrlen,0);
      if( fread(&keyrec ,kreclen,1,kfp)!=1) Ferr('r',1,keyfile);
      keyrec.pmr[pnum]=rpval;
      keyrec.pml[pnum]=lpval;
      f=keyrec.keynum;
      fseek(kfp, i * kreclen + khdrlen,0);
   if( fwrite(&keyrec ,kreclen,1,kfp)!=1) Ferr('w',0,keyfile);
      printf("key %d , parameter %d changed l %g,r %g\n",f,pnum,lpval,rpval);
   }
   fclose(kfp);
   return(TRUE);
}

int InterpParam(int lf,int hf,int pnum) /* interp specific param from lkey to hkey */
{
int i,lk,hk;
float lowkeyl[MAXPM],highkeyl[MAXPM];
float lowkeyr[MAXPM],highkeyr[MAXPM];
FILE *kfp;
   lk = LookKey(lf);
   hk = LookKey(hf);
   printf("lf %d ,hf %d,lk %d,hk %d\n",lf,hf,lk,hk);
   if (lk == -1) { printf("Frame %d not a key frame.\n",lf); return(FALSE); }
   if (hk == -1) { printf("Frame %d not a key frame.\n",hf); return(FALSE); }

   if ((kfp = fopen(keyfile,"rb+"))==NULL) Ferr('f',1,keyfile);
   for (i=lk+1; i<hk; i++) {  /* change keys between lk and hk */
      fseek(kfp, i * kreclen + khdrlen,0);
      if( fread(&keyrec ,kreclen,1,kfp)!=1) Ferr('r',1,keyfile);
      GetKey(lk,lowkeyl,lowkeyr);
      GetKey(hk,highkeyl,highkeyr);
keyrec.pml[pnum]= ( lowkeyl[pnum] + (( (float) g_keys[i] - (float) g_keys[lk]) /	    ( (float) g_keys[hk] - (float) g_keys[lk] )) * (highkeyl[pnum]-lowkeyl[pnum] ));
keyrec.pmr[pnum] = ( lowkeyr[pnum] + (( (float) g_keys[i] - (float) g_keys[lk]) /          ( (float) g_keys[hk] - (float) g_keys[lk] )) * (highkeyr[pnum]-lowkeyr[pnum] ));
keyrec.keynum=(short)g_keys[i];
      fseek(kfp, i * kreclen + khdrlen,0);
   if( fwrite(&keyrec ,kreclen,1,kfp)!=1) Ferr('w',0,keyfile);
      printf("key %d , parameter %d changed to r %g l%g\n",g_keys[i],pnum,keyrec.pmr[pnum],keyrec.pmr[pnum]);
   }
   fclose(kfp);
   return(TRUE);
}




/*  CreateLips - create binary file for lip sync froomm ascii lip file */
int CreateLips(char file[])
{
char k;
int  i,j;
FILE *ifp ,*ofp;
FILE *fopen();
j=0;
   if ((ifp = fopen(file,"r"))==NULL) {
    fprintf(stderr,"Can not read lip sync file \"%s\".\n",file);
    return(FALSE);
   }

   if ((ofp = fopen(lipsfile,"wb"))==NULL) {
    fprintf(stderr,"Can not open binary lip sync file \"%s\".\n",lipsfile);
    return(FALSE);
   }

   lipshdr.nframes=0; lipshdr.usrbit1=MAXPM;
   if( fwrite(&lipshdr ,lhdrlen,1,ofp)!=1) Ferr('w',1,lipsfile);
   i=1;
   if (fscanf(ifp,"%c",&k)<0 ) Ferr('r',2,lipsfile);

   while (fscanf(ifp,"%c",&k)==1) {
   if (k=='k') {
      lipsrec.npms=j;
      if( fwrite(&lipsrec ,lreclen,1,ofp)!=1) Ferr('w',3,lipsfile);
      j=0;
      i++;
      }
    else {
       if (fscanf(ifp,"%d%f\n",&lipsrec.pnum[j],&lipsrec.pval[j])==2) { j++;
       lipsrec.side[j-1]=k;
       }
   }
       /* lipsrec.side[j]='e'; */
   }
      lipsrec.npms=j;
      if( fwrite(&lipsrec ,lreclen,1,ofp)!=1) Ferr('w',3,lipsfile);
    lipshdr.nframes=i; lipshdr.usrbit1=MAXPM;
   lipsframes=i;
   fseek(ofp, 0,0);
   if( fwrite(&lipshdr ,lhdrlen,1,ofp)!=1) Ferr('w',4,lipsfile);
    fclose(ifp);
    fclose(ofp);
    return(TRUE);
}

/* add lip params from fas.lips to the curent frame to be displayer in playback*/
int AddLipParams(int f)
{
int  i=0, match=1;
FILE *lfp ,*fopen();

if (f > lipsframes) {
  /*fprintf(stderr,"no lip sync: lip sync only goes to frame %d\n",lipsframes); */
  return(FALSE);
  } else {
   if ((lfp = fopen(lipsfile,"rb"))==NULL) {
    fprintf(stderr,"Can not read file \"%s\".\n",lipsfile);
    return(FALSE);
   }
      fseek(lfp, f * lreclen + lhdrlen,0);
      if( fread(&lipsrec ,lreclen,1,lfp)!=1) /* Ferr('r',1,lipsfile) */;
       /* fprintf(stderr,"lip sync\n"); */
      for (i=0;i<lipsrec.npms;i++) {
        if (lipsrec.side[i]=='r') cpmr[lipsrec.pnum[i]]=lipsrec.pval[i];
        else if (lipsrec.side[i]=='l') cpml[lipsrec.pnum[i]]=lipsrec.pval[i];
        else if (lipsrec.side[i]=='p') { cpml[lipsrec.pnum[i]]=lipsrec.pval[i]; cpmr[lipsrec.pnum[i]]=lipsrec.pval[i]; }
          else { fprintf(stderr,"error lipsrec[%d]=%c\n",i,lipsrec.side[i]);
	        return(FALSE); }
       }

        cpml[63] =  - cpmr[63];
      memmove(bpml,cpml,sizeof(bpml));
      memmove(bpmr,cpmr,sizeof(bpmr));
      memmove(wpml,cpml,sizeof(wpml));
      memmove(wpmr,cpmr,sizeof(wpmr));
    fclose(lfp);
    return(TRUE);
    }
}


int ConvertKeys80()	/* convert keys to new format */
{
int i;
FILE *kfp, *tfp;
char sfile[MAX_LINE];
   /*	all is valid , open files */
   if ((kfp = fopen(keyfile,"rb+"))==NULL) Ferr('f',1,keyfile);
   if ((tfp = fopen(tempfile,"wb"))==NULL) Ferr('f',1,tempfile);
   fseek(kfp, 0,0);
   fseek(tfp, 0,0);
   /* dont cp header */
   if( fread(&keyhdr ,khdrlen,1,kfp)!=1) Ferr('r',2,keyfile);
   keyhdr.usrbit1=MAXPM;
   if( fwrite(&keyhdr ,khdrlen,1,tfp)!=1) Ferr('w',2,tempfile);
   /* cp keys */
   for (i=0;i<g_nkeys;i++) {
      if( fread(&o80keyrec ,o80kreclen,1,kfp)!=1) Ferr('r',3,keyfile);
	 keyrec.keynum=o80keyrec.keynum;
         memmove(keyrec.pml,cpml,sizeof (keyrec.pml));
         memmove(keyrec.pmr,cpmr,sizeof (keyrec.pmr));
         memmove(keyrec.pml,o80keyrec.pml,sizeof (o80keyrec.pml));
         memmove(keyrec.pmr,o80keyrec.pmr,sizeof (o80keyrec.pmr));
      if( fwrite(&keyrec ,kreclen,1,tfp)!=1) Ferr('w',3,tempfile);
   } 
   fclose(tfp);
   /* rename(tempfile,keyfile); */
   fclose(kfp);
   sprintf(sfile,"copy %s %s",tempfile,keyfile);
    system(sfile); 
   return(TRUE);
}


int ConvertKeys110()	/* convert keys to new format */
{
int i;
char sfile[MAX_LINE];

FILE *kfp, *tfp;
   /*	all is valid , open files */
   if ((kfp = fopen(keyfile,"rb+"))==NULL) Ferr('f',1,keyfile);
   if ((tfp = fopen(tempfile,"wb"))==NULL) Ferr('f',1,tempfile);
   fseek(kfp, 0,0);
   fseek(tfp, 0,0);
   /* dont cp header */
   if( fread(&keyhdr ,khdrlen,1,kfp)!=1) Ferr('r',2,keyfile);
   keyhdr.usrbit1=MAXPM;
   if( fwrite(&keyhdr ,khdrlen,1,tfp)!=1) Ferr('w',2,tempfile);
   /* cp keys */
   for (i=0;i<g_nkeys;i++) {
      if( fread(&o110keyrec ,o110kreclen,1,kfp)!=1) Ferr('r',3,keyfile);
	 keyrec.keynum=o110keyrec.keynum;
         memmove(keyrec.pml,cpml,sizeof (keyrec.pml));
         memmove(keyrec.pmr,cpmr,sizeof (keyrec.pmr));
         memmove(keyrec.pml,o110keyrec.pml,sizeof (o110keyrec.pml));
         memmove(keyrec.pmr,o110keyrec.pmr,sizeof (o110keyrec.pmr));
      if( fwrite(&keyrec ,kreclen,1,tfp)!=1) Ferr('w',3,tempfile);
   } 
   fclose(tfp);
   /* rename(tempfile,keyfile); */
   fclose(kfp);
   sprintf(sfile,"copy %s %s",tempfile,keyfile);
   system(sfile); 
   return(TRUE);
}



/* GetRegionPm  - load up pm indices of facial region tracks */
int GetRegionPm(char rname[])
{
int i;

	for(i=0;i<40;i++) frtf[i]=0;

   switch (rname[0]) {
      case 'm':
      i=0;
frtf[i++]= 4; frtf[i++]= 61; frtf[i++]= 62; frtf[i++]= 63; frtf[i++]= 64;
frtf[i++]= 65; frtf[i++]= 66; frtf[i++]= 67; frtf[i++]= 68; frtf[i++]= 69;
frtf[i++]= 70; frtf[i++]= 71; frtf[i++]= 72; frtf[i++]= 73; frtf[i++]= 74;
frtf[i++]= 75; frtf[i++]= 76; frtf[i++]= 77; frtf[i++]= 78; frtf[i++]= 12;
frtf[i++]= 79;
   	      break;
      case 'e':
      i=0;
frtf[i++]= 1; frtf[i++]= 45; frtf[i++]= 5; frtf[i++]= 6; frtf[i++]= 51;
frtf[i++]= 52; frtf[i++]= 7; frtf[i++]= 8; frtf[i++]= 9; frtf[i++]= 2;
frtf[i++]= 34;
	      break;
      case 's':
      i=0;
frtf[i++]= 1; frtf[i++]= 51;
frtf[i++]= 52; frtf[i++]= 7; frtf[i++]= 8; frtf[i++]= 9; frtf[i++]= 2;
frtf[i++]= 34;
	      break;
    default: { printf("Not a track region\n"); return(FALSE); }
      }
      return(TRUE);
}

/*  ReadLibrary  - read in entry (pm file)  and apply to current frame */
int ReadLibrary(char *pffile,int frtf_on)
{
char pletter;
int  i=0, match=1, pnum;
float pval;
FILE *pfp ,*fopen();
   if ((pfp = fopen(pffile,"rb"))==NULL) {
    fprintf(stderr,"Can not read file \"%s\".\n",pffile);
    return(FALSE);
   }
   match=1;
    while (fscanf(pfp,"%c %d %f\n", &pletter,&pnum,&pval)>0) {
       if (frtf_on) {
       match=0;
       for(i=0;i<40;i++) if (pnum==frtf[i]) match=1;
       }
       if (match){
          if (pletter=='r') cpmr[pnum]=pval;
          else if (pletter=='l') cpml[pnum]=pval;
          else if (pletter=='p') { cpml[pnum]=pval; cpmr[pnum]=pval; }
          else { fprintf(stderr,"error pletter=%c\n",pletter); return(FALSE); }
       }
    }
      memmove(bpml,cpml,sizeof(bpml));
      memmove(bpmr,cpmr,sizeof(bpmr));
      memmove(wpml,cpml,sizeof(wpml));
      memmove(wpmr,cpmr,sizeof(wpmr));
    fclose(pfp);
    return(TRUE);
}

/* write out entry to library */
int WriteLibrary(char * pffile)
{
int  i;
FILE *pfp ,*fopen();
   if ((pfp = fopen(pffile,"wb"))==NULL) {
    fprintf(stderr,"Can not create file \"%s\".\n",pffile);
    return(FALSE);
   }
   for (i=1; i<MAXPM; i++) {
      if (cpml[i]==cpmr[i])
         fprintf(pfp,"p %d %g\n",i,cpmr[i]);
       else {
         fprintf(pfp,"r %d %g\n",i,cpmr[i]);
         fprintf(pfp,"l %d %g\n",i,cpml[i]);
      }
    }
      memmove(wpml,cpml,sizeof(wpml));
      memmove(wpmr,cpmr,sizeof(wpmr));
    fprintf(stderr,"Library entry \"%s\" saved.\n",pffile);
    fclose(pfp);
    return(TRUE);
}

/* DrawFrame - for animation draw and update a frame fast */
int DrawFrame(float f) // changed by GCK 3/07/01
{
   float a;
   int lk,hk;		/* low key, high key */
   float lowkeyl[MAXPM],highkeyl[MAXPM];
   float lowkeyr[MAXPM],highkeyr[MAXPM];

   lk=LowKey((int)f);
   if (lk==-1) { hk = lk = g_nkeys-1; }
   else hk=lk+1;

   GetKey(lk,lowkeyl,lowkeyr);
   GetKey(hk,highkeyl,highkeyr);

   if (lk < 0 || hk >= g_nkeys) { printf("Internal error playing back animation.\n");  return(1); }
   
   a = (float) (f - (float)g_keys[lk]) / (float) (g_keys[hk] - g_keys[lk]);

   
   /*  GCK 3.09.01 ---> */
   switch(g_interpMode)
   {
   case NOISY: noisyinterpf(a, lowkeyl, lowkeyr, highkeyl, highkeyr);
   case QUADRATIC: quadraticinterpf(a,lowkeyl,lowkeyr,highkeyl,highkeyr); break;
   case LINEAR: 
   default: linterpf(a,lowkeyl, lowkeyr, highkeyl, highkeyr); break;
   }
   /*  GCK ---> */
      
	  if (g_lipsync) AddLipParams(f);  /* if lipsync enabled, add lip sync params to these frame */
	  	/*  define_warp_nodes(); */
      UpdateObject();
   return(TRUE);
}

