/*
    GL-117
    Copyright 2001, 2002 Thomas A. Drexl aka heptargon

    This file is part of GL-117.

    GL-117 is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    GL-117 is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with GL-117; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/* This file includes the memory representation of any 3D model. */

#ifndef IS_MODEL_H
#define IS_MODEL_H

#include "common.h" // ok

#include "vertexarray.h" // ok

/* Currently models are normalized to the (-1,-1,-1)-(1,1,1) cube and static!
   The model represents the "class" description of a static model's geometry and colors.
   It is "instanciated" using a DynamicObj which has a reference to the model,
   scaling, rotation, translation, physical attributes...
   A model consists of several objects.
   Objects consist of vertices, quads, triangles, and one material. */

// CColor stores color information
class CColor
{
  public:
  unsigned char c [4]; // color information as vector, 32 bpp (floats would be faster for the vertex arrays)
  CColor ();
  CColor (CColor *col);
  CColor (short cr, short cg, short cb);
  CColor (short cr, short cg, short cb, short ca);
  ~CColor ();
  void setColor (CColor *col);
  void setColor (short cr, short cg, short cb, short ca);
  void setColor (short cr, short cg, short cb);
  bool isEqual (CColor *col); // compare colors
  void take (CColor *col); // copy data from col
};

// CTexture loads and stores a texture to memory
// To use a texture, it must be loaded and added to the OpenGL texture list using
//   gl->genTextureTGA();
// instead of this class!
class CTexture
{
  public:
  unsigned char *data; // texture color data as array, 32 bpp (RGBA? => see tga loader)
  char name [256]; // texture file name
  bool mipmap; // mipmapping on/off depending on gluBuildMipmaps
  int textureID; // texture ID of native GL code
  int width, height;
  // average values to substitute textured quads by colors for LOD:
  float texlight; // average of texture's overall brightness
  float texred; // average of texture's red
  float texgreen; // average of texture's green
  float texblue; // average of texture's blue
  int quality; // texture quality of native GL code
  bool alpha; // alpha blending necessary
  CTexture ();
  ~CTexture ();
  int loadFromTGA (char *fname, int quality, int alphatype, int mipmap); // called via gl->genTextureTGA()
  void getColor (CColor *c, int x, int y); // color of a special pixel
};

// CVector3 stores the components of a 3D vector (x,y,z)
class CVector3 
{
  public:
  float x, y, z; // coordinates, float on most systems faster than double
  CVector3 ();
  CVector3 (float x, float y, float z);
  CVector3 (CVector3 *v);
  void set (float x, float y, float z);
  void neg ();
  void add (CVector3 *v);
  void sub (CVector3 *v);
  void mul (float fac);
  void crossproduct (CVector3 *v);
  float dotproduct (CVector3 *v);
  float length ();
  void norm ();
  bool isEqual (CVector3 *v); // exactly equal in memory (no sense for comparisons)
  bool isEqual (CVector3 *v, float tol); // numerically equal, use a tolerance like 1E-8
  void take (CVector3 *v); // copy data from v
};

// CVector2 stores the components of a 2D vector, for texture purpose
class CVector2 
{
  public:
  float x, y; // coordinates
  void take (CVector2 *v); // copy data from v
  bool isEqual (CVector2 *v); // exactly equal in memory (no sense for comparisons)
  bool isEqual (CVector2 *v, float tol); // numerically equal, use a tolerance like 1E-8
};

// CVertex represents a vertex which may take inforamtion about color, location, normal, texture, number of surrounding triangles
class CVertex
{
  public:
  int triangles; // number of triangles this vertex belongs to
  CColor color; // color, used when displayed without textures
  CVector3 vector; // coordinates
  CVector3 normal; // normal vector interpolated of all surrounding triangles
  CVector2 tex; // 2D texture coordinates
  CVertex ();
  CVertex (CVertex *v);
  void addNormal (CVector3 *n); // the normal vector of a vertex can be calculated as average of all adjacent plane normals
  void addColor (CColor *c); // the color of a vertex can be calculated as average of all adjacent plane colors
  void take (CVertex *v); // copy data from v
};

extern double pitab; // pi=atan(1)
extern float sintab [360], costab [360]; // table for sine, cosine functions (obsolete, use COS(), SIN() instead)

// CRotation stores one (x,y,z)-rotation
class CRotation
{
  private:
  float rot [3] [3]; // rotation matrix
  public:
  short a, b, c; // rotation angles for each plane of the carthesian cosy
  CRotation ();
  ~CRotation ();
  void setAngles (short a, short b, short c);
  void addAngles (short a, short b, short c);
  void calcRotation ();
  float rotateX (CVector3 *v);
  float rotateY (CVector3 *v);
  float rotateZ (CVector3 *v);
  float getsintab (int a);
  float getcostabntab (int a);
  void take (CRotation *r);
};

// CTriangle stores references to the vertices of the triangle/face
class CTriangle
{
  public:
  CVertex *v [3]; // references to the three vertices
  void getNormal (CVector3 *n);
  void setVertices (CVertex *a, CVertex *b, CVertex *c);
};

// CQuad stores references to the vertices of the quad/square/face
class CQuad
{
  public:
  CVertex *v [4]; // references to the four vertices
  void getNormal (CVector3 *n);
  void setVertices (CVertex *a, CVertex *b, CVertex *c, CVertex *d);
};

// CMaterial stores the name, filename, color, and texture of a material
class CMaterial
{
  public:
  char name [255]; // unique name
  char filename [255]; // unique file name
  CColor color; // uniform color
  CTexture *texture; // reference to a texture (or NULL if there is no texture)
  float utile; // tiling coordinates
  float vtile;
  float uoffset; // texture offsets (the importer must calculate u/v due to offsets)
  float voffset;
  float uscale; // texture scaling (the importer must calculate u/v due to scaling)
  float vscale;
  float wrot; // rotation in degree (the importer must calculate u/v due to wrot)
  CMaterial ();
};

// CObject stores the material, vertices, and faces (triangles, quads) of an object
class CObject
{
  public:
  Uint16 numVertices;
  Uint16 numTriangles;
  Uint16 numQuads;
  Uint16 numTexVertex;
  CMaterial *material; // an object has one unique material
  bool hasTexture; // an object can have one unique texture
  char name [255]; // unique object name
  CVertex *vertex; // vertex list
  CTriangle *triangle; // triangle list
  CQuad *quad; // quad list
  CObject ();
  ~CObject ();
  int addVertex (CVertex *w); // used to construct objects
  void setColor (CColor *col);
};

// CModel stores the materials and objects of a model, the data structure is optimized for 3DS files
class CModel 
{
  private:
  // all private members are only used "temporarily" at runtime!
  int rotcol; // very special for flickering light sources, e.g. the engine's bright yellow color is rotated
  float light_ambient [4]; // special light source attributes
  float light_diffuse [4];
  float light_ambient2 [4];
  float light_diffuse2 [4];
  CVector3 tlnull;
  CRotation rotnull;
  VertexArray *va; // using a vertex array means more memory, but better performance

  public:
  char name [20]; // unique model name like "GL-117"
  int shading; // shading can be set to FLAT (0) or SMOOTH/GOURAUD (1)
  Uint16 numObjects; // number of objects (which have a unique material)
  Uint16 numMaterials; // number of materials (should be the same as the number of objects)
  bool displaylist; // enable using a display list
  CMaterial *material [100]; // materials, at most 100 (these are only pointers)
  CObject *object [100]; // objects, at most 100 (these are only pointers)
  bool nolight; // do not use light?
  bool alpha; // use alpha blending?
  int numRefpoints; // reference points for missiles
  CVector3 *refpoint; // obsolete
  float scale, scalex, scaley, scalez; // overall scaling of original 3DS coords
  // Note: the model is stored to (-1,-1,-1)-(1,1,1) in RAM, the SpaceObj tells about the scaling of a model
  float cubex, cubey, cubez; // surrounding cube (or radius of sphere) for simplified collision detection
  int list1, list2, list3; // display lists already generated for each type of draw() method

  CModel ();
  void setName (char *name);
  void addMaterial (CMaterial *material);
  void addObject (CObject *object);
  void addRefPoint (CVector3 *tl);
  ~CModel ();
  void setColor (CColor *col);
  void drawVertexNormals (CObject *cm, float zoom);
  int rotateColor (int n);
  void scaleTexture (float fx, float fy);
  // the drawing methods take the following parameters:
  // tl+tl2=translation, rot=rotation, lum=luminance (default 1.0), explode=radial translation (default 0)
  // draw everything
  void draw (CVector3 *tl, CVector3 *tl2, CRotation *rot, float zoom, float lum, int explode);
  // draw without GL lighting
  void draw2 (CVector3 *tl, CVector3 *tl2, CRotation *rot, float zoom, int explode);
  // draw without textures
  void draw3 (CVector3 *tl, CVector3 *tl2, CRotation *rot, float zoom, int explode);
  // draw without textures, different luminance
  void draw3 (CVector3 *tl, CVector3 *tl2, CRotation *rot, float zoom, float lum, int explode);
};

// CSphere represents an ellipsoid according to the CModel data structure
class CSphere : public CModel
{
  private:
  int random (int n);
  public:
  int segments; // segments on lateral angle, doubled for longitudinal angle
  float radius;
  float dx, dy, dz; // ellipsoid measures in the carthesian cosy
  CSphere ();
  CSphere (float radius, int segments, float dx, float dy, float dz);
  ~CSphere ();
  void init (float radius, int segments);
  void init (float radius, int segments, float dx, float dy, float dz, int randomized);
  void invertNormals (); // point outside/inside
  void setNorthPoleColor (CColor *c, float w); // see setPoleColor, phi=0, theta=90
  void setSouthPoleColor (CColor *c, float w);
  void setPoleColor (int phi, int theta, CColor *c, float w); // shade color over any pole
};

// Part of an ellipsoid
class CSpherePart : public CModel
{
  public:
  int segments; // segments on lateral angle, doubled for longitudinal angle
  float radius;
  CSpherePart ();
  CSpherePart (float radius, int segments, float phi);
  ~CSpherePart ();
  void init (float radius, int segments);
  void init (float radius, int segments, float phi);
  void setNorthPoleColor (CColor *c, float w); // see setPoleColor, phi=0, theta=90
  void setSouthPoleColor (CColor *c, float w);
  void setPoleColor (int phi, int theta, CColor *c, float w); // shade color over any pole
};

// More models could be added here, esp. for importing complex non-polygonal formats (obj, wrl)

#endif
