// ***** Video For FRACTINT
// ***** Essentially C code, but with some C++ and windows
// ***** (C) 2009 lcdvasrm

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <dos.h>
#include <windows.h>

#include <string>
#include <vector>
using namespace std;

// VFF.cpp : main project file.
// Version 1.3

//#define _strlwr strlwr
//#define _strupr strupr

#define NBR_DYNAMIC_F 13  /* Nombre de fonctions dynamiques */
#define NBR_PARAM 6       /* Fractint 20.0 */
int NB_LINES=576;      /* For PAL. Used only for interlaced mode */
/*#define M_PI 3.1415926535*/
/*
Principe : lecture du fichier film.stb
En Extrait la séquence de prises de vues, le nombre d'images entre chaque
point de vue, le profil de courbe de déplacement … suivre pour chacun des
parametres : position du centre, taille de la zone vue, orientation.

On definit une struture point de vue pdv avec des infos redondantes entre
elles afin de faciliter les traitements selon le contexte
*/

typedef struct {long double x; long double y;} point;
typedef struct {point centre; point tl; point br; point bl; long double fovx; long double fovy; long double angle;} pdv;
typedef enum {SINUS, EXPO, LINEAR, PARABOLE_FALL, PARABOLE_JUMP, SINUS2, ARCOS, SINUS2BIS, ARCOSBIS, ARCOSQUAD, EXPOLIN, SLOW_START, QUICK_START} cine_type;
typedef unsigned char map[256*3];
typedef unsigned long int ulint;
typedef long double (*fd)(ulint ibeg, ulint iend, ulint in, long double a, long double b);
typedef long double parm[NBR_PARAM]; /* Les 6 parametres reels de fractint */


/*
fovx est la taille de l'image le long de l'axe horizontal de l'image

les fonctions de profil de courbe
prennent en entree
- les numeros des images de départ et d'arrivée
- le numéro d'image en question
- le nombre reel de départ
- le nombre reel d'arrivée
elles sortent le nombre reel pour l'image en question
*/

/* Shared by main + parser */
int simulate;
int interlace;
int dframe_rate; // double the frame rate ?
long int speed;
char video_mode[4];
//int mode;
int resx, resy; // final resolution

char *postfix[2]={"","_"};
char mappath[]="maps\\";
char err[MAX_PATH];

void sortie(const char *s)
{
 puts(s);
 exit(-1);
}


double sqr(double d)
{
 return(d*d);
}

/*$$ FCTS *********************************************************************/
/*
NOM DE LA FONCTION : polar identique à pol dans two_star

OBJET : Calcul de l'angle Ox^OM(x,y)

RESULTAT : Angle en radians, entre 0 et 2*PI

INTERFACES :
*/
/*$$ EFCT *********************************************************************/

double polar(double x,double y)
{
 double a;

 if (x==0)
  if (y>0)
   return(M_PI/2);
  else return(-M_PI/2);
 a=atan(fabs(y/x));
 if ((x>0)&&(y>=0)) return(a);
 if ((x<0)&&(y>=0)) return(M_PI-a);
 if ((x<0)&&(y<=0)) return(M_PI+a);
 if ((x>0)&&(y<=0)) return(2*M_PI-a);

 return 0;
}


int nombre_docurences(char *s, char c)
{
 int i,j;

 i=0;j=0;

 while (s[i]!=0)
 {
  if (s[i]==c)
   j++;
  i++;
 }
 return(j);
}

void strip(char *s)
{
 int i,j,n;

 n=strlen(s);

 i=0;
 while ((s[i]==' ')||(s[i]=='\t'))
  i++;

 for (j=i;j<=n;j++)
 {
  s[j-i]=s[j];      /* Deplacement vers la gauche de i caracteres */
 }
}



long double sinusoide(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 long double x,t;
 t= M_PI * ((long double) in-ibeg)/((long double) iend-ibeg);
 x= a + 0.5*(b-a)*(1.0-cos(t));
 return(x);
}

long double sinusoide2(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 long double x,t;
 t= M_PI * ((long double) in-ibeg)/((long double) iend-ibeg);
 x= a + 0.5*(b-a)*(1.0-cos(M_PI*(1.0+cos(M_PI-t))/2.0));
 return(x);
}

long double sinusoide2bis(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 ulint imed;
 long double cmed;

 imed=(ibeg+iend)/2;
 cmed=(a+b)/2;

 if (in<imed)
  return(sinusoide2(ibeg,imed,in,a,cmed));
 else
  return(sinusoide2(imed,iend,in,cmed,b));
}


long double arcos(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 long double x,t;
 t= ((long double) (2.0*in-ibeg-iend))/((long double) (iend-ibeg));
 x= a + (b-a)/M_PI*(M_PI-acos(t));
 return(x);
}

long double arcosbis(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 ulint imed;
 long double cmed;

 imed=(ibeg+iend)/2;
 cmed=(a+b)/2;

 if (in<imed)
  return(arcos(ibeg,imed,in,a,cmed));
 else
  return(arcos(imed,iend,in,cmed,b));

}


long double arcosquad(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 ulint imed1,imed2,imed3;
 long double cmed1,cmed2,cmed3;

 imed1=ibeg+(iend-ibeg)/4;
 cmed1=a+(b-a)/4;

 if (in<imed1)
  return(arcos(ibeg,imed1,in,a,cmed1));

 imed2=ibeg+(iend-ibeg)/2;
 cmed2=a+(b-a)/2;

 if (in<imed2)
  return(arcos(imed1,imed2,in,cmed1,cmed2));

 imed3=ibeg+3*(iend-ibeg)/4;
 cmed3=a+3*(b-a)/4;

 if (in<imed3)
  return(arcos(imed2,imed3,in,cmed2,cmed3));

 return(arcos(imed3,iend,in,cmed3,b));

}


/* Contraintes : a et b doivent etre du meme signe */
long double expo(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 long double x,t;
 t= M_PI * ((long double) in-ibeg)/((long double) iend-ibeg);
 x = a * exp(0.5*(1.0-cos(t))*log(b/a));
 return(x);
}

/* Contraintes : a et b doivent etre du meme signe */
long double expolin(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 long double x,t;
 t= ((long double) in-ibeg)/((long double) iend-ibeg);
 x = a * exp(t*log(b/a));
 return(x);
}


long double linear(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 long double x;
 long double t;
 t= ((long double) in-ibeg)/((long double) iend-ibeg);
 x = a + (b-a)*t;
 return(x);
}

long double parabole_fall(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 long double x,t;
 t= ((long double) in-ibeg)/((long double) iend-ibeg);
 t=t*t;
 x = a + (b-a)*t;
 return(x);
}

long double parabole_jump(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 long double x,t;
 t= ((long double) in-iend)/((long double) ibeg-iend);
 t=t*t;
 x = b + (a-b)*t;
 return(x);
}

long double slow_start(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 long double x,t;
 t= ((long double) in-ibeg)/((long double) iend-ibeg);
 t = 2.9175729805497845*t;
 t = ((exp(t)+exp(-t))/2-1)-t*t/2-t*t*t*t/24;
 x = a + (b-a)*t;
 return(x);
}

long double quick_start(ulint ibeg, ulint iend, ulint in, long double a, long double b)
{
 long double x,t;
 t= ((long double) in-iend)/((long double) ibeg-iend);
 t = 2.9175729805497845*t;
 t = ((exp(t)+exp(-t))/2-1)-t*t/2-t*t*t*t/24;
 x = b + (a-b)*t;
 return(x);
}


fd fdyn[NBR_DYNAMIC_F]={sinusoide, expo, linear, parabole_fall, parabole_jump,
	    sinusoide2, arcos, sinusoide2bis, arcosbis, arcosquad, expolin, slow_start,
		quick_start};

char *fdynstr[NBR_DYNAMIC_F]={"SINUS","EXPO","LINEAR","PARABOLIC_FALL","PARABOLIC_JUMP","SINUS2","ARCOS","SINUS2BIS","ARCOSBIS","ARCOSQUAD","EXPOLIN","SLOW_START","QUICK_START"};

/* retourne l'entier le + proche */

int clint(long double x)
{
 return((int) floor(x+0.5));
}

#define shift(k,delta) (3*( (255 + k + delta) % 255 ))

/* Attention, la rotation de map se fait entre les couleurs 1 et 255,
   la couleur 0 n'est pas affectée */

void map_rot(ulint ibeg, ulint iend, ulint in, int delta_idx, map mbeg, map m)
{
 int k,delta,shft;

 m[0]=mbeg[0];
 m[1]=mbeg[1];
 m[2]=mbeg[2];

 for (k=0;k<255;k++)
 {
  delta = clint(linear(ibeg,iend,in,0,delta_idx));
  shft = shift(k,delta);
  m[3*k+3]=mbeg[ 3+ shft ];
  m[3*k+4]=mbeg[ 4+ shft ];
  m[3*k+5]=mbeg[ 5+ shft ];
 }
}

void map_interp(ulint ibeg, ulint iend, ulint in, map mbeg, map mend, map m)
{
 int k;

 for (k=0;k<256*3;k++)
  m[k]=(unsigned char) linear(ibeg,iend,in,(long double) mbeg[k],(long double) mend[k]);
}

/* Procedure qui determine si mend est simplement la translatee de mbeg */
/* Retoune le delta_idx */

int delta_map(map mbeg, map mend)
{
 int k,same,delta;

 for (delta=1;delta<255;delta++)
 {
  same=1;
  for (k=0;k<255;k++)
  {
   if (
   (mbeg[3*k+3]!=mend[3+shift(k,delta)])
   ||
   (mbeg[3*k+4]!=mend[4+shift(k,delta)])
   ||
   (mbeg[3*k+5]!=mend[5+shift(k,delta)])
   )
   {same=0;break;}
  }
  if (same==1)
  {
   /* On renvoie le decalage. S'il est <-128, on revoie x+256 */
   /* pour choisir le sens de rotation le plus court */

   if ( (-delta+255) % 255 < delta)
    return((-delta+255) % 255);
   else
    return(-delta);
  }
 }
 return(0); /* Utiliser l'interpolation (marche aussi pour 2 map identiques) */
}



void parametres(ulint ibeg, ulint iend, ulint in, int parn, parm parbeg, parm parend, parm parx, cine_type cpar[6])
{
 int k;

 for (k=0;k<parn;k++)
  parx[k] = fdyn[cpar[k]](ibeg,iend,in,parbeg[k],parend[k]);
}


/*
la fonction de génération de séquence prend en entree
- le nombre d'images de la séquence
- le num‚ro d'image en question
- le point de vue de départ : 3 points
- le point de vue d'arrivée (pas de notion d'orientation)
- le type de profil pour chacun des trois parametres
elle sort le point de vue pour l'image en question
*/

/* Procedure cadre qui … partir d'un centre+fov+angle ==> 3 points */

void cadre(pdv *p)
{
 p->tl.x = p->centre.x - p->fovx*cos(p->angle) + p->fovy*cos(p->angle+M_PI/2);
 p->tl.y = p->centre.y - p->fovx*sin(p->angle) + p->fovy*sin(p->angle+M_PI/2);

 p->bl.x = p->centre.x - p->fovx*cos(p->angle) - p->fovy*cos(p->angle+M_PI/2);
 p->bl.y = p->centre.y - p->fovx*sin(p->angle) - p->fovy*sin(p->angle+M_PI/2);

 p->br.x = p->centre.x + p->fovx*cos(p->angle) - p->fovy*cos(p->angle+M_PI/2);
 p->br.y = p->centre.y + p->fovx*sin(p->angle) - p->fovy*sin(p->angle+M_PI/2);
}



/* Procedure reciproque de cadre = rcadre */

void rcadre (pdv *p)
{
 p->angle = polar( p->br.x - p->bl.x , p->br.y - p->bl.y );
 p->fovx = 0.5 * sqrt(sqr(p->br.x - p->bl.x)+sqr(p->br.y - p->bl.y));
 p->fovy = 0.5 * sqrt(sqr(p->tl.x - p->bl.x)+sqr(p->tl.y - p->bl.y));
 p->centre.x = 0.5 * (p->tl.x + p->br.x);
 p->centre.y = 0.5 * (p->tl.y + p->br.y);
}



/* Procedure that returns the intermediaires views    */
/* Center is shifted downward one line for odd frames */

void cadres(pdv *p1, pdv *p2,
	    ulint ibeg, ulint iend,
	    ulint in,
	    cine_type zoom,
	    cine_type rotate,
	    cine_type trans,
	    pdv *p,
	    long double aspect_ratio,
	    int frame )  /* 0 for even, 1 for odd when interlacing */
{

 p->fovx = fdyn[zoom](ibeg,iend,in,p1->fovx,p2->fovx);
 if (aspect_ratio!=1.0)
  p->fovx = fdyn[zoom](ibeg,iend,in,p1->fovx,p2->fovx)*aspect_ratio;
 p->fovy = fdyn[zoom](ibeg,iend,in,p1->fovy,p2->fovy);
 p->angle = fdyn[rotate](ibeg,iend,in,p1->angle,p2->angle);
 p->centre.x = fdyn[trans](ibeg,iend,in,p1->centre.x,p2->centre.x);
 p->centre.y = fdyn[trans](ibeg,iend,in,p1->centre.y,p2->centre.y);

 /* Shift on one line along vertical view axis for odd frames */
 /* By not in double frame rate mode */

 if ((frame==1)&&(dframe_rate==0))
 {
   p->centre.x = p->centre.x - p->fovy*cos(p->angle+M_PI/2)*2.0/NB_LINES;
   p->centre.y = p->centre.y - p->fovy*sin(p->angle+M_PI/2)*2.0/NB_LINES;
 }

 cadre(p);
}

void readmapfile(char *f,map m)
{
 FILE *mapfile;
 char s[80];
 int k,r,g,b;

 if ((mapfile=fopen(f,"rt"))==NULL)
  sortie("can't read map file");

 for (k=0;k<256;k++)
 {
  fgets(s,80,mapfile);
  sscanf(s,"%d %d %d",&r,&g,&b);
  m[3*k]=r;
  m[3*k+1]=g;
  m[3*k+2]=b;
 }
 fclose(mapfile);
}

void savemapfile(char *f,map m)
{
 FILE *mapfile;
 int k;

 if ((mapfile=fopen(f,"wt"))==NULL)
  sortie("can't create map file");

 for (k=0;k<256;k++)
 {
  fprintf(mapfile,"%d %d %d\n",m[3*k],m[3*k+1],m[3*k+2]);
 }

 fclose(mapfile);
}

void debug_delta_map(void)
{
 map m1,m2;

 readmapfile("map1.map",m1);
 readmapfile("map2.map",m2);
 printf("decalage =%d\n",delta_map(m1,m2));
}


/* Fait generer par fractint, pour chaque entree dans le fichier 'par'
   un fichier map nomme selon le nom de l'entree.
   consequence, les entrees doivent avoir un nom sur 8 caracteres
   et elles doivent etre toutes differentes
   Principe : generer un ficher autokey pour fractint
   */

// If a par in a .par file makes use of something like colors=@mapfile.map
// then mapfile.map should be placed into the vff.exe directory.

WCHAR wcsmappath[] = L"maps\\";

void wsortie(const WCHAR *s)
{
 wprintf(L"%s\n",s);
 exit(-1);
}

DWORD copy_safe(char *src, char *dst, char *serr)
{
	 DWORD dwAttrs;   

	 dwAttrs = GetFileAttributes(dst); 
	 if (dwAttrs!=INVALID_FILE_ATTRIBUTES)
	 {
		// remove write protection of an already present file
		SetFileAttributes(dst, dwAttrs & (~FILE_ATTRIBUTE_READONLY)); 
	 }

	 dwAttrs = GetFileAttributes(src); 
	 if (dwAttrs==INVALID_FILE_ATTRIBUTES)
	 {
		 printf("Invalid file attributes for file %s",src);
		 sortie("Cannot continue");
	 }

	 if (CopyFile(src,dst,FALSE)==0)
	 {
		 DWORD dw;
		 dw=GetLastError();
		 va_list args = NULL;
	     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,dw,0,(LPTSTR) serr,MAX_PATH-1,&args);
		 return dw;
	 }

	 if (dwAttrs & FILE_ATTRIBUTE_READONLY) 
	 { 
		SetFileAttributes(dst, dwAttrs & (~FILE_ATTRIBUTE_READONLY)); 
	 } 

	 return 0;
}

void move_safe(char *src, char *dst)
{
	 DWORD dwAttrs;   
	 char s[MAX_PATH];

	 dwAttrs = GetFileAttributes(dst); 
	 if (dwAttrs!=INVALID_FILE_ATTRIBUTES)
	 {
		// remove write protection of an already present file
		SetFileAttributes(dst, dwAttrs & (~FILE_ATTRIBUTE_READONLY)); 
	 }

	 sprintf(s,"move /Y \"%s\" \"%s\"",src,dst);
	 puts(s);
	 fflush(stdout);
	 system(s); 
}

void copy_formula(char *c, char *basepath, char *parset, char *spar, char *formulafile)
{
	 //copy the formula file in the current directory
	 char src[MAX_PATH];
	 char serr[MAX_PATH];
	 formulafile[0] = 0x00;
	 sscanf(c+12,"%s",formulafile);
	 strcpy(src,basepath);
	 strcat(src,formulafile);

	 DWORD dw = copy_safe(src,formulafile,serr);

	 if (dw!=0)
	 {
		 if (dw==ERROR_FILE_NOT_FOUND)
		 {
			printf("Couldn't find formula file '%s' referenced by parset '%s' in parfile '%s'\n",formulafile,parset,spar);
			sortie("Place it in the same directory as the .stb/.par file.");
		 }
		 else
		 {
			printf("Could not copy formula file '%s' referenced by parset '%s' in parfile '%s'\n",formulafile,parset,spar);
			printf("for the reason : %s",serr);
			sortie("");
		 }
	 }
}


/*
void map_file_generator_wchar(WCHAR *parfilename)
{
 FILE *autokey,*par;
 char s[MAX_PATH];
 WCHAR spar[MAX_PATH];
 char parrec[13];
// char parfiledir[256];
 WCHAR parfiledir[256];
 WCHAR *parfile;
 WCHAR theparfile[MAX_PATH];

 vector<string> parrecs;

 SECURITY_ATTRIBUTES sa;

 wsprintf(spar,L"%s",parfilename);

 if ((par=_wfopen(spar,L"rt"))==NULL)
  sortie("can't open par file for autokey generation");

 fflush(stdout);

 //LPCWSTR
 GetFullPathName(parfilename,sizeof(parfiledir),parfiledir,&parfile);
 // Create Sub directory ./maps if it does not exit

 wcscpy(theparfile,parfile);

 *parfile = 0x00;
 wcscat(parfiledir,wcsmappath);

 sa.nLength = sizeof(sa);
 sa.bInheritHandle = false;
 sa.lpSecurityDescriptor = NULL;

 if (CreateDirectory(parfiledir,&sa)==0)
 {
	 if (ERROR_ALREADY_EXISTS!=GetLastError())
		 sortie("Can't create sub directory for the maps");
 }

 // Obliged to place a copy of the .par file in the current api directory
 // for fractint to be able to get it

 if(CopyFile(parfilename,L"tmp.par",FALSE)==0)
	 sortie("Can't copy the parfile to a tmp.par file in the current vff dir");

 if ((autokey=fopen("vff.key","wt"))==NULL)
  sortie("can't create autokey text file");

 // Select Video Mode 
 fprintf(autokey,"WAIT 1.0\nSF6\n");

 int i,j;
 string parrecstring;
 char *c;
 WCHAR mapfile[MAX_PATH];
 WCHAR mapfilefullpath[MAX_PATH];
 i=0;

 while (fgets(s,sizeof(s),par)!=NULL)
 {
  strip(s);
  if (strchr(s,'{')!=NULL)
  {
   sscanf(s,"%8[0-9A-Z_a-z]",parrec);
   fprintf(autokey,"WAIT 0.1\n\"@\"\nWAIT 0.1\nF6\nWAIT 0.1\n\"%s\"\n","tmp.par");
   fprintf(autokey,"WAIT 0.1\nENTER\n\"%s\"\n",parrec);
   fprintf(autokey,"WAIT 0.1\nENTER\nWAIT 0.1\n\"cs\"\n");
   fprintf(autokey,"WAIT 0.1\n\"%s\"\nENTER\nWAIT 1.4\n",parrec);
   fprintf(autokey,"ESC\n");
   parrecstring = parrec;
   parrecs.push_back(parrecstring);
   i++;
  }
  if ((c=strstr(s,"colors=@"))!=NULL)
  {
	 // Obliged to place a copy of the referenced .map files in the current api directory
	 // for fractint to be able to get it
	  if (sscanf(c+8,"%s",mapfile)==1)
	  {
		  swprintf(mapfilefullpath,sizeof(mapfilefullpath),L"%s%s",parfiledir,mapfile);
		  if (CopyFile(mapfilefullpath,mapfile,FALSE)==0)
		  {
			  wstring str;
			  str+=L"The map file '";
			  str+=mapfile;
			  str+=L"' that is referenced by entry '";
			  for (i=0;i<strlen(parrec);i++)
			   str.push_back((WCHAR) parrec[i]);
			  str+=L"' in .par file '" ;
			  str+=parfilename;
			  str+=L"' is missing from the directory '";
			  str+= parfiledir;
//			  sprintf(err,"The map file '%s' that is referenced by entry '%s' in .par file '%s' is missing from the directory '%s'",mapfile,parrec,parfilename,parfiledir);
			  wsortie(str.c_str());
		  }
	  }
  }
 }
 fprintf(autokey,"ESC\nESC\n\"y\n");

 fclose(autokey);
 fclose(par);

 STARTUPINFO sinfo;
 sinfo.cb = sizeof(sinfo);
 memset(&sinfo,0,sizeof(sinfo));
 sinfo.dwFlags = STARTF_RUNFULLSCREEN;


 PROCESS_INFORMATION  pinf;
 

 puts("fractint autokey=play autokeyname=vff.key");
 fflush(stdout);
 if (CreateProcess(NULL,L"fractint\\fractint.exe autokey=play autokeyname=vff.key",NULL,NULL,true,0,NULL,NULL,&sinfo,&pinf))
 {
	 puts("success");
	 fflush(stdout);
   // Wait until child process exits.
    WaitForSingleObject( pinf.hProcess, INFINITE );

    // Close process and thread handles. 
    CloseHandle( pinf.hProcess );
    CloseHandle( pinf.hThread );

 }
// system("fracwtint\\fractint autokey=play autokeyname=vff.key");
 puts("done");
 fflush(stdout);
 
 // Move only all new map files in a subdirectory called maps below the parfile directory
 
 for (j=0;j<i;j++)
 {
	 sprintf(s,"move /Y %s.map \"%s%s.map\"",parrecs[j].c_str(),parfiledir,parrecs[j].c_str());
	 puts(s);
	 fflush(stdout);
	 system(s); 
 }
}

*/

void map_file_generator(char *parfilename)
{
 FILE *autokey,*par;
 char s[MAX_PATH];
 char spar[MAX_PATH];
 char parrec[13];
// char parfiledir[256];
 char parfiledir[MAX_PATH];
 char *parfile;
 char theparfile[MAX_PATH];
 char mapfiledir[MAX_PATH];
 char serr[MAX_PATH];
 char formulafile[MAX_PATH];

 vector<string> parrecs;
 vector<string> formulas;
 vector<string> workmaps;

 SECURITY_ATTRIBUTES sa;

 sprintf(spar,"%s",parfilename);

 if ((par=fopen(spar,"rt"))==NULL)
  sortie("can't open par file for autokey generation");

 fflush(stdout);

 GetFullPathName(parfilename,sizeof(parfiledir),parfiledir,&parfile);
 // Create Sub directory ./maps if it does not exit

 strcpy(theparfile,parfile);

 *parfile = 0x00;

 strcpy(mapfiledir,parfiledir);
 strcat(mapfiledir,mappath);

 sa.nLength = sizeof(sa);
 sa.bInheritHandle = false;
 sa.lpSecurityDescriptor = NULL;

 if (CreateDirectory(mapfiledir,&sa)==0)
 {
	 if (ERROR_ALREADY_EXISTS!=GetLastError())
		 sortie("Can't create sub directory for the maps");
 }

 // Obliged to place a copy of the .par file in the current api directory
 // for fractint to be able to get it

 DWORD dw = copy_safe(parfilename,"tmp.par",serr);
 
 if (dw!=0)
	 sortie("Can't copy the parfile to a tmp.par file in the current vff dir");

 if ((autokey=fopen("vff.key","wt"))==NULL)
  sortie("can't create autokey text file");

 /* Select Video Mode */
 fprintf(autokey,"WAIT 1.0\nSF6\n");

 int i,j;
 string parrecstring;
 string formulastring;
 string workmapstring;
 char *c;
 char mapfile[MAX_PATH];
 char mapfilefullpath[MAX_PATH];
 i=0;

 while (fgets(s,sizeof(s),par)!=NULL)
 {
  strip(s);
  if (strchr(s,'{')!=NULL)
  {
   sscanf(s,"%8[0-9A-Z_a-z]",parrec);
   fprintf(autokey,"WAIT 0.1\n\"@\"\nWAIT 0.1\nF6\nWAIT 0.1\n\"%s\"\n","tmp.par");
   fprintf(autokey,"WAIT 0.1\nENTER\n\"%s\"\n",parrec);
   fprintf(autokey,"WAIT 0.1\nENTER\nWAIT 0.1\n\"cs\"\n");
   fprintf(autokey,"WAIT 0.1\n\"%s\"\nENTER\nWAIT 1.4\n",parrec);
   fprintf(autokey,"ESC\n");
   parrecstring = parrec;
   parrecs.push_back(parrecstring);
   i++;
  }

  if ((c=strstr(s,"formulafile="))!=NULL)
  {
	 copy_formula(c,parfiledir,parrec,parfilename,formulafile);
	 formulastring = formulafile;
	 formulas.push_back(formulastring);
  }


  if ((c=strstr(s,"colors=@"))!=NULL)
  {
	 // Obliged to place a copy of the referenced .map files in the current api directory
	 // for fractint to be able to get it
	  if (sscanf(c+8,"%s",mapfile)==1)
	  {
		  sprintf(mapfilefullpath,"%s%s",parfiledir,mapfile);
		  if (copy_safe(mapfilefullpath,mapfile,serr)!=0)
		  {
			  string str;
			  str+="The map file '";
			  str+=mapfile;
			  str+="' that is referenced by entry '";
			  str+=parrec;
			  str+="' in .par file '" ;
			  str+=parfilename;
			  str+="' is missing from the directory '";
			  str+= parfiledir;
//			  sprintf(err,"The map file '%s' that is referenced by entry '%s' in .par file '%s' is missing from the directory '%s'",mapfile,parrec,parfilename,parfiledir);
			  sortie(str.c_str());
		  }
		  workmapstring = mapfile;
		  workmaps.push_back(workmapstring);
	  }
  }
 }
 fprintf(autokey,"ESC\nESC\n\"y\n");

 fclose(autokey);
 fclose(par);

 STARTUPINFO sinfo;
 sinfo.cb = sizeof(sinfo);
 memset(&sinfo,0,sizeof(sinfo));
 sinfo.dwFlags = STARTF_RUNFULLSCREEN;


 PROCESS_INFORMATION  pinf;
 

 puts("fractint autokey=play autokeyname=vff.key");
 fflush(stdout);
 if (CreateProcess(NULL,"fractint\\fractint.exe autokey=play autokeyname=vff.key",NULL,NULL,true,0,NULL,NULL,&sinfo,&pinf))
 {
	 puts("success");
	 fflush(stdout);
   // Wait until child process exits.
    WaitForSingleObject( pinf.hProcess, INFINITE );

    // Close process and thread handles. 
    CloseHandle( pinf.hProcess );
    CloseHandle( pinf.hThread );

 }
// system("fractint\\fractint autokey=play autokeyname=vff.key");
 puts("done");
 fflush(stdout);
 
 // Move only all new map files in a subdirectory called maps below the parfile directory
 char srcf[MAX_PATH];
 char dstf[MAX_PATH];


 for (j=0;j<i;j++)
 {
	 sprintf(srcf,"%s.map",parrecs[j].c_str());
	 sprintf(dstf,"%s%s.map",mapfiledir,parrecs[j].c_str());
	 move_safe(srcf,dstf);
 }


 size_t k;
 
 for (k=0;k<workmaps.size();k++)
	 DeleteFile(workmaps[k].c_str());

  for (k=0;k<formulas.size();k++)
	 DeleteFile(formulas[k].c_str());

 DeleteFile("tmp.par");
 DeleteFile("vff.key");
}

/* Parser */
/* The number of parameters is not passed to the parser */
/* Because there can be more parameters than what appears in the storyboard */

void parser(char *basepath,char *parfilename,char *parsetbeg,
		ulint ibeg,ulint iend,
	    ulint icalcbeg, ulint icalcend,
	    cine_type zoom,
	    cine_type rotate,
	    int nrot,
	    cine_type trans,
	    cine_type cpar[NBR_PARAM],
	    long double aspect_ratio,
		int withoutend
)
{
 FILE *batch,*refpar,*par;
 char s[MAX_PATH];
 char smap[MAX_PATH];
 char spar[MAX_PATH];
 char parset[13];
 char img_name[13];
 char answer[13];
 map mbeg,mend,m;
 pdv pbeg,pend,p;
 parm parbeg;
 parm parend;
 parm parx;
 ulint in;
 int delta_maps,parn,k,frame;
 long double delta_angle;

 sprintf(spar,"%s%s",basepath,parfilename);

 if ((par=fopen(spar,"rt"))==NULL)
  sortie("can't open par file pointed to by the storyboard");

 if ((refpar=fopen("ref.par","wt"))==NULL)
  sortie("can't create 'reference.par' text file");


 /* Locate the entry point */

 parset[0]=0;
 parn=0;

 while (fgets(s,sizeof(s),par)!=NULL)
 {
  _strlwr(s);
  strip(s);
  if (strchr(s,'{')!=NULL)
  {
   sscanf(s,"%8[0-9A-Z_a-z]",parset);
   if (strstr(parset,parsetbeg)!=NULL)
    break;
  }
 }

 if (parset[0]==0)
  sortie("can't find set in parfile");

    sprintf(smap,"%s%s%s.map",basepath,mappath,parset);
    readmapfile(smap,mbeg);
    while (fgets(s,sizeof(s),par)!=NULL)
    {
     _strlwr(s);
     strip(s);

     /* 'colors' must be the last info */

     if (strstr(s,"colors")!=NULL)  break;

     if (strstr(s,"params")!=NULL)
     {
       parn=nombre_docurences(s,'/')+1;
       if (parn>6)
        sortie("Found more than six parameters,\n this is more than what fractint can manage !");
       sscanf(s,"params=%Le/%Le/%Le/%Le/%Le/%Le",&parbeg[0],
       &parbeg[1],&parbeg[2],&parbeg[3],&parbeg[4],&parbeg[5]);

     }
     else if (strstr(s,"corners")!=NULL)
     {
      if (nombre_docurences(s,'/')==5)
       sscanf(s,"corners=%Le/%Le/%Le/%Le/%Le/%Le",
       &pbeg.tl.x,&pbeg.br.x,&pbeg.br.y,&pbeg.tl.y,&pbeg.bl.x,&pbeg.bl.y);
      else
      {
       sscanf(s,"corners=%Le/%Le/%Le/%Le",
       &pbeg.tl.x,&pbeg.br.x,&pbeg.br.y,&pbeg.tl.y);
       pbeg.bl.x=pbeg.tl.x;
       pbeg.bl.y=pbeg.br.y;
      }
      rcadre(&pbeg);
     }
     else
	 {
		 char *c;
		 if ((c=strstr(s,"formulafile="))!=NULL)
		 {
			 char formulafile[MAX_PATH];
			 copy_formula(c,basepath,parset,spar,formulafile);
		 }
		 fputs(s,refpar);
	 }


    }


 /* Read the second set */

 parset[0]=0;

 while (fgets(s,sizeof(s),par)!=NULL)
 {
  _strlwr(s);
  strip(s);

  if (strchr(s,'{')!=NULL)
  {
   sscanf(s,"%8[0-9A-Z_a-z]",parset);
   break;
  }
 }

 if (parset[0]==0)
  sortie("can't find second set in parfile");


    sprintf(smap,"%s%s%s.map",basepath,mappath,parset);
    readmapfile(smap,mend);

    while (fgets(s,sizeof(s),par)!=NULL)
    {
     _strlwr(s);
     strip(s);

     if (strstr(s,"params")!=NULL)
     {
       sscanf(s,"params=%Le/%Le/%Le/%Le/%Le/%Le",&parend[0],
       &parend[1],&parend[2],&parend[3],&parend[4],&parend[5]);
     }

     else

     if (strstr(s,"corners")!=NULL)
     {
      if (nombre_docurences(s,'/')==5)
       sscanf(s,"corners=%Le/%Le/%Le/%Le/%Le/%Le",
       &pend.tl.x,&pend.br.x,&pend.br.y,&pend.tl.y,&pend.bl.x,&pend.bl.y);
      else
      {
       sscanf(s,"corners=%Le/%Le/%Le/%Le",
       &pend.tl.x,&pend.br.x,&pend.br.y,&pend.tl.y);
       pend.bl.x=pend.tl.x;
       pend.bl.y=pend.br.y;
      }
      rcadre(&pend);
     }

     else
      if (strstr(s,"}")!=NULL)
       break;

    }




  fclose(par);
  fclose(refpar);

/**********************************************************************/

  delta_maps = delta_map(mbeg,mend);

  /* Minimize angle distance to avoid making more that one turn */
  /* for no reason */

  delta_angle = fabs(pend.angle-pbeg.angle);
  if (fabs(pend.angle+2*M_PI-pbeg.angle)<delta_angle)
   pend.angle += 2*M_PI;
  if (fabs(pend.angle-2*M_PI-pbeg.angle)<delta_angle)
   pend.angle -= 2*M_PI;


  pend.angle += 2.0*M_PI*nrot; /* Add some turns if asked to */

  refpar=fopen("ref.par","rt");

/**********************************************************************/

 for (in=icalcbeg;in<=icalcend;in+=interlace+1)
 {
  for (frame=0;frame<=interlace;frame++)
  {
  sprintf(img_name,"im%05d.gif",in+frame);

/*
   We always must have that
   the first video field is generated with the start parameters when icalcbeg=ibeg
   We must have in interlace mode that:
   the last video field is generated with the end parameters when icalcend=iend
   icalcend=iend
   iend+interlace-withoutend = iend+1-0,in+frame=icalcend+frame=iend+1=iend+1
   the last video field is generated with the 1 field time before the end parameters when icalcend=iend-2
   iend+interlace-withoutend = iend+1-1=iend,  in+frame=icalcend+frame=iend-2+1=iend-1
   ==> hence the term iend+interlace
*/

  if (delta_maps==0)
   map_interp(ibeg,iend+interlace-withoutend,in+frame,mbeg,mend,m);
  else
   map_rot(ibeg,iend+interlace-withoutend,in+frame,delta_maps,mbeg,m);

  savemapfile("vff.map",m);

  cadres(&pbeg,&pend,ibeg,iend+interlace-withoutend,in+frame,zoom,rotate,trans,&p,aspect_ratio,frame);

  parametres(ibeg,iend+interlace-withoutend,in+frame,parn,parbeg,parend,parx,cpar);

  /*******************/
  /* Create Par File */
  /*******************/

  if ((batch=fopen("vff.par","wt"))==NULL)
   sortie("can create 'par' text file");

   rewind(refpar);

   fprintf(batch,"vff { ; VFF One Image Batch for Fractint\n");

   while (fgets(s,sizeof(s),refpar)!=NULL)
    fputs(s,batch);

   fprintf(batch,"  passes=1 sound=off batch=yes video=");
   fprintf(batch,video_mode);
   fprintf(batch," colors=@vff.map\n");
   fprintf(batch,"  savename=%s\n",img_name);

   if (parn>0)
   {
    fprintf(batch,"  params=%.18Le",parx[0]);
    for (k=1;k<parn;k++)
    {
     fprintf(batch,"/%.18Le",parx[k]);
    }
    fprintf(batch,"\n");
   }

   fprintf(batch,"  corners=%.18Le/%.18Le/%.18Le/%.18Le/%.18Le/%.18Le\n",p.tl.x,p.br.x,p.br.y,p.tl.y,p.bl.x,p.bl.y);
   fprintf(batch,"}\n");

   fclose(batch);

  /***********************/
  /* End Create Par File */
  /***********************/


  if (simulate==0)
  {
   printf("Calculating image #%05d\n",in);
   puts("fractint\\fractint @vff.par/vff");
  }
  else
   printf(".");

 
  if (GetKeyState(VK_RSHIFT)& 0xFF00) /* test shift droit */
  {
   printf("Are you sure you want to stop the calculation ?\n");
   printf("(0)=No. (1)=Yes -->");
   gets(answer);
   if (atoi(answer)==1)
    sortie("Stop on demand");
  }

  /****************/

  if (simulate==0)
  {
   system("fractint\\fractint @vff.par/vff");
   puts("depress <SHIFT RIGHT> to interrupt");
   puts("depress <ALT>+<ENTER> at any time to toggle full screen");
  }
  } /* End Frames Even/Odd loop */
 }  /* End Parser Image Loop */


/**********************************************************************/

 fclose(refpar);

 if (simulate==1)
  printf("\n");
}

/*
bool extract_file(char *c, char *s)
{
	char *c1,*c2;

	if (strchr(c,'"')!=c)
		return false;
	c1 = c+1;
	c2 = strchr(c1,'"');
	if (c2==NULL)
		return false;
	*c2 = 0x00;
	strcpy(s,c1);

	return true;
}
*/

// Syntaxe en ligne de commande
// vff parfile="file.par"
// vff stb="file" simu=0|1 display_aspect=1|1.333 raster_aspect=1|1.333 mode=0|1|2 interlace=0|1 dframe_rate=0|1 antialiasing=1 nblines=x

bool parse_command_line(int argc, char**argv, int *genmaps, char *parfile, char *storyboard, int *simu, long double *display_aspect, long double *raster_aspect, int *mode, int *interlace, int *dframe_rate, int *antialiasing, int *nblines)
{
	char *c;
//	int genmaps;

#define NB_ARGS 9
	char *fields[NB_ARGS]={"stb=","simu=","display_aspect=","raster_aspect=","mode=","interlace=","dframe_rate=","antialiasing=","nblines="};
	char values[NB_ARGS][255];
	int i;

	for (i=0;i<NB_ARGS;i++)
		values[i][0]=0x00;

	if (argc==2)
	{
		if (c=strstr(argv[1],"parfile="))
		{
			c=c+strlen("parfile=");
			if (*c==0x00)
				return false;
			strcpy(parfile,c);
			*genmaps = 1;
			return true;
		}
		else
			return false;
	}
	else if (argc==NB_ARGS+1)
	{
		for (i=0;i<NB_ARGS;i++)
		{
			if (c=strstr(argv[i+1],fields[i]))
			{
				c+=strlen(fields[i]);
				if (*c==0x00)
					return false;
				strcpy(&values[i][0],c);
			}
			else
				return false;
		}

		strcpy(storyboard,values[0]);

		if (sscanf(values[1],"%d",simu)==0)
			return false;
		if (sscanf(values[2],"%Lf",display_aspect)==0)
			return false;
		if (sscanf(values[3],"%Lf",raster_aspect)==0)
			return false;
		if (sscanf(values[4],"%d",mode)==0)
			return false;
		if (sscanf(values[5],"%d",interlace)==0)
			return false;
		if (sscanf(values[6],"%d",dframe_rate)==0)
			return false;
		if (sscanf(values[7],"%d",antialiasing)==0)
			return false;
		if (sscanf(values[8],"%d",nblines)==0)
			return false;

		*genmaps = 0;
		return true;
	}
	else 
		return false;

	return true;
}



bool interactive_mode(int *genmaps, char *parfilename, char *stbfilename, int *simulate, long double *aspect_ratio, long double *raster_aspect_ratio, int *mode, int *interlace, int *dframe_rate, int *antialiasing, int *nblines)
{
 char answer[MAX_PATH];
 int i;
 FILE *f;

 /*storyboard_file_name*/
 puts("Do you want to generate the map files for a parfile ?");
 printf("(1)=Yes. (0)=No -->");
 gets(answer);
 *genmaps = atoi(answer);

/* debug_delta_map(); */
 if (*genmaps==1)
 {
  simulate=0;
  printf("type .par filename=>");
  gets(answer);
  strcpy(parfilename,answer);
  return true;
 }

 do {
	 printf("\nType storyboard (.stb) filename=>");
	 gets(answer);
	 strcpy(stbfilename, answer);

	 // Check now to avoid useless work
	 f=fopen(stbfilename,"rt");

	 if (f==NULL)
		 puts("Can't open storyboard file for film generation. ctrl+c to exit.");
 }
 while(f==NULL);

 fclose(f);

 puts("\nDo you want to simulate ?");
 printf("(1)=Yes. (0)=No -->");
 gets(answer);

 if (atoi(answer)==0)
  *simulate=0;
 else
  *simulate=1;


 do {
	 puts("\nGive many decimals to avoid rounding errors");
	 printf("Final Display Aspect Ratio  : (0) 4/3. (1) 16/9. (other) custom.  -->");
	 gets(answer);
	 i = sscanf(answer,"%Lf",aspect_ratio);
	 if (*aspect_ratio==0)
		 *aspect_ratio = 1.0;
	 else if (*aspect_ratio==1)
		 *aspect_ratio = 4.0/3.0;
	 else
		 *aspect_ratio/= 4.0/3.0;
 }
 while(i==0);

 do{
	 puts("\nGive many decimals to avoid rounding errors");
	 printf("Raster Aspect Ratio  : (0) 4/3. (1) 16/9. (other) custom.  -->");
	 gets(answer);
	 i = sscanf(answer,"%Lf",raster_aspect_ratio);
	 if (*raster_aspect_ratio==0)
		 *raster_aspect_ratio = 1.0;
	 else if (*raster_aspect_ratio==1)
		 *raster_aspect_ratio = 4.0/3.0;
	 else
		 *raster_aspect_ratio/= 4.0/3.0;
 }
 while(i==0);

  printf("\n(0) Fast Preview. (2) All Images -->");
  gets(answer);
  *mode=atoi(answer);

  if (*mode==0)
	  *nblines = 60;
  else
  {
	puts("\nPlease give the number of lines in the final video :");
	puts("Type 576 for PAL, 480 for NTSC, 720 or 1080 for HD.");
	printf("-->");
	gets(answer);
	*nblines = atoi(answer);
  }

  if (*mode==2)
  {
	puts("\nAntialising if selected will double or quadruple the number of pixels computed.");
	puts("Post processing will be necessary for filtering.");
	printf("(1) Yes Anti Aliasing 2x.  (0) No Anti Aliasing. -->");
	gets(answer);
	*antialiasing = atoi(answer);

    puts("\nDouble frame rate with no interlacing ?");
    printf("(1)=Yes. (0)=No -->");
    gets(answer);

    if (atoi(answer)==0)
		*dframe_rate = 0;
	else
	{
		*interlace = 1;
		*dframe_rate = 1;
	}

	if (*dframe_rate == 0)
	{
		puts("\nInterlacing will double the amount of pictures calculated");
		puts("Each image will have half the final vertical resolution");
		puts("Every other image will be shifted by 1/nb_lines vertically in the complex plane");
		puts("Post processing will be necessary for interlacing each pair of images");
		puts("Calculate for Interlacing ?");
		printf("(1)=Yes. (0)=No -->");
		gets(answer);

		if (atoi(answer)==0)
		 *interlace=0;
		else
		 *interlace=1;
	}
  }

 return true;
}

void build_fractint_cfg(int resx, int resy)
{
	FILE *fin,*ftmp;
	char s[MAX_PATH];
	char cfg[]="fractint.cfg";
	char bak[]="fractint.bak";
	char tmp[]="fractint.tmp";
	bool found = false;
	char serr[MAX_PATH];


	fin = fopen("fractint.cfg","rt");
	if (fin==NULL)
		sortie("Can't find fractint.cfg. It should be located in the vff directory.");

	CopyFile( cfg, bak, TRUE); // Backup once and for all the fractint.cfg file

	ftmp = fopen("fractint.tmp","wt");
	if (ftmp==NULL)
		sortie("Can't create fractint.tmp temporary file. Verify write protection of this file");

	while (fgets(s,sizeof(s),fin))
	{
		if ( s == strstr(s,"AF6"))
		{
			fprintf(ftmp,"AF6 ,Disk/RAM 'Video'           ,   3,   0,   0,   0,  11,%d,%d,256,VFF Fractal\n",resx,resy);
			found = true;
		}
		else
			fprintf(ftmp,s);
	}

	if (!found)
			fprintf(ftmp,"AF6 ,Disk/RAM 'Video'           ,   3,   0,   0,   0,  11,%d,%d,256,VFF Fractal\n",resx,resy);

	fclose(fin);
	fclose(ftmp);

	if (copy_safe(tmp,cfg,serr)!=0)
		sortie("Failed to overwrite the Fractint.cfg file. Verify write protection of this file");
}

void main(int argc, char **argv)
{

 cine_type cpar0[NBR_PARAM]={LINEAR,LINEAR,LINEAR,LINEAR,LINEAR,LINEAR};
 //cine_type cpar_null[6]={0,0,0,0,0,0};
 char parfilename[MAX_PATH];
 char stbfilename[MAX_PATH];

 char parsetname[9];
 char sibeg[7],siend[7],sstep[7],snrot[7];
 char sicalcbeg[7];
 char sicalcend[7],scp[NBR_PARAM+3][20];
 int parn,commentary;
 ulint ibeg,iend,icalcbeg,icalcend,step;
 long nrot;
 int i,k;
 cine_type cp[3+NBR_PARAM];
 cine_type cpp[NBR_PARAM];
 char s[257];
 FILE *storyboard;
 char c;
 long double aspect_ratio, raster_aspect_ratio;
 int withoutend;
 int mode;
 int genmaps;
 int antialiasing;

/* printf("%.18Le\n",(long double) 1.0/6.0); */

 strcpy(video_mode,"AF8");
 speed=1; /* By default, normal speed */
 interlace=0;
 dframe_rate=0;
/*
 system("dir");
 puts("XXXX");fprintf(stderr,"ERR");fprintf(stdout,"YYY");
 for (i=0;i<argc;i++)
 {
	 puts("--");
	 printf("%d -- %s\n",i,argv[i]);
 }
 puts("XXXX");
 fflush(stdout);
*/
 if (!parse_command_line(argc, argv, &genmaps, parfilename, stbfilename, &simulate, &aspect_ratio, &raster_aspect_ratio, &mode, &interlace, &dframe_rate, &antialiasing, &NB_LINES))
 {
//   puts("Pb"); exit(-1);
   printf("\nVFF v1.3\n\n");
   interactive_mode(                 &genmaps, parfilename, stbfilename, &simulate, &aspect_ratio, &raster_aspect_ratio, &mode, &interlace, &dframe_rate, &antialiasing, &NB_LINES);
 }

 if (genmaps)
 {
   puts("Genmaps"); fflush(stdout);
   map_file_generator(parfilename);
   puts("Kool !!!");
   exit(0);
 }

 if ((storyboard=fopen(stbfilename,"rt"))==NULL)
	  sortie("can't open storyboard file for film generation");

 if (dframe_rate==1)
	interlace = 1; // no interlacing occurs in that case actually, but however still need to set interlace=1

 if ((interlace==1)&&(dframe_rate == 0))
 {
	resy = NB_LINES/2;
 }
 else
 {
	 if (antialiasing)
		 resy = NB_LINES * 2;
	 else
		 resy = NB_LINES;
 }

 /*
 if (raster_aspect_ratio == -1)
	 resx = (int) floor(1.33333333333*NB_LINES+0.5f);
 else if (raster_aspect_ratio == -2)
	 resx = (int) floor(1.77777777777*NB_LINES+0.5f);
 else
*/
 resx = (int) floor(1.33333333*raster_aspect_ratio*NB_LINES+0.5f);

 if (antialiasing)
	 resx = resx * 2;

  if (mode==0)
  {
   speed=4;
   interlace=0; /* Force to non interlaced */
   dframe_rate=0;
  }

  strcpy(video_mode,"AF6"); /* 16/9 : for example : 1920 x 1080 pixels */

  build_fractint_cfg(resx,resy);


  char basepath[MAX_PATH];
//  char thestbfile[MAX_PATH];
  char *stbfile;

  GetFullPathName(stbfilename,sizeof(basepath),basepath,&stbfile);

//  strcpy(thestbfile,stbfile);
  *stbfile = 0x00;


  // Here we go now. Main Loop

 ibeg = 0; /* By default, first picture number = 0 */

 commentary=0;

 while (fgets(s,256,storyboard)!=NULL)
 {
  _strlwr(s);
  strip(s);
  if (strlen(s)==0)
   continue;

  if (commentary==1)
  {
   if (s[0]=='}')
    commentary=0;
   continue;
  }

  if (s[0]=='{')
  {
   commentary=1;
   continue;
  }

  if (s[0]!=';')
  {
   nrot=0;

   parn=sscanf(s,"%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
   parfilename,parsetname,
   sibeg,siend,sicalcbeg,sicalcend,
   scp[0],scp[1],scp[2],
   scp[3],scp[4],scp[5],scp[6],scp[7],scp[8]) - 9;

   if (parn+9<3)   /* CR at End of file ? */
    continue;

   c=sibeg[0];

   if ((c=='+')||(c=='*'))
   {
    parn=sscanf(s,"%s %s %s %s %s %s %s %s %s %s %s %s",
    parfilename,parsetname,sstep,scp[0],scp[1],scp[2],scp[3],scp[4],scp[5],scp[6],scp[7],scp[8])-6;
    if ((scp[2][0]=='+') || (scp[2][0]=='-'))
    {
     /* One param was in fact a nb of rotations indication */
     parn=sscanf(s,"%s %s %s %s %s %s %s %s %s %s %s %s %s",
     parfilename,parsetname,sstep,scp[0],scp[1],snrot,scp[2],scp[3],scp[4],scp[5],scp[6],scp[7],scp[8])-7;

      nrot=atol(snrot);
    }

    sstep[0]=' '; /* Pour permettre la convertion en entier long */

    step=atol(sstep);
    iend=ibeg+step;
    icalcbeg=ibeg;

/* "+25" fera calculer 25 images de telle sorte que la derniŠre soit … une image du parametre d'arriv‚e */
/* "*25" fera calculer 26 images de telle sorte que la derniŠre ait le parametre d'arriv‚e */

    if (c=='+')
	{
     icalcend=iend-1;
	 withoutend=1;
	}
    else   /* c=='*'*/
	{
     icalcend=iend;
	 withoutend=0;
	}
   }
   else
   {
    if ((scp[2][0]=='+') || (scp[2][0]=='-'))
    {
     /* One param was in fact a nb of rotations indication */
     parn=sscanf(s,"%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
     parfilename,parsetname,
     sibeg,siend,sicalcbeg,sicalcend,
     scp[0],scp[1],snrot,scp[2],
     scp[3],scp[4],scp[5],scp[6],scp[7],scp[8])-10;
     nrot=atol(snrot);
    }

    ibeg=atol(sibeg);
    iend=atol(siend);
    icalcbeg=atol(sicalcbeg);
    icalcend=atol(sicalcend);
	withoutend=1; /* See that again later . Why that ? */
   }

   for (k=0;k<3+parn;k++)
   {
    _strupr(scp[k]);

    for (i=0;i<NBR_DYNAMIC_F;i++)
    {
     if (strcmp(scp[k],fdynstr[i])==0)
     {
      cp[k]=(cine_type) i;
      break;
     }
    }
    if (i==NBR_DYNAMIC_F)
     sortie("Problem in storyboard, Dynamic Function selection incorrect");
   }

  for (k=3+parn;k<3+NBR_PARAM;k++)
   cp[k]=LINEAR; /* Normalement inutile, au cas ou */
   /* This way, by default, a parameter is : linear */

  for (k=3;k<3+NBR_PARAM;k++)
   cpp[k-3]=cp[k];

  if (speed==1)
   printf("%s - %s - %lu - %lu - %lu - %lu -%s-%s-nrot:%ld-%s-%s-%s-%s-%s-%s-%s\n",
   parfilename,parsetname,ibeg,iend,icalcbeg,icalcend,
   fdynstr[cp[0]],fdynstr[cp[1]],nrot,fdynstr[cp[2]],
   fdynstr[cpp[0]],fdynstr[cpp[1]],fdynstr[cpp[2]],
   fdynstr[cpp[3]],fdynstr[cpp[4]],fdynstr[cpp[5]]);
  else
   printf("%s - %s - %lu - %lu - %lu - %lu -%s-%s-nrot:%ld-%s-%s-%s-%s-%s-%s-%s\n",
   parfilename,parsetname,ibeg/4,iend/4,icalcbeg/4,icalcend/4,
   fdynstr[cp[0]],fdynstr[cp[1]],nrot,fdynstr[cp[2]],
   fdynstr[cpp[0]],fdynstr[cpp[1]],fdynstr[cpp[2]],
   fdynstr[cpp[3]],fdynstr[cpp[4]],fdynstr[cpp[5]]);

   if (!interlace)
    withoutend=0;

/* if (simulate==0) */
   if (speed==1)
   {
    if (interlace==1)
     parser(basepath,parfilename,parsetname,2*ibeg,2*iend,2*icalcbeg,2*icalcend,
      cp[0],cp[1],nrot,cp[2],cpp,aspect_ratio,withoutend);
    else
     parser(basepath,parfilename,parsetname,ibeg,iend,icalcbeg,icalcend,
      cp[0],cp[1],nrot,cp[2],cpp,aspect_ratio,withoutend);
   }
   else
   {
    parser(basepath,parfilename,parsetname,ibeg/speed,iend/speed,icalcbeg/speed,icalcend/speed,
     cp[0],cp[1],nrot,cp[2],cpp,aspect_ratio,withoutend);
   }

  ibeg=iend;

  }
 }

 _fcloseall();

 puts("Kool !!!");
}