/****************************************************************/
/*                                                              */
/* program: MAIN.C                  Created by : Brian Jacobson */
/*                                               09/07/94       */
/* Function: This program will parse a data input file to       */
/*           create the internal data structures for the SIPP   */
/*           program.                                           */
/*           Thanks to Robert Ringrose/Tomas Lozano-Perez for   */
/*           pieces of this code.                               */
/****************************************************************/


/* TBD:
   -- "-" for stdin on input and output files (default?)
   -- strip parens from input file
*/


#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>

#include "xrender.h"
#include "sipp.h"
#include "primitives.h"
#include "viewpoint.h"
#include "smalloc.h"
#include "parse.h"
#include "getopt.h"   /* for athena... */

/* try to get ansi to believe we have a popen() */
extern FILE	*popen(const char *, const char *);

extern char *optarg;          /* Used to find command line arguments      */
extern flyarndList *flyarndNames;
extern cameraList  *cameraNames;
extern lightList   *lightNames;
extern objList     *objNames;
extern double       startTime, endTime;  /* Starting and ending render time */
extern int          sizeX, sizeY;        /* Size of panel in X and Y        */
extern double       timeStep;            /* Indicates the time step         */
extern unsigned char verbose;

main(argc, argv)
    int    argc;
    char **argv;
{
  FILE    *outFile=0;
  char    writeFile = FALSE;
  char    gifout = FALSE;
  char    incr_filename = FALSE;     /* For -i option */
  unsigned time_increment = 0;
  char    gzipout = FALSE;   /* for -z option */
  char    gzipCommandString[MAX_NAME_SIZE];
  char    inFile[MAX_NAME_SIZE];
  char    outFilename[MAX_NAME_SIZE];
  char    patFilename[MAX_NAME_SIZE];
  char    viewFileName[MAX_NAME_SIZE];
  char    mainmode, mode;
  char   *incr_filename_pat;   /* for -i option */
  char   *base;
  int     c;
  int     size;
  int oversample = 1;
  flyarndList *flyarnd;
  cameraList *cam;
  double  time;
  unsigned char autopause = FALSE;
  Vector  tmp;

  mainmode = FLAT;     /* Indicate use a line drawing for ps1 */
  size = 256;      /* Size of panel to render */

  while ((c = getopt(argc, argv, "zr:i:pgflxcs:o:")) != EOF) {
      switch (c) {

      case 'x':
	autopause = TRUE;
	break;

      case 'c':
	gifout = TRUE;
	break;

      case 'z':
	gzipout = TRUE;
	break;

      case 'i':
	incr_filename = TRUE;
	time_increment = atoi(optarg);
	break;

      case 'p':
	mainmode = PHONG;
	break;
	
      case 'g':
	mainmode = GOURAUD;
	break;
	
      case 'f':
	mainmode = FLAT;
	break;
	
      case 'l':
	mainmode = LINE;
	break;
	
      case 's':
	size = atoi(optarg);
	break;
	
      case 'r':
	oversample = atoi(optarg);
	break;
	
      case 'o':           /* output file */
	strcpy(outFilename,optarg);
	strcpy(patFilename,optarg);
	writeFile = TRUE;
	break;
	
      default:
	fprintf(stderr,"Wait -- unknown option %c!\n",c);
	exit(-1);
      }
  }
   
  /*
  ** try to process the input file name -- 
  ** just get the first non-option string
  */
  if (optind >= argc  ||  sscanf(argv[optind]," %s",inFile) != 1) {
      fprintf(stderr,"Usage: spam <input_file> [-o <output_file>]\n\t"
	      "[-s <size>] [-z] [-i <start>] [-r <oversample>] [{-pgfl}]\n\n");
      fprintf(stderr,"\t-l\twireframe (Line) drawing\n");
      fprintf(stderr,"\t-f\tflat shading\n");
      fprintf(stderr,"\t-g\tGouraud shading\n");
      fprintf(stderr,"\t-p\tPhong shading\n");
      fprintf(stderr,"\t-r\tOversampling\n");
      fprintf(stderr,"\t-x\tForce pause between each frame\n");
      fprintf(stderr,"\t-c\tOutput file as .GIF format\n");
      fprintf(stderr,"\t-z\tCompress saved file with gzip\n");
      fprintf(stderr,"\t-i <x>\tOutput filenames in incremental format.\n");
      fprintf(stderr,"\t\t<x> is the first value.  The output_file for -o\n");
      fprintf(stderr,"\t\tshould contain a %%d for the incremental time\n");
      exit(1);
  }

  sipp_init();     /* Initialize the renderer */

  ParseFile(inFile,FALSE);       /* Read in the data file */
  if ((!sizeX) || (!sizeY))      /* Set up the panel size */
    sizeX = sizeY = size;

  fprintf(stdout,"Rendering, wait...\n");

  for (flyarnd = flyarndNames; flyarnd != NULL; flyarnd=flyarnd->next) {
    double theta, phi, a, i;
    
    /* currently set up for looking at origin... */
    hither = flyarnd->hither;
    yon = flyarnd->yon;
    camera_look_at(sipp_camera,flyarnd->lookp.x,flyarnd->lookp.y,
		   flyarnd->lookp.z);
    camera_up(sipp_camera,0.,1.,0.);
    camera_focal(sipp_camera,flyarnd->fov);
    if ((mode = flyarnd->mode) == MDEFAULT)
      mode = mainmode;

    if (verbose)
      printf("Camera Flyaround : %s\n",flyarnd->name);
    
    phi = 0.01;
    for (theta = 0.0; phi < M_PI - 0.01; theta += flyarnd->steptheta) { 
      
      a = flyarnd->radius * sin(phi) * flyarnd->aspect;
      camera_position(sipp_camera, 
		      flyarnd->lookp.x + a*sin(theta), 
		      flyarnd->lookp.y + flyarnd->radius*cos(phi),
		      flyarnd->lookp.z + a*cos(theta));

      render_ximage(sizeX,sizeY,mode,1,mode==LINE?RX_NOREFRESH:0);
      for (i=0.0; i < (flyarnd->delay); i++);

      phi += (flyarnd->stepphi) * flyarnd->steptheta / (2 * M_PI);
    }
    fprintf(stdout,"Done. Hit return to see next image.\n");
    getc(stdin);
  }
  
  cam = cameraNames; 
  for (time = startTime; (time<=endTime) && (cam != NULL); time += timeStep) {

    /* Now find the camera associated with this time... */
    cam = NextTimedCamera(&cam,time);
    
    /* Check to see if we've got a NULL camera..! (no more) */
    if (cam == NULL) {
      fprintf(stderr,"** Warning! No cameras defined for time >= %.3lg. Exiting...\n",time);
      exit(0);
    }

    /* Now see if we've got cameras defined at the current time */
    if (((cam->start - time) > Z) || ((cam->end - time) < Z)) {
      printf("** Warning! No cameras defined for time = %.3lg. Skipping...\n",time);
      continue;
    }

    if (verbose)
      printf("Camera Name : %s  Time : %.4lf \n",cam->name, time);

    InterpolateCamera(cam,time);

    hither = cam->hither;
    yon = cam->yon;
    
    camera_use(cam->camera); 
    if ((mode = cam->mode) == MDEFAULT)
      mode = mainmode;

    InterpolateLights(&lightNames,time);
    InterpolateObjects(objNames,time);
    
    if (writeFile) {
      if (gifout) {
	/* don't let them gzip a gif */
	if (gzipout) {
	    fprintf(stderr,"*** Sorry, gzipping a gif is not supported "
		    "(or smart)!\n");
	    exit(-1);
	}

	if (incr_filename)
	  sprintf(viewFileName,patFilename,time_increment);
	else
	  sprintf(viewFileName,"%s.%07.3lf.gif",outFilename,time);
        render_gif_file(sizeX, sizeY, viewFileName, mode, oversample);
      } else {
	if (incr_filename)
	  sprintf(viewFileName,patFilename,time_increment);
	else
	  sprintf(viewFileName,"%s.%07.3lf.ppm",outFilename,time);

	if (gzipout) {
	    /* open pipe if we're gzipping */
	    char command[200];
	    sprintf(command,"gzip > %s.gz",viewFileName);
	    outFile = popen(command,"w");
	    if (!outFile) {
		fprintf(stderr,"Error piping gzip to %s\n",viewFileName);
		exit(-11);
	    }
	} else {
	    /* open file to write ppm directly */
	    if ((outFile = fopen(viewFileName,"w")) == NULL) {
		fprintf(stderr,"Error in output filename %s\n",viewFileName);
		exit(-10);
	    }
	}

        render_image_file(sizeX, sizeY, outFile, mode, oversample);
	if (outFile)
	    if (gzipout)
		pclose(outFile);
	    else
		fclose(outFile);
      }

      time_increment++;
    }
    else {
      render_ximage(sizeX,sizeY,mode,oversample,mode==LINE?RX_NOREFRESH:0);
      if ((cam->pause) || (autopause)) {
	fprintf(stdout,"Done. Hit return to see next image.\n");
	getc(stdin);
      }
    }
    if (autopause)
      cam = cam->next;
  }
  exit(0);
}
