#ifndef _GEOMOBJECT_H__
#define _GEOMOBJECT_H__

//
// Object
//
class GeomObject {
  
public:
  GeomObject         ( void );
  
  // pure virtuals - necessary to overload
public:
  virtual int        intersectWithRay      ( const Point3&, 
					     const Point3&, Point3& ) = 0;
  virtual int        nearestToRay          ( const Point3&,
					     const Point3&, Point3& ) = 0;
  virtual int        nearestToPoint        ( const Point3&, Point3& ) = 0;
  virtual int        normalAtPoint         ( const Point3&, Vector3& ) = 0;
  virtual void       bounds                ( Point3&, Point3& ) = 0;
  virtual int        update                ( const Point3&, const Point3& ) = 0;
  virtual void       draw                  ( void ) = 0;                   
  virtual void       drawBounds            ( void ) = 0;  

  // virtuals - not necessary to overload
public:
  virtual void       setPosition           ( const Point3& );
  virtual void       setColor   ( float r, float g, float b )
  { _col[0] = r; _col[1] = g; _col[2] = b; };
  virtual void       attach                ( GeomObject* c ) { _constraint = c; };

  // protected: // XXX these should be protected, with real access methods
  Point3            _pos;                  // object position (usually centroid)
  Color3            _col;                  // a distinct color for object
  GeomObject       *_constraint;           // object to which it is constrained, if any

};

//
// Sphere
//
class Sphere: public GeomObject {
  
public:
  Sphere                                   ( float radius = 1.f, 
					     int nlunes = 16, 
					     int nbands = 16 );
  
public:
  virtual int        intersectWithRay      ( const Point3&, 
					     const Point3&, Point3& );
  virtual int        nearestToRay          ( const Point3&, 
					     const Point3&, Point3& );
  virtual int        nearestToPoint        ( const Point3&, Point3& );
  virtual int        normalAtPoint         ( const Point3&, Vector3& );
  virtual void       bounds                ( Point3&, Point3& );
  virtual int        update                ( const Point3&, const Point3& );
  virtual void       draw                  ( void );
  virtual void       drawBounds            ( void );

private:
  float              _radius;
  int                _nlunes;              // # sections of constant longitude
  int                _nbands;              // # sections of constant latitude
  GLUquadricObj     *_sphereQuadric;
};

//
// XYRect : rectangle of given width, height on plane of constant z
//
class XYRect : public GeomObject {
  
public:
  XYRect                                   ( float, float );
  
public:
  virtual int        intersectWithRay      ( const Point3&, 
					     const Point3&, Point3& );
  virtual int        nearestToRay          ( const Point3&, 
					     const Point3&, Point3& );
  virtual int        nearestToPoint        ( const Point3&, Point3& );
  virtual int        normalAtPoint         ( const Point3&, Vector3& );
  virtual void       bounds                ( Point3&, Point3& );
  virtual int        update                ( const Point3&, const Point3& );
  virtual void       draw                  ( void );
  virtual void       drawBounds            ( void );

private:
  float              _width, _height;

};

//
// RandomMeshscape
//
class RandomMeshscape : public GeomObject {
  
public:
  RandomMeshscape                          ( float size = 1.f,    // the width, height & depth of grid
					     int nribs = 16 );    // # of columns/rows in grid
  
public:
  int        intersectWithRay      ( const Point3&, 
					     const Point3&, Point3& );
  int        nearestToRay          ( const Point3&, 
					     const Point3&, Point3& );
  int        nearestToPoint        ( const Point3&, Point3& );
  int        normalAtPoint         ( const Point3&, Vector3& );
  void       bounds                ( Point3&, Point3& );
  int        update                ( const Point3&, const Point3& );
  void       draw                  ( void );
  void       drawBounds            ( void );
  
  
private:
  float              _size;               // the width, height & depth of grid
  int                _nribs;              // # of columns/rows in grid
  float            **_depth;              // array of depths
  float              _inc;                // width of squares...made internal for speed
  float            **_squaremaxs;        // internal array of heights...precomputed for speed
  float            **_squaremins;        // internal array of heights...precomputed for speed

private:   // some accessor functions for doing searches
  void       getSquareHeights            (int, int, float *, float *, float *, float *);
  float      getSquareYTop               (int);
  float      getSquareYBottom            (int);
  float      getSquareXLeft              (int);
  float      getSquareXRight             (int);
  void       getSquareVertices           (int, int, float *, float *, float *, float *);
  int        checkheight                 (int x, int y, const Point3& eye, const Point3& far);
  void       getBoundingSquares          (int* square1, int* square2, float m, float b);
  int        validSquare                 (int x,int y);
  int first(float* pt1, float* pt2, const Point3& e, const Point3& f);
  void cross_product(float* v1, float* v2, float* cross);
  int left_on(float* pt1, float* pt2, float* pt3, int dir);
  int inside_triangle(float* pt1,float* pt2,float* pt3,float* intersectPt,int dir);
  int intersect_plane(float* pt1, float* pt2, float* pt3, float* intersectPt,
		      const Point3& e, const Point3& f);
  int intersect_triangle(float* pt1, float* pt2, float* pt3, float* intersectPt,
			 const Point3& eye, const Point3& far);
  int checkbox(int x, int y, float* intersectPt, const Point3& eye, const Point3& far);
  int                debug; // flag to turn on/off couts
  int debug_checkheight;
  int debug_checkbox;
  int debug_intersect_triangle;
  int debug_intersectWithRay;
  int debug_setPixel;
  float magnitude(float* vec);
  float area(float* pt1, float* pt2, float* pt3);
  void normalize(float* vec);
  void setPixel(int x, int y, float* ipt, float* newPt, float* eyer, float* farr);
  void do_bresenham(float m, float b, int x1, int y1, int x2, int y2
, float* ipt, float* newPt, float* eyer, float* farr);
  int bx1; // next 4 are to debug projected eye/far box endpoints
  int by1;
  int bx2;
  int by2;
  void drawbox(int x, int y, int col, float z1, float z2);
  int ***boxes; // xpos,ypos -> 1. chosen by bres 2. chosen by checkheight 3. intersection
  void assign_3vec(float* dest, float* src);
  int find_major_dir(const Point3& eye, const Point3& far);
  float area2(float* a, float* b, float* c);
  int _intersect;
  void drawTriangle(int x, int y, int tri);
  float hypotenuse(float x, float y);

  // eye/far projected onto z=0
  float  segx0;
  float  segx1;
  float  segy0;
  float  segy1;

  // eye in world coords
  float  eyex;
  float  eyey;
  float  eyez;

  // far in world coords
  float  farx;
  float  fary;
  float  farz;
};

#endif
