/*
 *
 * 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 vrweb-bugs@iicm.tu-graz.ac.at
 *
 */


#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 */
