// Author      : Josh Grant
// Course      : CIS5900, Computer Graphics, Fall 2000
// Assignment  : hw02
// Date        : September 18th, 2000
// Description : C++ implemtation file for the Image class. This class allows
//               someone to draw a dot or a series of dots to a ppm file by
//               using the class Pixel to keep track of each Pixel.  The dots
//               can be drawn with any number of filters available: box,
//               tent, cubic, quadric, quartic, or a 2D tent filter.  All the
//               filters depend on the class's member variable radius.  In
//               addition a line segment can be drawn with this class.
//               Several line segment functions including: A parametric,
//               explicit, implicit, integration, and subdivision recursion. 

#ifndef _IMAGE_CPP
#define _IMAGE_CPP

#include <math.h>
#include <image.h>
#include <iostream.h>

// Default constructor.  Set everything to zero.
Image::Image() {
  xDim   = 0;
  yDim   = 0;
  xMax   = 0.0;
  xMin   = 0.0;
  yMax   = 0.0;
  yMin   = 0.0;
  pixels = NULL;
}

// Additional Constructor.  This constructor must be called in order to get
// the Image class to actually do anything.
Image::Image(int XDIM, int YDIM, double XMAX, double XMIN,
	     double YMAX, double YMIN) {
  xDim   = XDIM;
  yDim   = YDIM;
  xMax   = XMAX;
  xMin   = XMIN;
  yMax   = YMAX;
  yMin   = YMIN;

  // create an array of Pixel objects that the pixels pointer points to.
  pixels = new Pixel[xDim*yDim];
}

// Give back the memory taken by the new statement above.
Image::~Image() {
  delete [] pixels;
}

// Sets a pixel at a given x, y, z to a certain r, g, b.  All the surrounding
// <radius> pixels are colored based on the given r, g, b and the specified
// filter value.
int Image::setPoint(double myX, double myY, double myZ,
		    double myR, double myG, double myB,
		    double myW) {
  
  int x, y, index;

  x = (int)((myX - xMin)*(xDim - 1.0) / (xMax - xMin));
  y = (int)((myY - yMin)*(yDim - 1.0) / (yMax - yMin));

  index = y*xDim + x;
  
  if (index >= xDim*yDim || index < 0)
    return 0;

  pixels[index].x      += myX * myW;
  pixels[index].y      += myY * myW;
  pixels[index].z      += myZ * myW;
  pixels[index].red    += myR * myW;
  pixels[index].green  += myG * myW;
  pixels[index].blue   += myB * myW;
  pixels[index].weight += myW;

  return 1;
}

int Image::setPixel(double myX, double myY, double myZ, 
		    double myR, double myG, double myB,
		    double myW, int index) {
  
  if (index >= xDim*yDim || index < 0)
    return 0;

  pixels[index].x      += myX * myW;
  pixels[index].y      += myY * myW;
  pixels[index].z      += myZ * myW;
  pixels[index].red    += myR * myW;
  pixels[index].green  += myG * myW;
  pixels[index].blue   += myB * myW;
  pixels[index].weight += myW;

  return 1;
}

void Image::writePPM(ostream &os) {
  int yIndex, xIndex, index;

  cout << "P3" << endl;
  cout << xDim << " " << yDim << endl;
  cout << 255 << endl;
  cout << endl;

  for (yIndex = yDim - 1; yIndex >= 0; yIndex--) {
    for (xIndex = 0; xIndex < xDim; xIndex++) {
      index = yIndex*xDim + xIndex;
      pixels[index].writePPM(os);
    }
    cout << endl;
  }
}

void Image::writePPM(fstream &os) {
  int yIndex, xIndex, index;

  cout << "P3" << endl;
  cout << xDim << " " << yDim << endl;
  cout << 255 << endl;
  cout << endl;

  for (yIndex = yDim - 1; yIndex >= 0; yIndex--) {
    for (xIndex = 0; xIndex < xDim; xIndex++) {
      index = yIndex*xDim + xIndex;
      pixels[index].writePPM(os);
    }
    cout << endl;
  }
}

#endif