/****************************************************************************
*                pgm.c
*
*  This module contains the code to read the PGM file format.
*
*  from Persistence of Vision(tm) Ray Tracer
*  Copyright 1996 Persistence of Vision Team
*---------------------------------------------------------------------------
*  NOTICE: This source code file is provided so that users may experiment
*  with enhancements to POV-Ray and to port the software to platforms other
*  than those supported by the POV-Ray Team.  There are strict rules under
*  which you are permitted to use this file.  The rules are in the file
*  named POVLEGAL.DOC which should be distributed with this file. If
*  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
*  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
*  Forum.  The latest version of POV-Ray may be found there as well.
*
* This program is based on the popular DKB raytracer version 2.12.
* DKBTrace was originally written by David K. Buck.
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
*
* Original patch copyright 1994 Tim Rowley
* Updated for POV 3.0 by Chris Cason, Jan '95.
*
*****************************************************************************/

/****************************************************************************
*  The format is as follows:
*
*  (header:)
*    P2              - ASCII data in file OR
*    P5              - binary data in file
*    # hello         - comment (optional, may be multiple)
*    wwww hhhh       - Width, Height (ASCII text)
*    # world         - comment (optional, may be multiple)
*    nnn             - maximum color (nnn = white, 0 = black)
*
*  (each pixel: one of the following)
*    xx               - Intensity 0-nnn (binary byte)
*    AAA              - Intensity 0-nnn (ASCII number)
*
*****************************************************************************/

#include "frame.h"
#include "povproto.h"
#include "povray.h"
#include "pgm.h"
#include "ppm.h"

/*****************************************************************************
*
* FUNCTION
*
*  Read_PGM_Image
*
* INPUT
*   
* OUTPUT
*   
* RETURNS
*   
* AUTHOR
*   
* DESCRIPTION
*
* CHANGES
*     Modified to support ASCII files, comments, and arbitrary bit depth [AED]
*
******************************************************************************/

void Read_PGM_Image(Image, name)
IMAGE *Image;
char *name;
{
  char type;
  int width, height;
  int depth;
  char input;
  char junk[512];
  int x, y;
  int data;
  FILE *infile;

  if ((infile = Locate_File(name,READ_FILE_STRING,".pgm",".PGM",TRUE)) == NULL)
  {
    Error ("Cannot open PGM image %s.\n", name);
  }

  if (fscanf(infile,"P%c\n",&type) != 1 || (type != '2' && type != '5'))
  {
    Error ("File is not in PGM format.\n");
  }

  /* Ignore any comments */
  while ((input = fgetc(infile)) == '#')
  {
    fgets(junk,512,infile);
  }

  ungetc(input,infile);

  if (fscanf(infile,"%d %d\n",&width,&height) != 2)
  {
    Error ("Error reading width or height from PGM image.\n");
  }

  /* Ignore any comments */
  while ((input = fgetc(infile)) == '#')
  {
    fgets(junk,512,infile);
  }

  ungetc(input,infile);

  if (fscanf(infile,"%d\n",&depth) != 1 ||
      (depth > 255 && type == '5') ||
      depth > 65535 || depth < 1)
  {
    Error ("Unsupported number of colors (%d) in PGM image.\n", depth);
  }


  Image->width  = (DBL)(Image->iwidth  = width);
  Image->height = (DBL)(Image->iheight = height);

  if (depth < 256)
  {
    Image->Colour_Map_Size = depth;

    Image->Colour_Map = (IMAGE_COLOUR *)POV_MALLOC(depth*sizeof(IMAGE_COLOUR), "PGM color map");

    for (x = 0; x < depth; x++)
    {
      Image->Colour_Map[x].Red =
      Image->Colour_Map[x].Green =
      Image->Colour_Map[x].Blue = x*255/depth;
      Image->Colour_Map[x].Filter =0;
      Image->Colour_Map[x].Transmit =0;
    }

    Image->data.map_lines = (unsigned char **)POV_MALLOC(height*sizeof(unsigned char *), "PGM image");

    for (y = 0; y < height; y++)
    {
      Image->data.map_lines[y] = (unsigned char *)POV_MALLOC(width,"PGM image line");

      if (type == '2') /* ASCII data to be input */
      {
        for (x = 0; x < width; x++)
        {
          if (fscanf(infile,"%d",&data) != 1)
          {
            Error ("Error reading data from PGM image.\n");
          }
          Image->data.map_lines[y][x] = data;
        }
      }
      else /* (type == '5') Raw binary data to be input */
      {
        for (x = 0; x < width; x++)
        {
          if ((data = getc(infile)) == EOF)
          {
            Error ("Error reading data from PGM image.\n");
          }
          Image->data.map_lines[y][x] = data;
        }
      }
    }
  }
  else /* if(depth < 65536) the data MUST be in ASCII format */
  {
    IMAGE_LINE *line_data;

    Image->Colour_Map_Size = 0;
    Image->Colour_Map = (IMAGE_COLOUR *)NULL;

    Image->data.rgb_lines = (IMAGE_LINE *)POV_MALLOC(height * sizeof(IMAGE_LINE), "PGM image");
    for (y = 0; y < height; y++)
    {
      line_data = &Image->data.rgb_lines[y];

      line_data->red   = (unsigned char *)POV_MALLOC(width, "PGM image line");
      line_data->green = (unsigned char *)POV_MALLOC(width, "PGM image line");
      line_data->blue  = (unsigned char *)POV_MALLOC(width, "PGM image line");
      line_data->transm = (unsigned char *)NULL;

      for (x = 0; x < width; x++)
      {
        if (fscanf(infile,"%d",&data) != 1)
        {
          Error("Error reading data from PGM image.\n");
        }

        data = (int)((DBL)data*65535/depth);

        line_data->red[x] = (data >> 8) & 0xFF;
        line_data->green[x] = data & 0xFF;
        line_data->blue[x] = 0;
      }
    }
  }

  fclose(infile);
}
