// Ray-tracing engine definitions

#include <stdlib.h>

// A classic vector

typedef double Vector[3];

// some defines to refer to it

#define X 0
#define Y 1
#define Z 2


// A light source

class LightSource
{
  public:
    int Intensity;
    double Red, Green, Blue;
    Vector position;
    LightSource *next;
    
    LightSource(double x, double y, double z, double r, double g, double b);
};


// This abstract class represents objects in the virtual world that we are going to depict

class Object
{
  public:
    
    float Red, Green, Blue;	// amount of red, green and blue light diffusely reflected
    float reflect;
    Object *next;

    // Constructor
    
    Object()
    {
        next = 0;
        
        // Make it white
        Red = 1.0;
        Green = 1.0;
        Blue = 1.0;
        reflect = 0.0;
    }
    
    // Abstract function which finds the intersection of a ray with the object
    
    virtual int Intersect(Vector From, Vector Direction, Vector &Intersection, double &Distance,
        Vector &Normal)=0;    
};


// Derive some real objects from the above abstract class

class Sphere : public Object
{
  public:
    double radius;
    Vector Center;
    
    Sphere(double x, double y, double z, double rad, double r, double g, double b, double ref);
    virtual int Intersect(Vector From, Vector Direction, Vector &Interesction, 
        double &Distance, Vector &Normal);
};

class BoundedPlane : public Object
{
  public:
    double A,B,C,D;
    double X1, X2, Y1, Y2, Z1, Z2;
    
    BoundedPlane(double a, double b, double c, double d, double x1, double x2, double y1,
        double y2, double z1, double z2, double r, double g, double bl, double ref);
    virtual int Intersect(Vector From, Vector Direction, Vector &Interesction, 
        double &Distance, Vector &Normal);
};


// The RayTracer as a class

class RayTracer
{
  public:
    int Width;				// Width of the the viewing frame in pixels
    int Height;				// Height of the viewing frame in pixels
    Object *FirstObject;	// List of objects in the virtual world
    LightSource *FirstLight;// List of light sources in the virutal world
    Vector ViewVector;		// Direction to view the current pixel
	double ViewWidth;		// Width of film over the focal length essentially, determines
							// whether we are viewing wide-angle or telephoto
    double ViewingAngle;	// Angle from the origin to the viewing position
    double sVA, cVA;		// sine and cosine of that angle

	    
    // This guy does a ray trace
    void Trace(Object *ObjectList, LightSource *LightList, int w, int h,
        Vector ViewPos);
        
    // This traces the light along a single path, including refletionns
    void ViewARay(Vector ViewPos, Vector ViewDir, int Depth, double &Reg, double &Green, double &Blue);
        
    // Call back which sets a pixel on the screen, the ray tracer engine does not bother
    // with such mundane details
    
    virtual void SetPixel(int x, int y, int r, int g, int b) = 0;
    
  private:
    
    // Compute a view direction vector for a particular pixel on the film
    
    void ComputeViewVector(int x, int y);
    
    // Find the nearest object that intersects with a a viewing vector.  Also returns
    // the point of intersection, distance away, and a unit vector normal to the surface
    
    Object *FindNearestObject(Vector ViewPos, Vector ViewVector, Vector &Intersection,
        double &Distance, Vector &Normal);
        
    // Get the light hitting an object, broken down into red, green and blue
    
    void GetLight(Vector Point, Vector Normal, double &r, double &g, double &b);
    
};
