/************************************************************************
			   3DPath v1.00

		      Copyright (c) 1994 by
       Keith Vertanen, Scott Perowitz & Aleksey Przhelyaskovskiy

	  Contact authors before distributing modified copies

************************************************************************/

#include <iostream.h>
#include <fstream.h>
#include <strstrea.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>     // for getch() primitive
#include <math.h>      // for sqrt()
#include "spline.cpp"

#define VER "v1.00"
#define ERR1 "\nERROR: You must specify names of a point and a script files.\n\n"
#define ERR2 "\nERROR: Invalid option.\n\n"
#define ERR3 "\nERROR: File name must be specified.\n\n"
#define ERR4 "\nERROR: Number of frames should be specified.\n\n"
#define ERR5 "\nERROR: Cannot open script file: "
#define ERR6 "\nERROR: Not enough control points for cubic spline.\n\n"
#define ERR7 "\nERROR: No location section.\n\n"
#define ERR8 "\nERROR: No closing '>' in location section.\n\n"
#define ERR9 "\nERROR: No look_at section.\n\n"
#define ERR10 "\nERROR: No closing '>' in look_at section.\n\n"
#define ERR11 "\nERROR: Invalid example batch file.\n\n"
#define ERR12 "\nERROR: Cannot open example file: "
#define ERR13 "\nERROR: Not enough control points for spline.\n\n";

void show_help();  // display command line help
void read_command_line(int argc, char *argv[], int *num_frames,
			int *degree, int *view, int *test_script, int *batch,
			char point_file[40], char script_file[40],
			char out_file[40], char override_file[40],
			char example_file[40], char static_look_at[40]) ; //parse the command line
int find_length(char *open_file);   // gets # of lines in a file
void read_points(char point_file[40], point *control,
		 int *num_control, int *closed); // read the control points into array
int search(char *text, char *pattern); // find position of pattern in text
void int_to_str(char text[5], int num); // convert int to string
void do_script(char script_file[40], char override_file[40],
	point *position, int num_frames, char static_look_at[40],
	int closed);
void show_spline(int view, int num_control, int num_frames,
		   point *position, point *control_points);
void make_test_script(char script_file[40],char override_file[40],
			point *position,int num_frames);
void do_batch(char out_file[40], char example_file[40],
	      char override_file[40], char script_file[40],
	      int num_frames,int closed);

void main(int argc, char *argv[])
{
  char point_file[40],
       script_file[40],
       out_file[40],
       override_file[40],
       example_file[40];
  int num_frames,
      num_control=0,
      degree=3,
      view=0,
      test_script=0,
      batch=0,
      closed=0,
      j;

  point *control_points, *position;
  char static_look_at[40];

  for (j=0; j<40; j++)           // null all the filename arrays
  {
    point_file[j]=NULL;
    script_file[j]=NULL;
    out_file[j]=NULL;
    override_file[j]=NULL;
    example_file[j]=NULL;
    static_look_at[j]=NULL;
  }
  strcpy(example_file, "3dsample.bat");

  // get all the filenames and options from the command line

  read_command_line(argc,argv,&num_frames,&degree,&view,&test_script,
			&batch,point_file,script_file,out_file,
			override_file,example_file,static_look_at);

  // allocate the control array and read it from the point file
  num_control=find_length(point_file);
  if (num_control<=degree)
  {
    cout << ERR13;
    exit(-1);
  }
  control_points=new point[num_control+1];
  read_points(point_file, control_points, &num_control, &closed);

  // allocate the position array and calculate it from the bspline
  if (closed)        // add an extra if closed since we'll drop the duplicate last point
    num_frames++;
  position=new point[num_frames];
  bspline(num_control-1,degree+1,control_points,position,num_frames);

  if (test_script)    // does user want just a test script generated
  {
    make_test_script(script_file,override_file,position,num_frames);
  }
  else
  {
    if (view>0)
      show_spline(view,num_control,num_frames,position,control_points);
    else
      do_script(script_file,override_file,position,num_frames,
		static_look_at,closed);
  }

  if (batch!=0)
    do_batch(out_file,example_file,override_file,script_file,num_frames,closed);
}

void show_help()
{
    cout << "3DPath " << VER << " Copyright (c) 1994 by\n";
    cout << "Keith Vertanen, Scott Perowitz & Aleksey Przhelyaskovskiy\n";
    cout << "=================================================================\n";
    cout << "Command line:\n";
    cout << "  3DPath  pointfile[.3d]  scriptfile[.pov]\n\n";

    cout << "Optional switches:\n";
    cout << "  -f(# frames) how many frames to generate (default 100)\n";
    cout << "  -b(filename) create output batch file (filename optional)\n";
    cout << "  -d(filename) example batch file to base output on\n";
    cout << "  -o(filename) override filename for the output scripts\n";
    cout << "  -p(#)        degree of polynomial for spline (default 3)\n";
    cout << "  -xy -xz -yz  view curve in xy, xz, or yz plane without generating scripts\n";
    cout << "  -l(x,y,z)    use static look_at vector of x,y,z (i.e. -l100,50,25)\n";
    cout << "  -t           create test script with path as spheres\n";
}


void read_command_line(int argc, char *argv[], int *num_frames,
			int *degree, int *view, int *test_script,
			int *batch,char point_file[40],
			char script_file[40],char out_file[40],
			char override_file[40],char example_file[40],
			char static_look_at[40])
{
  int i,j,k,l;
  int found;

  // if # of arguments < 2, print help screen & exit
  if (argc <= 2)
  {
    show_help();
    // this line should be changed to the call to a help screen
    exit(-1);
  } //if


  *num_frames=-1;

  // go through the arguments
  for (i=1; i < argc; i++)
  {
    switch (i)
    {
      case  1:
	  {
	    found=0;
	    for (j=0; j<strlen(&argv[i][0]) && j<39; j++)
	    {
	      point_file[j]=argv[i][j];
	      if (argv[i][j]=='.')
		found=1;
	    }
	    if ((!found) && (j<37))              // if no extension, add .3D
	    {
	      point_file[j]='.';
	      j++;
	      point_file[j]='3';
	      j++;
	      point_file[j]='D';
	    }
	  }
	break;
      case  2:
	  {
	    found=0;
	    for (j=0; j<strlen(&argv[i][0]) && j<39; j++)
	    {
	      script_file[j]=argv[i][j];
	      if (argv[i][j]=='.')
		found=1;
	    }
	    if ((!found) && (j<37))             // if no extension, add .POV
	    {
	      script_file[j]='.';
	      j++;
	      script_file[j]='P';
	      j++;
	      script_file[j]='O';
	      j++;
	      script_file[j]='V';
	    }

	  }
	break;
     case  3:
     case  4:
     case  5:
     case  6:
	  if (((argv[i][0] == '-') || (argv[i][0] == '/'))  // create test script
		    && (argv[i][1] == 't' ))
	  {
	    *test_script=1;
	    break;
	  } // if

	  if (((argv[i][0] == '-') || (argv[i][0] == '/'))  // static look_at vector
		    && (argv[i][1] == 'l' ))
	  {
	      for (j=0; j<strlen(&argv[i][2]); j++)
		static_look_at[j]=argv[i][j+2];
	    break;
	  } // if

	  if (((argv[i][0] == '-') || (argv[i][0] == '/'))  // xy or xz view
		    && (argv[i][1] == 'x' ))
	  {
	      if (argv[i][2]=='y')
		*view = 1;
	      if (argv[i][2]=='z')
		*view = 2;
	    break;
	  } // if

	  if (((argv[i][0] == '-') || (argv[i][0] == '/'))  // yz view
		    && (argv[i][1] == 'y' ))
	  {
	      if (argv[i][2]=='z')
		*view = 3;
	    break;
	  } // if

	  if (((argv[i][0] == '-') || (argv[i][0] == '/'))
		    && (argv[i][1] == 'p' ))
	  {
	      *degree = atoi(&argv[i][2]);
	      if (atoi (&argv[i][2]) == 0)
		*degree=3;
	    break;
	  } // if

	  if (((argv[i][0] == '-') || (argv[i][0] == '/'))
		    && (argv[i][1] == 'o' ))
	  {
	      for (j=0; j<strlen(&argv[i][2]) && argv[i][j+2]!='.'; j++)
		override_file[j]=argv[i][j+2];
	      if (&argv[i][2] == NULL)
	      {
		cout << ERR3;
		show_help();
		exit(-1);
	      }
	    break;
	  } // if

	  if (((argv[i][0] == '-') || (argv[i][0] == '/'))
		    && (argv[i][1] == 'f' ))
	  {
	      *num_frames = atoi(&argv[i][2]);
	      if (atoi (&argv[i][2]) == 0)
	      {
		*num_frames=-1;
	      }
	    break;
	  } // if

	  if (((argv[i][0] == '-') || (argv[i][0] == '/'))
		    && (argv[i][1] == 'b' ))
	  {
	      *batch=1;
	      found=0;
	      for (j=0; j<strlen(&argv[i][2]); j++)
	      {
		out_file[j]=argv[i][j+2];
		if (argv[i][j+2]=='.')
		  found=1;
	      }
	      if (!found)
	      {
		out_file[j]='.';           // no extension add .bat
		j++;
		out_file[j]='B';
		j++;
		out_file[j]='A';
		j++;
		out_file[j]='T';
		j++;
	      }

	      if (argv[i][2] == NULL)
	      {
		for (k=0; (k<strlen(argv[2]) && argv[2][k]!='.'); k++);
		for (l=0; l<k; l++)
		  out_file[l]=argv[2][l];
		out_file[l]='.';           // no file specified, use script
		l++;                       // name plus .bat extension
		out_file[l]='B';
		l++;
		out_file[l]='A';
		l++;
		out_file[l]='T';
		l++;
		j=l;
	      }
	      for (k=j; k<40; k++)
		out_file[k]=NULL;

	    break;
	   } // if

	  if (((argv[i][0] == '-') || (argv[i][0] == '/'))
		    && (argv[i][1] == 'd' ))
	  {
	      found=0;
	      for (j=0; j<strlen(&argv[i][2]); j++)
	      {
		example_file[j]=argv[i][j+2];
		if (argv[i][j+2]=='.')
		  found=1;
	      }
	      if (!found)
	      {
		example_file[j]='.';           // no extension add .bat
		j++;
		example_file[j]='B';
		j++;
		example_file[j]='A';
		j++;
		example_file[j]='T';
		j++;
	      }

	      if (argv[i][2] == NULL)
	      {
		cout << ERR3;
		show_help();
		exit(-1);
	      }
	      for (k=j; k<40; k++)
		example_file[k]=NULL;
	    break;
	  } // if

      default:
	  cout << ERR2 << argv[i];
	  show_help();
	  exit(-1);
	break;
    } // switch
  } //for

  cout << "\n/// 3DPath " << VER << " /// \n";
  cout << "Copyright (c) 1994 by Keith Vertanen, Scott Perowitz & Aleksey Przhelyaskovskiy\n\n";

  if (*num_frames<0)    // if no -f specified
  {
    cout << "No frame number specified, defaulting to 100.\n";
    *num_frames=100;
  }
}

int find_length(char *open_file)
{
  int num_lines=0;

  ifstream source;
  source.open(open_file,ios::nocreate);
  if (source)
  {
    int len=255;
    char stop='\n';
    char line[256];

    while (source.eof()==0)        // find out how big of an array to allocate
    {
      source.getline(line,len,stop);
      if ((line[0]!='#') && (strlen(line)>1))
	num_lines++;
    }
    source.close();
  }
  else
  {
    cout << "\nERROR: Cannot open point file: " << open_file << ".\n";
    exit(-1);
  }
  return num_lines;
}

void read_points(char *point_file, point *control, int *num_lines,
		 int *closed)
{
  int i;
  char line[256];
  double x,y,z;
  int len=255;
  char stop='\n';

  ifstream source;
  source.open(point_file,ios::nocreate);  // open her up again
  if (source)
  {
    i=0;
    while (i<(*num_lines))
    {
      source.getline(line,len,stop);
      if ((line[0]!='#') && (strlen(line)>1))
      {
	istrstream ins(line,strlen(line));
	ins >> x >> y >> z;
	(control[i]).x=x;
	(control[i]).y=y;
	(control[i]).z=z;
	i++;
      }
    }
  }
  else
  {
    cout << "\nERROR: Cannot open point file: " << point_file << "\n";
    exit(-1);
  }
  if ((control[i-1].x==control[0].x) &&
     (control[i-1].y==control[0].y) &&
     (control[i-1].z==control[0].z))    // if first pt = last pt, insert smoothing point
  {
    double dx,dy,dz;
    control[i].x=control[i-1].x;   // copy last point down one
    control[i].y=control[i-1].y;
    control[i].z=control[i-1].z;
    dx=control[1].x-control[0].x;
    dy=control[1].y-control[0].y;
    dz=control[1].z-control[0].z;
    control[i-1].x=control[0].x-dx;
    control[i-1].y=control[0].y-dy;
    control[i-1].z=control[0].z-dz;
    *num_lines=*num_lines+1;  // pass back that we have one more control point
    cout << "Closed path detected, inserting control point to smooth.\n";
    *closed=1;
  }
}

int search(char *text, char *pattern)
{
  int i, j, M, N;
  char *p,*a;

  p=strupr(pattern);
  a=strupr(text);
  M=strlen(p);
  N=strlen(a);

  for (i=0, j=0; j<M && i<N; i++, j++)
  {
    if (a[i]!=p[j])
    {
      j=-1;
    }
  }
  if (j==M) return i-M; else return i;
};

void int_to_str(char text[6], int num)
{
  // there has got to be a bloody primitive for this...  what is it???
  int i, a, j=0;
  int e=10000;

  for (i=0; i<5; i++)
  {
    a=num/e;
    if ((a>0) || (j>0))  // no leading zeros wanted
    {
      switch (a)
      {
	case 0 : { text[j]='0'; break; }
	case 1 : { text[j]='1'; break; }
	case 2 : { text[j]='2'; break; }
	case 3 : { text[j]='3'; break; }
	case 4 : { text[j]='4'; break; }
	case 5 : { text[j]='5'; break; }
	case 6 : { text[j]='6'; break; }
	case 7 : { text[j]='7'; break; }
	case 8 : { text[j]='8'; break; }
	case 9 : { text[j]='9'; break; }
      }
      j++;
      num=num-(e*a);
    }
    e=e/10;
  }
  for (i=j; i<6; i++)
    text[i]=NULL;
}

void do_script(char script_file[40], char override_file[40],
		point *position, int num_frames, char static_look_at[40],
		int closed)
{
  int current_frame, end_camera, i = 0;
  int begin_camera_pos;
  int begin_location, end_location, begin_look_at, end_look_at = 0;
  int begin_location_pos, end_location_pos, begin_look_at_pos, end_look_at_pos = 0;
  int j;
  char ch, insertion[200];
  char *x;
  double xt,yt,zt;

  ifstream script;
  script.open(script_file,ios::nocreate);  // open up script source file
  if (script)
  {
    int len=255;
    char stop='\n';
    char line[256];
    char *ptr;
    char a='>';

    // We will now find, with surgical precision, the line number and
    // position of the location and look_at keywords in the camera section
    // of the script file.  NOTE: location must precede look_at or else

    while (script.eof()==0)  // search the file to find the location of camera section
    {
      script.getline(line,len,stop);
      begin_camera_pos=search(line,"camera");
      if (begin_camera_pos<strlen(line))
      {
	begin_camera_pos++;
	begin_location_pos=search(line,"location");
	while (begin_location_pos>=strlen(line))
	{
	  if (script.eof())
	  {
	    cout << ERR7;
	    exit(-1);
	  }
	  script.getline(line,len,stop);
	  begin_location_pos=search(line,"location");
	  i++;
	}
	begin_location=i+1;
	begin_location_pos++;
	ptr=strchr(line,a);
	while (!ptr)
	{
	  if (script.eof())
	  {
            cout << ERR8;
	    exit(-1);
	  }
	  script.getline(line,len,stop);
	  ptr=strchr(line,a);
	  i++;
	}
	end_location_pos=ptr-line+1;
	end_location=i+1;

	begin_look_at_pos=search(line,"look_at");
	while (begin_look_at_pos>=strlen(line))
	{
	  if (script.eof())
	  {
            cout << ERR9;
	    exit(-1);
	  }
	  script.getline(line,len,stop);
	  begin_look_at_pos=search(line,"look_at");
	  i++;
	}
	begin_look_at=i+1;
	begin_look_at_pos++;
	ptr=strchr(line,a);
	while (!ptr)
	{
	  if (script.eof())
	  {
	    cout << ERR10;
	    exit(-1);
	  }
	  script.getline(line,len,stop);
	  ptr=strchr(line,a);
	  i++;
	}
	end_look_at_pos=ptr-line+1;
	end_look_at=i+1;
	break;
      }
      i++;
    }
    script.close();

    // okay, lets make the actual files
    char our_name[40];

    for (i=0; i<40; i++) // blank out the array
      our_name[i]=NULL;

    if (strlen(override_file)==0)     // did the user give us an override name
    {
      i=0;
      while (i<40 && script_file[i]!='.')
      {
	our_name[i]=script_file[i];
	i++;
      }
    }
    else
    {
      i=0;
      while (i<40 && override_file[i]!='.')
      {
	our_name[i]=override_file[i];
	i++;
      }
    }

    ofstream output;
    char numstr[6];
    char numstr2[6];
    char open_name[40];

    int_to_str(numstr,num_frames);

    j=strlen(our_name)-1;
    while ((j>=0) && (our_name[j]!='\\'))
      j--;

    if (strlen(our_name)-j-1+strlen(numstr)>8)   // check if we need to chop name
    {
      for (i=j+9-strlen(numstr); i<40; i++)
	our_name[i]=NULL;
    }
    int_to_str(numstr2,num_frames);

    // here is the loop that actually generates the output script files
    cout << "Generating frame #";

    if (closed)      // if smooth closed path, don't double up the first and last frames
      num_frames--;

    for (i=1; i<=num_frames; i++)
    {
      cout << i;
      int_to_str(numstr,i);
      strcpy(open_name,our_name); // copy our_name
      for (j=0; j<strlen(numstr2)-strlen(numstr); j++)  // add leading zeros
	strcat(open_name,"0");
      strcat(open_name,numstr);   // put the number suffix on
      strcat(open_name,".POV");   // put the .POV extension on
      output.open(open_name);     // open up output file

      script.open(script_file,ios::nocreate);
      for (j=1; j<begin_location; j++)        // get to location line
      {
	 script.getline(line,len,stop);
	 output.write(line,strlen(line));
	 output.put('\n');
      }
      for (j=1; j<begin_location_pos; j++)   // get to location position
      {
	script.get(ch);
	output.put(ch);
      }
      for (j=0; j<200; j++)
	insertion[j]=NULL;
      x=NULL;
      strcpy(insertion,"location <");

      xt=0;
      yt=0;
      zt=0;

      xt=position[i-1].x;
      yt=position[i-1].y;
      zt=position[i-1].z;

      gcvt(xt,15,x);
      strcat(insertion,x);
      strcat(insertion,", ");
      gcvt(yt,15,x);
      strcat(insertion,x);
      strcat(insertion,", ");
      gcvt(zt,15,x);
      strcat(insertion,x);
      strcat(insertion,">");

      output.write(insertion,strlen(insertion));

      if (begin_location!=end_location)  // if closure on different line
      {
	for (j=begin_location; j<end_location; j++)
	  script.getline(line,len,stop);
	begin_location_pos=1;
      }

      ch=NULL;
      for (j=begin_location_pos; ch!='\n'; j++) // get to end of location line
      {
	script.get(ch);
	if (j>end_location_pos)
	  output.put(ch);
      }
      for (j=end_location+1; j<begin_look_at; j++)   // get to look_at line
      {
	 script.getline(line,len,stop);
	 output.write(line,strlen(line));
	 output.put('\n');
      }
      for (j=1; j<begin_look_at_pos; j++)   // get to look_at position
      {
	script.get(ch);
	output.put(ch);
      }
      for (j=0; j<200; j++)
	insertion[j]=NULL;
      strcpy(insertion,"look_at <");
      if (strlen(static_look_at)>0)
      {
	strcat(insertion,static_look_at);
	strcat(insertion,">");
      }
      else
      {
	if (i<num_frames)
	{
	  xt=position[i].x;
	  yt=position[i].y;
	  zt=position[i].z;
	}
	else
	{
	  xt=2*position[i-1].x-position[i-2].x;
	  yt=2*position[i-1].y-position[i-2].y;
	  zt=2*position[i-1].z-position[i-2].z;
	}
	gcvt(xt,15,x);
	strcat(insertion,x);
	strcat(insertion,", ");
	gcvt(yt,15,x);
	strcat(insertion,x);
	strcat(insertion,", ");
	gcvt(zt,15,x);
	strcat(insertion,x);
	strcat(insertion,">");
      }
      output.write(insertion,strlen(insertion));

      if (begin_look_at!=end_look_at)  // if closure on different line
      {
	for (j=begin_look_at; j<end_look_at; j++)
	  script.getline(line,len,stop);
      }

      ch=NULL;
      for (j=begin_look_at_pos; ch!='\n'; j++) // get to end of look_at line
      {
	script.get(ch);
	if (j>end_look_at_pos)
	  output.put(ch);
      }
      while (!script.eof())
      {
	 script.getline(line,len,stop);
	 output.write(line,strlen(line));
	 output.put('\n');
      }

      script.close();

      for (j=0; j<strlen(numstr); j++)
	cout << "\b";
      output.close();
    }
    cout << "\n";
  }
  else
  {
    cout << "\nERROR: Cannot open script file: " << script_file << "\n";
    exit(-1);
  }
}

void show_spline(int view, int num_control, int num_frames,
		  point *position, point *control_points)
{
  int i;
  double max_x=-99999999999;
  double max_y=-99999999999;
  double max_z=-99999999999;
  double min_x=99999999999;
  double min_y=99999999999;
  double min_z=99999999999;
  double top, left, bottom, right;
  double dx,dy;
  char num[6];

  if (set_graph())
  {
  for (i=0; i<num_frames; i++)   // find the min and max values of curve
  {
    if (position[i].x>max_x)
      max_x=position[i].x;
    if (position[i].y>max_y)
      max_y=position[i].y;
    if (position[i].z>max_z)
      max_z=position[i].z;
    if (position[i].x<min_x)
      min_x=position[i].x;
    if (position[i].y<min_y)
      min_y=position[i].y;
    if (position[i].z<min_z)
      min_z=position[i].z;
  }
  for (i=0; i<num_control; i++)   // find the min and max values of control pts
  {
    if (control_points[i].x>max_x)
      max_x=control_points[i].x;
    if (control_points[i].y>max_y)
      max_y=control_points[i].y;
    if (control_points[i].z>max_z)
      max_z=control_points[i].z;
    if (control_points[i].x<min_x)
      min_x=control_points[i].x;
    if (control_points[i].y<min_y)
      min_y=control_points[i].y;
    if (control_points[i].z<min_z)
      min_z=control_points[i].z;
  }

  switch (view)
  {
    case 1 : {top=min_y-20; left=min_x-20; bottom=max_y+20; right=max_x+20; break;}  //xy view
    case 2 : {top=min_z-20; left=min_x-20; bottom=max_z+20; right=max_x+20; break;}  //xz view
    case 3 : {top=min_y-20; left=min_z-20; bottom=max_y+20; right=max_z+20; break;}  //yz view
  }
  dx=getmaxx()/(right-left);
  dy=getmaxy()/(bottom-top);

    setcolor(BLUE);
    switch (view)
    {
      case 1 :
      {
	for (i=0; i<num_control; i++)
	{
	  circle((control_points[i].x-left)*dx,     // draw control points
		(control_points[i].y-top)*dy,2);
	}
	circle((control_points[0].x-left)*dx,
		(control_points[0].y-top)*dy,0); // drop the pen down at first control point
	setcolor(WHITE);
	for (i=0; i<num_frames; i++)
	{
	  circle((position[i].x-left)*dx,(position[i].y-top)*dy,1);
	}
	setcolor(GREEN);
	for (i=0; i<num_control; i++)  // put number by the control points
	{
	  int_to_str(num,i);
	  if (i==0)
	    num[0]='0';
	  outtextxy((control_points[i].x-left)*dx+3,
		    (control_points[i].y-top)*dy+3,num);
	}
	break;
      }
      case 2 :
      {
	for (i=0; i<num_control; i++)
	{
	  circle((control_points[i].x-left)*dx,     // draw control points
		(control_points[i].z-top)*dy,2);
	}
	circle((control_points[0].x-left)*dx,
		(control_points[0].z-top)*dy,0); // drop the pen down at first control point
	setcolor(WHITE);
	for (i=0; i<num_frames; i++)
	{
	  circle((position[i].x-left)*dx,(position[i].z-top)*dy,1);
	}
	setcolor(GREEN);
	for (i=0; i<num_control; i++)  // put number by the control points
	{
	  int_to_str(num,i);
	  if (i==0)
	    num[0]='0';
	  outtextxy((control_points[i].x-left)*dx+3,
		    (control_points[i].z-top)*dy+3,num);
	}

	break;
      }
      case 3 :
      {
	for (i=0; i<num_control; i++)
	{
	  circle((control_points[i].z-left)*dx,     // draw control points
		(control_points[i].y-top)*dy,2);
	}
	circle((control_points[0].z-left)*dx,
		(control_points[0].y-top)*dy,0); // drop the pen down at first control point
	setcolor(WHITE);
	for (i=0; i<num_frames; i++)
	{
	  circle((position[i].z-left)*dx,(position[i].y-top)*dy,1);
	}
	setcolor(GREEN);
	for (i=0; i<num_control; i++)  // put number by the control points
	{
	  int_to_str(num,i);
	  if (i==0)
	    num[0]='0';
	  outtextxy((control_points[i].z-left)*dx+3,
		    (control_points[i].y-top)*dy+3,num);
	}
	break;
      }
    }
    getch();
    restorecrtmode();
  }
}

void make_test_script(char script_file[40],char override_file[40],
			point *position,int num_frames)
{
  char our_name[40];
  int i,j;
  double x,y,z;
  double x2,y2,z2;
  double radius;
  char *t;
  char insertion[255];

  if (override_file[0]!=NULL)
    strcpy(our_name,override_file);
  else
    strcpy(our_name,script_file);

  i=strlen(our_name)-1;            // backup to beginning of filename
  while ((our_name[i]!='\\') && (i>0))
    i--;
  j=0;
  while ((our_name[i]!='.') && (j<6) && (our_name[i]!=NULL))
  {
    i++;
    j++;
  }
  our_name[i]='_';
  i++;
  our_name[i]='3';
  i++;
  our_name[i]='D';
  i++;
  our_name[i]='.';
  i++;
  our_name[i]='P';
  i++;
  our_name[i]='O';
  i++;
  our_name[i]='V';
  i++;

  for (j=i; j<40; j++)
    our_name[j]=NULL;

  ifstream input;
  input.open(script_file,ios::nocreate);  // open up example file
  if (input)
  {
  cout << "Creating test script file: " << our_name << "\n";
  ofstream output;
  output.open(our_name);      // open up output file

  int len=255;
  char stop='\n';
  char line[256];

  while (input.eof()==0)  // copy the whole script file intact
  {
    input.getline(line,len,stop);
    output.write(line,strlen(line));
    output.put('\n');
  }
  input.close();
  radius=0;
  for (i=0; i<num_frames; i++)
  {
    x=position[i].x;
    y=position[i].y;
    z=position[i].z;

    if (i+1==num_frames)
    {
      x2=position[i-1].x;
      y2=position[i-1].y;
      z2=position[i-1].z;

    }
    else
    {
      x2=position[i+1].x;
      y2=position[i+1].y;
      z2=position[i+1].z;
    }
    radius=radius+sqrt((x-x2)*(x-x2)+(y-y2)*(y-y2)+(z-z2)*(z-z2));
  }
  radius=radius/num_frames;

  for (i=0; i<num_frames; i++)
  {
    x=position[i].x;
    y=position[i].y;
    z=position[i].z;

    strcpy(insertion,"sphere { <");
    gcvt(x,15,t);
    strcat(insertion,t);
    strcat(insertion,", ");
    gcvt(y,15,t);
    strcat(insertion,t);
    strcat(insertion,", ");
    gcvt(z,15,t);
    strcat(insertion,t);
    strcat(insertion,">, ");
    gcvt(radius*0.9,15,t);
    strcat(insertion,t);
    output.write(insertion,strlen(insertion));

    strcpy(insertion,"  pigment {color Red} }\n");
    output.write(insertion,strlen(insertion));
  }
  }
  else
  {
    cout << ERR5 << script_file << "\n";  // couldn't open script file
    exit(-1);
  }
}

void do_batch(char out_file[40], char example_file[40],
		char override_file[40], char script_file[40],
		int num_frames, int closed)
{
  int current_frame, end_fname;
  int j, i=0,k;

  ifstream example;
  example.open(example_file,ios::nocreate);  // open up example file
  if (example)
  {
    int len=1000;   // hard code how big a batch file is available
    char stop=NULL;
    char data[1000];

    example.get(data,len,stop);
    example.close();

    // okay, lets make the out file
    char our_name[40];

    for (i=0; i<40; i++) // blank out the array
      our_name[i]=NULL;

    if (strlen(override_file)==0)     // did the user give us an override name
    {
      i=0;
      while (i<40 && script_file[i]!='.')
      {
	our_name[i]=script_file[i];
	i++;
      }
    }
    else
    {
      i=0;
      while (i<40 && override_file[i]!='.')
      {
	our_name[i]=override_file[i];
	i++;
      }
    }

    ofstream output;
    char numstr[6];
    char numstr2[6];
    char open_name[40];

    int_to_str(numstr,num_frames);

    j=strlen(our_name)-1;
    while ((j>=0) && (our_name[j]!='\\'))
      j--;

    if (strlen(our_name)-j-1+strlen(numstr)>8)   // check if we need to chop name
    {
      for (i=j+9-strlen(numstr); i<40; i++)
	our_name[i]=NULL;
    }
    int_to_str(numstr2,num_frames);

    output.open(out_file);      // open up output file

    if (closed)      // if smooth closed path, don't double up the first and last
      num_frames--;
    for (i=1; i<=num_frames; i++)
    {
      int_to_str(numstr,i);
      strcpy(open_name,our_name); // copy our_name
      for (j=0; j<strlen(numstr2)-strlen(numstr); j++)  // add leading zeros
	strcat(open_name,"0");
      strcat(open_name,numstr);   // put the number suffix on

      j=0;
      while (data[j]!=NULL)
      {
	while ((data[j]!='~') && (data[j]!=NULL))
	{
	  output.put(data[j]);
	  j++;
	}
	if (data[j]=='~')
	  j++;
	k=0;
	while ((open_name[k]!=NULL) && (data[j]!=NULL))
	{
	  output.put(open_name[k]);
	  k++;
	}
      }
    }
    output.close();
  }
  else
  {
    cout << ERR12 << example_file << "\n";
    exit(-1);
  }
}



