/* Write out the scene to text or Radiance or PGM file
 *
 * modifications:
 * 1998-09-24  added support for filename="-" to write to stdout
 *
 */


#include <stdio.h>
#include <stdlib.h>
#include "const.h"

int usebin = 1;		/* if ==1, write binary PPMs */

extern int inheight, inwidth;


/* ---------- Routines for writing ------------------------------------- */

/*
 * Write a Poskanzer GrayMap (.PGM) file of the heightfield
 * Write an ASCII version, only, to accomodate 16-bit grays
 */
int write_pgm_short(char filename[80],short int a[MAX_SIZE][MAX_SIZE],
                    int height,int width) {

   int i,j;
   FILE *fp;
   int max_val = -33000;
   int xloc, yloc;
   char use_stdout[2] = "-";

   /* find the maximum value of the array */
   for (i=0; i<height; i++) {
      for (j=0; j<width; j++) {
         if (a[i][j] > max_val) max_val = a[i][j];
      }
   }

   /* open the .pgm file for writing (or write to stdout) */
   if (use_stdout[0] == filename[0]) {
      fp = stdout;
   } else {
      fp = fopen(filename,"w");
      if (fp==NULL) {
         fprintf(stderr,"Could not open output file %s\n",filename);
         exit(0);
      }
   }

   /* write a header */
   fprintf(fp,"P2\n");
   fprintf(fp,"%d %d %d\n",width, height, max_val);

   /* write each data point as an int to the file */
   for (i=0; i<height; i++) {
      for (j=0; j<width; j++) {
         fprintf(fp,"%d\n",a[i][j]);
      }
   }

   /* close the file before returning to main */
   (void) fclose(fp);

   /* everything went OK, return zero */
   return(0);
}


/*
 * Write a Poskanzer GrayMap (.PGM) file of the heightfield
 * Write an ASCII version, only, to accomodate 16-bit grays
 */
int write_pgm_ushort(char filename[80],unsigned short int a[MAX_SIZE][MAX_SIZE],
                    int height,int width) {

   int i,j;
   FILE *fp;
   char use_stdout[2] = "-";
   int max_val = -1;
   int xloc, yloc;

   /* find the maximum value of the array */
   for (i=0; i<height; i++) {
      for (j=0; j<width; j++) {
         if (a[i][j] > max_val) max_val = a[i][j];
      }
   }

   /* open the .pgm file for writing (or write to stdout) */
   if (use_stdout[0] == filename[0]) {
      fp = stdout;
   } else {
      fp = fopen(filename,"w");
      if (fp==NULL) {
         fprintf(stderr,"Could not open output file %s\n",filename);
         exit(0);
      }
   }

   /* write a header */
   fprintf(fp,"P2\n");
   fprintf(fp,"%d %d %d\n",width, height, max_val);

   /* write each data point as an int to the file */
   for (i=0; i<height; i++) {
      for (j=0; j<width; j++) {
         fprintf(fp,"%d\n",a[i][j]);
      }
   }

   /* close the file before returning to main */
   (void) fclose(fp);

   /* everything went OK, return zero */
   return(0);
}


/*
 * Write a Poskanzer GrayMap (.PGM) file of the heightfield
 * Write an binary version, though
 * NOTE: No ASCII version of 8-bit graymap will be written
 */
int write_pgm_char(char filename[80],unsigned char a[MAX_SIZE][MAX_SIZE],
                    int height,int width) {

   int i,j,raw_val;
   FILE *fp;
   int max_val = 0;
   int xloc, yloc;
   char use_stdout[2] = "-";

   /* find the maximum value of the array */
   for (i=0; i<height; i++) {
      for (j=0; j<width; j++) {
         if (a[i][j] > max_val) max_val = a[i][j];
      }
   }

   /* open the .pgm file for writing (or write to stdout) */
   if (use_stdout[0] == filename[0]) {
      fp = stdout;
   } else {
      fp = fopen(filename,"w");
      if (fp==NULL) {
         fprintf(stderr,"Could not open output file %s\n",filename);
         exit(0);
      }
   }

   /* write a header */
   fprintf(fp,"P5\n");
   fprintf(fp,"%d %d %d\n",width, height, max_val);

   /* write each data point as a char to the file */
   for (i=0; i<height; i++) {
      for (j=0; j<width; j++) {
         raw_val = a[i][j];
         if (raw_val > 255) raw_val = 255;
         putc((char)raw_val,fp);
      }
   }

   /* close the file before returning to main */
   (void) fclose(fp);

   /* everything went OK, return zero */
   return(0);
}


/*
 * Write a Poskanzer PixMap (.PPM) file of the imagemap
 */
int write_ppm(char filename[80],COLOR out[MAX_SIZE][MAX_SIZE],
              int height,int width) {

   int i,j;
   COLOR this;
   FILE *fp;
   char use_stdout[2] = "-";

   /* check to see if user put a .ppm at the end */


   /* open the .ppm file for writing (or write to stdout) */
   if (use_stdout[0] == filename[0]) {
      fp = stdout;
   } else {
      fp = fopen(filename,"w");
      if (fp==NULL) {
         fprintf(stderr,"Could not open output file %s\n",filename);
         exit(0);
      }
   }

   /* write a header */
   if (usebin) {
      fprintf(fp,"P6\n");
   } else {
      fprintf(fp,"P3\n");
   }
   fprintf(fp,"%d %d %d\n",width, height, 255);

   /* write each data point as an int to the file */
   for (i=0; i<height; i++) {
      for (j=0; j<width; j++) {
         this = out[i][j];
         if (usebin) {
            putc((char)this.r,fp);
            putc((char)this.g,fp);
            putc((char)this.b,fp);
         } else {
            fprintf(fp,"%d %d %d\n",this.r,this.g,this.b);
         }
      }
   }

   /* close the file before returning to main */
   (void) fclose(fp);

   /* everything went OK, return zero */
   return(0);
}

void write_error(char message[80],int code) {

   fprintf(stderr,"%s\n",message);
   exit(code);
}


void write_finish() {

   fprintf(stderr,"\nFinished simulation.\n");
   exit(0);
}


/* ---------- Routines for reading ------------------------------------- */

/*
 * Read a Poskanzer GrayMap (.PGM) file and save in array hf[][]
 * This subroutine uses code from John Beale's er1u/inout.c
 */
int read_pgm_short(char filename[80],short int a[MAX_SIZE][MAX_SIZE]) {

   int i,j;
   int ix,iy;
   int npoints;            /* # points that should be in file */
   int points_read;        /* # points read from hf datafile */
   int xsize, ysize, maxval;
   int raw_val;
   char sbuf[512],dummy[2];
   char *junk;
   unsigned char fbin;                            /* PGM binary format flag */
   unsigned char oneb;                            /* one byte from file */
   FILE *fp;

   /* open the .pgm file for reading */
   fp = fopen(filename,"rb");
   if (fp==NULL) {
      fprintf(stderr,"Could not open input file %s\n",filename);
      exit(0);
   }
   fprintf(stderr,"Opening file %s\n",filename);

   /* read the header */
   if (fread(&sbuf,sizeof(char),2,fp) != 2) {
      fprintf(stderr,"   Could not read file, exiting.");
      return(1);	/* unsuccessful */
   } else {
      sbuf[2] = 0x00;
      fprintf(stderr,"   Initial file string: %s\n",sbuf);
   }

   fbin = 0;		/* assume PGM ascii */
   if (strcmp(sbuf,"P5") == 0) fbin = 1; /* PGM binary format */

   if ((strcmp(sbuf,"P5") != 0) && (strcmp(sbuf,"P2") != 0)) {
      fclose(fp);	/* close file, suck. */
      return(1);	/* unsuccessful */
   }

   /* file is PGM, either P5 (binary) or P2 (ascii) */

   while ((fscanf(fp,"%s",sbuf) != EOF) && sbuf[0] == '#') {
      /* fprintf(stderr,"comment:"); */
      fscanf(fp,"%[^\n]",sbuf);  /* read comment beyond '#' */
      fscanf(fp,"%[\n]",dummy);  /* read newline */
      fprintf(stderr,"   #%s\n",sbuf);            /* display comment */
   }

   xsize = (int) strtoul(sbuf, &junk, 10); /* cvt. xsize of array */
   fscanf(fp,"%s",sbuf);                 /* read ysize of array */
   ysize = (int) strtoul(sbuf, &junk, 10); /* cvt. ysize */
   fscanf(fp,"%s",sbuf);               /* read maxval of array */
   maxval = strtod(sbuf, &junk);

   fprintf(stderr,"   xsize %d  ysize %d  maxval %d\n",xsize,ysize,maxval);

   /* check size, make sure its not too big */
   if (xsize > MAX_SIZE) write_error("Input image width is too large.",1);
   if (ysize > MAX_SIZE) write_error("Input image height is too large.",1);

   points_read = 0;              /* haven't read any data points yet */
   npoints = xsize*ysize;
   ix = 0;
   iy = 0;                       /* fill array 0..xsize-1, 0..ysize-1 */

   fprintf(stderr,"   reading in...");
   if (fbin) {
      fread(&oneb,sizeof(unsigned char),1,fp);	/* read that line feed */
      while ((fread(&oneb,sizeof(unsigned char),1,fp) == 1) && (points_read < npoints) ) {
         a[iy][ix] = (short int) oneb;
         if (++ix > xsize-1) {
            ix = 0;
            iy++;
         }
         ++points_read;
      } /* end while not end-of-file */
   } else {
      while ((fscanf(fp,"%s",sbuf) != EOF) && (points_read < npoints) ) {
         /* a = strtod( sbuf, &junk); */
         a[iy][ix] = (short int)atoi(sbuf);
         if (++ix > xsize-1) {
            ix = 0;
            iy++;
         }
         points_read++;
      }
   } /* end if fbin */

   fprintf(stderr,"%lu elements read.\n",points_read);
   if (points_read != npoints) {
      fprintf(stderr,"   Warning: %lu points missing.\n",npoints-points_read);
   }
   fclose(fp);
   fprintf(stderr,"   Files closed.\n");

   inheight = ysize;
   inwidth = xsize;

   /* everything went OK, return zero */
   return(0);
}


/*
 * Read a Poskanzer GrayMap (.PGM) file and save in array hf[][]
 * This subroutine uses code from John Beale's er1u/inout.c
 * NOTE: this subroutine reads values from 0 to 65535
 */
int read_pgm_ushort(char filename[80],unsigned short int a[MAX_SIZE][MAX_SIZE]) {

   int i,j;
   int ix,iy;
   int npoints;            /* # points that should be in file */
   int points_read;        /* # points read from hf datafile */
   int xsize, ysize, maxval;
   int raw_val;
   char sbuf[512],dummy[2];
   char *junk;
   unsigned char fbin;                            /* PGM binary format flag */
   unsigned char oneb;                            /* one byte from file */
   FILE *fp;

   /* open the .pgm file for reading */
   fp = fopen(filename,"rb");
   if (fp==NULL) {
      fprintf(stderr,"Could not open input file %s\n",filename);
      exit(0);
   }
   fprintf(stderr,"Opening file %s\n",filename);

   /* read the header */
   if (fread(&sbuf,sizeof(char),2,fp) != 2) {
      fprintf(stderr,"   Could not read file, exiting.");
      return(1);	/* unsuccessful */
   } else {
      sbuf[2] = 0x00;
      fprintf(stderr,"   Initial file string: %s\n",sbuf);
   }

   fbin = 0;		/* assume PGM ascii */
   if (strcmp(sbuf,"P5") == 0) fbin = 1; /* PGM binary format */

   if ((strcmp(sbuf,"P5") != 0) && (strcmp(sbuf,"P2") != 0)) {
      fclose(fp);	/* close file, suck. */
      return(1);	/* unsuccessful */
   }

   /* file is PGM, either P5 (binary) or P2 (ascii) */

   while ((fscanf(fp,"%s",sbuf) != EOF) && sbuf[0] == '#') {
      /* fprintf(stderr,"comment:"); */
      fscanf(fp,"%[^\n]",sbuf);  /* read comment beyond '#' */
      fscanf(fp,"%[\n]",dummy);  /* read newline */
      fprintf(stderr,"   #%s\n",sbuf);            /* display comment */
   }

   xsize = (int) strtoul(sbuf, &junk, 10); /* cvt. xsize of array */
   fscanf(fp,"%s",sbuf);                 /* read ysize of array */
   ysize = (int) strtoul(sbuf, &junk, 10); /* cvt. ysize */
   fscanf(fp,"%s",sbuf);               /* read maxval of array */
   maxval = strtod(sbuf, &junk);

   fprintf(stderr,"   xsize %d  ysize %d  maxval %d\n",xsize,ysize,maxval);

   /* check size, make sure its not too big */
   if (xsize > MAX_SIZE) write_error("Input image width is too large.",1);
   if (ysize > MAX_SIZE) write_error("Input image height is too large.",1);

   points_read = 0;              /* haven't read any data points yet */
   npoints = xsize*ysize;
   ix = 0;
   iy = 0;                       /* fill array 0..xsize-1, 0..ysize-1 */

   fprintf(stderr,"   reading in...");
   if (fbin) {
      fread(&oneb,sizeof(unsigned char),1,fp);	/* read that line feed */
      while ((fread(&oneb,sizeof(unsigned char),1,fp) == 1) && (points_read < npoints) ) {
         a[iy][ix] = (unsigned short int) oneb;
         if (++ix > xsize-1) {
            ix = 0;
            iy++;
         }
         ++points_read;
      } /* end while not end-of-file */
   } else {
      while ((fscanf(fp,"%s",sbuf) != EOF) && (points_read < npoints) ) {
         /* a = strtod( sbuf, &junk); */
         a[iy][ix] = (unsigned short int)atoi(sbuf);
         if (++ix > xsize-1) {
            ix = 0;
            iy++;
         }
         points_read++;
      }
   } /* end if fbin */

   fprintf(stderr,"%lu elements read.\n",points_read);
   if (points_read != npoints) {
      fprintf(stderr,"   Warning: %lu points missing.\n",npoints-points_read);
   }
   fclose(fp);
   fprintf(stderr,"   Files closed.\n");

   inheight = ysize;
   inwidth = xsize;

   /* everything went OK, return zero */
   return(0);
}


/*
 * Read a Poskanzer GrayMap (.PGM) file and save in array hf[][]
 * This subroutine uses code from John Beale's er1u/inout.c
 */
int read_pgm_char(char filename[80],unsigned char a[MAX_SIZE][MAX_SIZE]) {

   int i,j;
   int ix,iy;
   int npoints;            /* # points that should be in file */
   int points_read;        /* # points read from hf datafile */
   int xsize, ysize, maxval;
   int raw_val;
   char sbuf[512],dummy[2];
   char *junk;
   unsigned char fbin;                            /* PGM binary format flag */
   unsigned char oneb;                            /* one byte from file */
   FILE *fp;

   /* open the .pgm file for reading */
   fp = fopen(filename,"rb");
   if (fp==NULL) {
      fprintf(stderr,"Could not open input file %s\n",filename);
      exit(0);
   }
   fprintf(stderr,"Opening file %s\n",filename);

   /* read the header */
   if (fread(&sbuf,sizeof(char),2,fp) != 2) {
      fprintf(stderr,"   Could not read file, exiting.");
      return(1);	/* unsuccessful */
   } else {
      sbuf[2] = 0x00;
      fprintf(stderr,"   Initial file string: %s\n",sbuf);
   }

   fbin = 0;		/* assume PGM ascii */
   if (strcmp(sbuf,"P5") == 0) fbin = 1; /* PGM binary format */

   if ((strcmp(sbuf,"P5") != 0) && (strcmp(sbuf,"P2") != 0)) {
      fclose(fp);	/* close file, suck. */
      return(1);	/* unsuccessful */
   }

   /* file is PGM, either P5 (binary) or P2 (ascii) */

   while ((fscanf(fp,"%s",sbuf) != EOF) && sbuf[0] == '#') {
      /* fprintf(stderr,"comment:"); */
      fscanf(fp,"%[^\n]",sbuf);  /* read comment beyond '#' */
      fscanf(fp,"%[\n]",dummy);  /* read newline */
      fprintf(stderr,"   #%s\n",sbuf);            /* display comment */
   }

   xsize = (int) strtoul(sbuf, &junk, 10); /* cvt. xsize of array */
   fscanf(fp,"%s",sbuf);                 /* read ysize of array */
   ysize = (int) strtoul(sbuf, &junk, 10); /* cvt. ysize */
   fscanf(fp,"%s",sbuf);               /* read maxval of array */
   maxval = strtod(sbuf, &junk);

   fprintf(stderr,"   xsize %d  ysize %d  maxval %d\n",xsize,ysize,maxval);

   /* check size, make sure its not too big */
   if (xsize > MAX_SIZE) write_error("Input image width is too large.",1);
   if (ysize > MAX_SIZE) write_error("Input image height is too large.",1);

   points_read = 0;              /* haven't read any data points yet */
   npoints = xsize*ysize;
   ix = 0;
   iy = 0;                       /* fill array 0..xsize-1, 0..ysize-1 */

   fprintf(stderr,"   reading in...");
   if (fbin) {
      fread(&oneb,sizeof(unsigned char),1,fp);	/* read that line feed */
      while ((fread(&oneb,sizeof(unsigned char),1,fp) == 1) && (points_read < npoints) ) {
         a[iy][ix] = (unsigned char) oneb;
         if (++ix > xsize-1) {
            ix = 0;
            iy++;
         }
         ++points_read;
      } /* end while not end-of-file */
   } else {
      while ((fscanf(fp,"%s",sbuf) != EOF) && (points_read < npoints) ) {
         /* a = strtod( sbuf, &junk); */
         a[iy][ix] = (unsigned char) atoi(sbuf);
         if (++ix > xsize-1) {
            ix = 0;
            iy++;
         }
         points_read++;
      }
   } /* end if fbin */

   fprintf(stderr,"%lu elements read.\n",points_read);
   if (points_read != npoints) {
      fprintf(stderr,"   Warning: %lu points missing.\n",npoints-points_read);
   }
   fclose(fp);
   fprintf(stderr,"   Files closed.\n");

   inheight = ysize;
   inwidth = xsize;

   /* everything went OK, return zero */
   return(0);
}
