/*
*
* Name:        ppm2sfimg.c
*
* Purpose:     conversion of PPM to SFImage
*
* Created:     20 Oct 95   Michael Pichler
*
* Changed:     20 Oct 95   Michael Pichler
*
*/

/*
*
* This program reads a PPM file (raw format) and writes out a
* Texture2 SFImage with 3 components (RGB)
*
* The usual disclaimer applies (see VRweb's COPYRIGHT notice)
*
* Compile this program with any Ansi-C compiler.
* E.g.: gcc -O -Wall -o ppm2sfimg ppm2sfimg.c
*
* Please send further questions to [email protected]
*
*/


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

/* define this to dump input and output data to stderr */
/*#define DEBUGOUTPUT*/

#define USAGE "\nusage: ppm2sfimg [ppmfile] [> outputfile]\n" \
 "ppmfile ... PPM raw file (default: stdin)\n" \
 "output (RGB Texture2 image) is written to stdout\n\n"


typedef struct
{ unsigned char R, G, B;
} colorRGBi;


int sourceRows = 0;
int sourceCols = 0;
int maxColor = 0;
colorRGBi** sourcePPM = 0;  /* source pixel */

void readSourcePPM (FILE*);
void writeSFImage ();  /* to stdout */


/* tiny helper */

void checkformem (void* p)
{ if (!p)
 { fprintf (stderr, "fatal error: out of memory\n");
   exit (2);
 }
}


/***** main *****/

void main (int argc, char* argv[])
{
 FILE* file;

 if (argc > 2)
 { fprintf (stderr, USAGE);
   exit (0);
 }

 if (argc > 1)
 {
   const char* filename = argv [1];

   file = fopen (filename, "rb");
   if (!file)
   { fprintf (stderr, "ssppm. error: could not open file '%s'" USAGE, filename);
     exit (1);
   }
 }
 else
   file = stdin;

 readSourcePPM (file);
 fclose (file);
 writeSFImage ();

} /* main */


/*** skipComment ***/
/* skip comment lines (beginning with '#') and empty lines */

void skipComment (FILE* file)
{
 for (;;)
 {
   int chr = getc (file);
   switch (chr)
   {
     case '#':  /* skip comment line */
     {
       int c;
       while ((c = getc (file)) != '\n' && c != EOF);
     }
     break;

     case '\n':
     break;

     case EOF:  /* end of file */
     return;

     default:  /* data line */
       ungetc (chr, file);
     return;
   }
 } /* for */
} /* skipComment */


/***** readSourcePPM *****/
/* reads source PPM file (raw bits P6) */

void readSourcePPM (FILE* file)
{
 int error, nextchar, row;

 skipComment (file);
 if (getc (file) != 'P' || getc (file) != '6')
 {
   fprintf (stderr, "ppm2sfimg. sorry, only able to deal with binary PPM files (header P6)\n");
   exit (1);
 }
 skipComment (file);
 error = fscanf (file, "%d", &sourceCols) != 1;
 skipComment (file);
 error = error || fscanf (file, "%d", &sourceRows) != 1;
 skipComment (file);
 error = error || fscanf (file, "%d", &maxColor) != 1 || !maxColor;
 nextchar = getc (file);  /* eat (exactly) one WS */
 error = error || (nextchar != '\n' && nextchar != ' ' && nextchar != '\t');

 if (error)
 { fprintf (stderr, "syntax error in PPM header - expected format:\n"
            "'P5 width height maxcolor' followed by one whitespace and pixel bytes\n");
   exit (1);
 }
 fprintf (stderr, "reading PPM of size %d x %d with RGB triples in range [0..%d].\n",
          sourceCols, sourceRows, maxColor);

 sourcePPM = (colorRGBi**) calloc (sourceRows, sizeof (colorRGBi*));
 checkformem (sourcePPM);

 for (row = 0;  row < sourceRows;  row++)
 {
   int col;
   colorRGBi* thisrow = sourcePPM [row] = (colorRGBi*) calloc (sourceCols, sizeof (colorRGBi));
   checkformem (thisrow);

   for (col = 0;  col < sourceCols;  col++)
   {
     int pixelval = getc (file);
     if (pixelval == EOF)
     { fprintf (stderr, "unexpected EOF on reading PGM file.");
       exit (1);
     }
     thisrow->R = pixelval;
     thisrow->G = getc (file);
     thisrow->B = getc (file);
     thisrow++;
   } /* for each col */
 } /* for each row */

 /* for testing purposes: dump data to stderr */
#ifdef DEBUGOUTPUT
 fprintf (stderr, "- input data -\n");
 for (row = 0;  row < sourceRows;  row++)
 { for (int col = 0;  col < sourceCols;  col++)
   {
     const colorRGBi* pixel = sourcePPM [row][col];
     fprintf (stderr, "(%3d, %3d, %3d) ", pixel->R, pixel->G, pixel->B);
   }
   fprintf (stderr, "\n");
 }
 fprintf (sderr, "- end of input data -\n");
#endif

} /* readSourcePGM */



/***** writeSFImage *****/
/* write SFImage data to stdout */

void writeSFImage ()
{
 int row, col;
 unsigned long value;

 if (!sourcePPM)
   return;

 printf ("Texture2 { # created with ppm2sfimg\n");
 printf ("\timage %d %d 3\n", sourceCols, sourceRows);  /* 3 components (RGB) */

 if (maxColor != 255)
 { fprintf (stderr, "ppm2sfimg. error: sorry, assuming color range of 0..255\n");
   exit (1);  /* just a scale in loop below, TODO */
 }

 row = sourceRows;
 while (row--)  /* bottom to top */
 {
   const colorRGBi* thisrow = sourcePPM [row];

   printf ("\t");
   col = sourceCols;
   while (col--)
   {
     value = ((long) thisrow->R << 16) | ((int) thisrow->G << 8) | thisrow->B;

     if (thisrow->R)  /* hex representation (better readable) */
       printf ("0x%lx ", value);
     else  /* decimal (shorter up to 999999) */
       printf ("%ld ", value);

     thisrow++;
   } /* for each col */

   printf ("\n");
 } /* for each row */

 printf ("}\n");  /* Texture2 image */

} /* writeDestinationPPM */