#include <stdio.h>
#include <conio.h>
#include <graphics.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

void maketables (void);
double sint(int X);
double cost(int X);

class screen
 {
  //   Purpose: This class implements the interface to the graphics screen device. It performs some
  // clipping (It will not draw beyond the screen border). The parameter m for the constructor has
  // no purpose at this time, but in the future it will be used to turn double buffering on and off.
  //
  int vispage,
      active;

  public:
	screen(int m);  // Initialize the graphics system into 640x350 16 color mode.
	screen();
	~screen();      // Close the graphics system.
	void open(int m);
	void close(void); // Close the graphics system.
	void plot(long x,long y, int c); // Plot a point at [x,y] in color c.
	void sline(long x1, long y1, long x2, long y2, int c); // Draw a line from [x1,y1] to [x2,y2] in color c.
	void sfillpoly(int num_points, int *points, int fc, int bc); // Draws a filled polygon of color fc and border bc.
	void clear(int c); // Clear the screen to color c.
	void swap(void);
 };

struct point
 {
  //  This structure holds the [x,y,z] data for points and vectors, and some common routines.
  //
  float x,y,z;

  point(float X=0,float Y=0,float Z=0) // assigns values at construction.
	{x=X;y=Y;z=Z;};
  void normalize(void); // Normalizes a vector.
  point &operator = (point &P) // Allows direct assignment.
	{x=P.x;y=P.y;z=P.z;return *this;};
 };

struct polyNODE // Used in the linked list of points in the polygon.
 {
  point P;
  polyNODE *Next;
 };


class polygon
 {
  //  This class is a general n sided polygon. It contains a linked list of points that comprise the
  // polygon, as well as the polygons color.
  //

  friend class Viewport3D;
  protected:
	polyNODE *list;
	int color;
	void dellist(void); //  Deletes the linked ilst of points.

  public:
	polygon();  // Create a polygon object.
	~polygon(); // delete a polygon object and free its memory.
	int addpoint (point &P); // Adds a point to the end of the list for the polygon.
	void chgcolor(int c) {color=c;}; // Changes the polygons color.
	void translate(float x, float y, float z); // Moves the polygon (in polygon space).
	void rotate(int t, int p, int a); // rotates the polygon around the origin (in polygon space).
	void scale(float s); // Scales the polygon (in polygon space).
	float getdist(point &P); // Gets the distance of the center of the polygon with reference to point P.
	void getcenter(point &C); // Gets the coordinates of the center of the polygon and puts it into C.
	void getnormal(point &N); // Gets the normal vector to the polygon and puts it in N.
	polygon &operator =(polygon &P); // Allows assignment of one polygon to another.
 };


struct playerNODE   // This is used in the linked list of polygons in the player class.
 {
  polygon P;
  playerNODE *Next;
 };

struct orderNODE
 {
  polygon *p;
  orderNODE *next;
 };

class player
 {
  friend class Viewport3D;
  protected:
	playerNODE *list;            // The list of polygons.
	orderNODE *orderings[8];     // Linked list of pre-ordered polygons.
	float X,Dx,                  // The X position and X velocity.
	      Y,Dy,        // The Y position and Y velocity.
	      Z,Dz,        // The Z position and Z velocity.
	      T,           // The Heading, rotation around X axis, CW, looking in.
	      P,           // The Heading, rotation around Y axis, CW, looking in.
	      A;           // The Heading, rotation around Z axis, CW, looking in.
	void delorderlist(orderNODE *l);

  public:
	player(float x=0, float y=0, float z=0);      // Creates a player
	~player();                                    // Deletes a player and all allocated memory.
	void dellist(void);                           // Deletes the linked list.
	int  addpoly(polygon &P);                     // Adds a polygon to the list.
	void move(void);                              // Moves the player in world space. (uses velocity).
	void chgvel(float ddX, float ddY, float ddZ); // Changes the velocity variables.
	void moveto(float X, float Y, float Z);       // Moves the player to [X,Y,Z] in world space.
	void translate(float X, float Y, float Z);    // Translates the player X,Y,Z in world space.
	void rotate(int t, int p, int a);             // Rotates the object around its origin t,p,a degrees.
	void rotateto(int t, int p, int a);           // Rotates the player to the specified angles.
	void scale(float pcnt);                       // Sclales the player.
	int  setorder(int view, int *ordering);       // Sets a polygon sorting order for a particular view.
	int  getorder(point &Origin);                 // Re-orders the polygon (depth sort).
	point getpos(void);                           // Returns the position of the center of the aircraft.
	player &operator = (player &P);               // Allows assignment of one player to another.
  };

class Viewport3D :public screen
 {
  //  This class is a higher level interface to the graphics system. Unlike the screen class, this
  // class implements a 3-D viewport into world space.
  //

  protected:
	point No,                 // Normal vector from Vp to Rp.
	      Vp,                 // View point.
	      Rp,                 // Reference point.
	      Ud,                 // Up direction.
	      X1,                 // Defines the line that Vp is rotated up and down around.
	      X2,
	      LastT,
	      LastB,
	      LastR,
	      LastL,
	      LastN;
	float Dist;               // Distance from Vp to Rp.
	float VPT_Matrix[4][4];   // The view plane tranformation matrix.
	void make_vpt_matrix(void);   // Calculates the new transform matrix.
	void make_identity(float matrix[4][4]); // clears matrix to an identity matrix.
	void matrix_multiply(float matrix1[4][4], float matrix2[4][4]); // Multiplys 2 4x4 mareices.
	void transform(point &P); // Transforms P by the transformation matrix.
	char GetRCode(point &P);
	int Clip_Line(point &P1, point &P2);
	void Clip_Poly_L (point &P, polygon &Po);
	void Clip_Poly_R (point &P, polygon &Po);
	void Clip_Poly_T (point &P, polygon &Po);
	void Clip_Poly_B (point &P, polygon &Po);
	void Clip_Poly_N (point &P, polygon &Po);
	int Clip_Poly(polygon &Pi, polygon &Po);
  public:
	Viewport3D (int mode);  // Creates a viewport.
	~Viewport3D();          // deletes a viewport.
	void translateR(float x, float z); // Moves the reference point and view point by [X,Y,Z].
	void scaleD(float s);              // Increces the distance between Vp and Rp.
	void rotateY(int P);               // Rotates Vp around Rp (Y axis rotation).
	void rotateUD(int t);              // Rotates Vp around Rp (up and down).
	int poly_visible(polygon &P);      // If the polygon should be drawn, returns 1 and 0 otherwise.
	int player_visible(player &P);     // If the player should be drawn, returns 1 and 0 otherwise.
	point getvp(void)                  // Returns the position of the viewpoint.
	 { return Vp; };
	void drawline(float x1, float y1, float z1, float x2, float y2, float z2, int c); // Draws a 3-D line.
	void drawpoly(float x, float y, float z, polygon &P); // Draws a 3-D polygon. (wireframe)
	void drawfillpoly(float x, float y, float z, polygon &P); // Draws a 3-D polygon. (solid filled)
	void drawplayer(player &P);      // Draws a player.
  };