#include "stdafx.h"

#include <math.h>
#include <vector>

#include "TArc.h"
#include "Matrix.h"
#include "Plane.h"

#include "Vec.h"
#include "Vertex.h"

#include "Texture.h"
#include "MaterialManager.h"

#include "Tile.h"

#include "DataOutputStream.h"
#include "DataInputStream.h"

// MFC - Assists in finding memory leaks:
#ifdef MFC_DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#pragma warning( disable : 4996 )

static Vec m_insideVecs[10]; // Achtung: 10 potentiell eine Fehlerquelle

/****************************************************************************/
/** \brief Destruktor
*****************************************************************************/
Tile::~Tile()
{
delete[] m_vertexOrg;
delete[] m_vertex;
delete[] m_vFC;
delete[] m_tri;

delete[] m_x;
delete[] m_y;
delete[] m_u;
delete[] m_v;
}
  
/****************************************************************************/
/** \brief Default-Konstruktor
*****************************************************************************/
Tile::Tile() 
  {
  m_numVertices = 4;
  initialize();
  }

/*****************************************************************************/
/** \brief Konstruktor (wird nur von SkyBox benoetigt)
    \param v0 Vertex 1 'oben links'
    \param v1 Vertex 2 'oben rechts'
    \param v2 Vertex 3 'unten rechts'
    \param v3 Vertex 4 'unten links' 
    \param typ FLOOR, WALL, PORTAL
    \param zoneTHIS  Nummer 'dieser' Zone
    \param zoneOTHER Nummer der 'anderen' Zone 
    \param name Name der Tile
*******************************************************************************/
Tile::Tile(Vec& v0, Vec& v1, Vec& v2, Vec& v3, int typ, int zoneTHIS, int zoneOTHER, char* name)
  {
  m_numVertices = 4;
  initialize();

  m_typ       = typ;

  strcpy(m_name, name);
  
  m_zoneTHIS  = zoneTHIS;
  m_zoneOTHER = zoneOTHER;

  m_vertex[0].set(v0); m_vertex[0].setUV(0, 0); // oben links
  m_vertex[1].set(v1); m_vertex[1].setUV(1, 0); // oben rechts
  m_vertex[2].set(v2); m_vertex[2].setUV(1, 1); // unten rechts
  m_vertex[3].set(v3); m_vertex[3].setUV(0, 1); // unten links
  m_vertex[4].set(v0); m_vertex[4].setUV(0, 0); // oben links
  
  Plane::set(m_vertex[0], m_vertex[3], m_vertex[1]); // Plane-Eigenschaften setzen
  }

/****************************************************************************/
/** \brief Allgemeine Objekt-Initialisierung 
*****************************************************************************/
void Tile::initialize()
  {
  m_sid = -1; // SurfaceID
  m_numClipVertices = (m_numVertices * 2) + 1;
  m_numTriangles    = (m_numVertices * 2) + 1;

  m_vertexOrg = new Vertex[m_numVertices+1];
  m_vertex    = new Vertex[m_numVertices+1];

  m_vFC = new Vertex[m_numClipVertices+1];
  m_tri = new Triangle[m_numTriangles];

  m_x = new float[m_numClipVertices+1]; // x0' (projiziert auf Plane)
  m_y = new float[m_numClipVertices+1]; // y0' (projiziert auf Plane)
  m_u = new float[m_numClipVertices+1]; // u * c0 (u Texelkoordinate in x-Richtung)
  m_v = new float[m_numClipVertices+1]; // v * c0 (v Texelkoordinate in y-Richtung)

  m_textureID = 0;
  m_typ       = 0;
  sprintf(m_name, "%s", "NewUnknown");
  m_d         = 0;
  m_zoneTHIS  = 0;
  m_zoneOTHER = 0;
 
  m_maxFC = 0;
  m_maxTri = 0;
  
  m_ambientLight = 1;
  m_directionalLight = 0;
  m_lightMap = 0;

  m_hasLightMapGrid = false;
  m_scrollFlag  = 0;
  m_animationID = 0;
  }

/****************************************************************************/
/** \brief Setzt die Vertices wieder zurueck
*****************************************************************************/
void Tile::resetVertices(void)
   {
   int i;

   for (i=0; i < (m_numVertices+1); i++)
      m_vertex[i].set(m_vertexOrg[i]);
   }

/****************************************************************************/
/** \brief Setzt die Vertices wieder zurueck
*****************************************************************************/
void Tile::reverseVertices(void)
   {
   for (int i=0; i < (m_numVertices+1); i++)
      m_vertexOrg[i].set(m_vertex[i]);
   }

/****************************************************************************/
/** \brief Setter-Methode
    \param t Tile
*****************************************************************************/
void Tile::set(Tile& t)
  {
  int i;
  m_textureID = t.m_textureID;
  m_sid       = t.m_sid;
  
  //sprintf(m_name, "%s", t.m_name);
  m_name[0] = 0;

  m_typ       = t.m_typ;
  m_d         = t.m_d;
  m_zoneTHIS  = t.m_zoneTHIS;
  m_zoneOTHER = t.m_zoneOTHER;
  
  m_numVertices     = t.m_numVertices;
  m_numClipVertices = t.m_numClipVertices;
  m_numTriangles    = t.m_numVertices;

  for (i=0; i < (m_numVertices+1); i++)
     m_vertex[i].set(t.m_vertex[i]);

  m_maxFC = t.m_maxFC;
  for (i=0; i < m_maxFC; i++)  // Punkte der gegen das Frustum geclippten Tile
     m_vFC[i].set(t.m_vFC[i]);

  for (i=0; i< (m_numClipVertices+1); i++)
     {
     m_x[i] = t.m_x[i];   // x0' (projiziert auf Plane)
     m_y[i] = t.m_y[i];   // y0' (projiziert auf Plane)
     m_u[i] = t.m_u[i];   // u * c0 (u Texelkoordinate in x-Richtung)
     m_v[i] = t.m_v[i];   // v * c0 (v Texelkoordinate in y-Richtung)
     }

  Plane::set(m_vertex[0], m_vertex[2], m_vertex[1]); // TODO: wg Dreieck

  this->m_ambientLight = t.m_ambientLight;
  this->m_directionalLight  = t.m_directionalLight;
  this->m_lightMap = t.m_lightMap;

  this->m_scrollFlag = t.m_scrollFlag;
  }
  
/****************************************************************************/
/** \brief Getter fuer die Zone, zu der diese Tile gehoert
    \return zone, bzw. zoneNr
*****************************************************************************/
int Tile::getZoneTHIS(){return m_zoneTHIS;}

/****************************************************************************/
/** \brief Getter fuer die angrenzende Zone (nur wenn diese Tile ein Portal ist)
    \return zone, bzw. zoneNr
*****************************************************************************/
int Tile::getZoneOTHER(){return m_zoneOTHER;}
    
/****************************************************************************/
/** \brief Getter fuer das Scrollflag
    \return 0--> nicht scrollen, !=1 scrollen
*****************************************************************************/
int Tile::getScrollFlag() {return m_scrollFlag; }

/****************************************************************************/
/** \brief Setter fuer das Scrollflag
    \param scrollFlag 0--> nicht scrollen, !=1 scrollen
*****************************************************************************/
void Tile::setScrollFlag(int scrollFlag) {m_scrollFlag = scrollFlag; }

/****************************************************************************/
/** \brief Kopiere die Tilevertices in die Liste der ClippedVertices
*****************************************************************************/
void Tile::resetClipList()
   {
   for (int i=0; i < (m_numVertices+1); i++)
      m_vFC[i].set(m_vertex[i]);
   
   m_maxFC = m_numVertices;
   }

/****************************************************************************/
/** \brief Clipped die ClippedVertices gegen die Plane
    \param p die Plane gegen die diese Tile geclipped wird
*****************************************************************************/
void Tile::clip(Plane& p)
 {
 int i;
 // Da die Tile, respektive das Polygon IMMER konvex ist, kann das geclippte 
 // Polygon nie mehr als n+1 Vertices beinhalten:

 int status=0, m_insideVecsCount = 0;

 Line line; 
 Vec vs, nv; 
 float len, t ;
 bool NaN;
 
 // Gehe ueber alle Clip-Vertices 
 for (i=0; i< m_maxFC; i++)
   { 
   // bilde aus den Vertices i und i+1 eine Gerade
   line.set(m_vFC[i], m_vFC[i+1]);
   
   nv.set(line.m_V);
   nv.normalize();
   len = nv.length();

   status = p.check(m_vFC[i]);
   if (status == INSIDE) // Startpunkt der Line liegt innerhalb der Plane
      {
      m_insideVecs[m_insideVecsCount++].set(m_vFC[i]); 
    
      NaN = p.intersect(line, &t); // Schneidet die Gerade die Plane?    
      if (NaN == true)
         {
         if ((t >= 0) && (t <= len))
            {
            line.getEndPoint(t, &vs);
            m_insideVecs[m_insideVecsCount++].set(vs);
            }
         }
      }
   else // status == OUTSIDE // // Startpunkt der Line liegt ausserhalb der Plane
      { 
      NaN = p.intersect(line, &t); // Schneidet die Gerade die Plane?    
      if (NaN == true)
         {
         if ((t >= 0) && (t <= len))
            {
            line.getEndPoint(t, &vs);
            m_insideVecs[m_insideVecsCount++].set(vs);
            }
         }
      }
   }
 
 // Vertices aus der inside-Liste in die Clipp-Liste uebertragen
   m_maxFC = m_insideVecsCount; // inside.size();
   for (i=0; i < m_maxFC; i++)
      {
      m_vFC[i].set(m_insideVecs[i]);
      }

   if (m_maxFC > 0)
      {
      m_vFC[i].set(m_insideVecs[0]);
      }
 }

/****************************************************************************/
/** \brief Liefert den Typ zurueckClipped die ClippedVertices gegen die Plane
    \return WALL, PORTAL, FLOOR
*****************************************************************************/
int Tile::getTyp()
 {
 return (m_typ);
 }

/****************************************************************************/
/** \brief Testet auf die naive Methode, ob die Gerade v0-->v1 die Tile schneidet
           Es wird die erste Seite der Tile als Gerade genommen und verschnitten
    \param v0 Geraden-Startpunkt
    \param v1 Geraden-Endpunktpunkt
    \return true-->Gerade schneidet die Tile, false-->Gerade schneidet nicht die Tile
*****************************************************************************/
bool Tile::intersect(Vec& v0, Vec& v1)
  {
  float epsilon = 0.0001f; // Scheisss Rundungsproblem!!
  
  Line line; 
  line.set(v0, v1);
  
  Vec nv; nv.set(line.m_V); 
  nv.normalize(); 
  float len = nv.length();
  float t = 0;

  float x0, x1;
  float y0, y1; 
  float z0, z1; 
  bool NaN;

  NaN = Plane::intersect(line, &t); 

  if (NaN == true)
     {
     if ((t >= 0) && (t <= len))
        {
        Vec v = line.getEndPoint2(t);
        
        if (m_vertex[0].m_x < m_vertex[1].m_x)
           {
           x0 = m_vertex[0].m_x;              
           x1 = m_vertex[1].m_x;
           }
        else
           {
           x0 = m_vertex[1].m_x;              
           x1 = m_vertex[0].m_x;
           }
        
        if (m_vertex[0].m_y < m_vertex[2].m_y)
           {
           y0 = m_vertex[0].m_y;              
           y1 = m_vertex[2].m_y;
           }
        else
           {
           y0 = m_vertex[2].m_y;              
           y1 = m_vertex[0].m_y;
           }

        if (m_vertex[0].m_z < m_vertex[2].m_z)
           {
           z0 = m_vertex[0].m_z;              
           z1 = m_vertex[2].m_z;
           }
        else
           {
           z0 = m_vertex[2].m_z;              
           z1 = m_vertex[0].m_z;
           }
        
        // Wenn die Camera im rechten Winkel zu einer Tile steht,
        // ist z0 gleich z1. Ist nun v.m_z nicht EXAKT z0 bzw. z1
        // wird die Tile nicht richtig bewertet (fliegt raus)
        // Dehalb hier ein kleines Epsilon :-))
        z0 -= epsilon;              
        z1 += epsilon;
        
        if ((x0 <= v.m_x) && (v.m_x <= x1) &&
            (y0 <= v.m_y) && (v.m_y <= y1) &&   
            (z0 <= v.m_z) && (v.m_z <= z1))
           {
           return (true);
           }
        }
     } 
  
  return (false);
  }

/****************************************************************************/
/** \brief Transformiert alle Vertices der Tile
    \param mat Transformationsmatrix
*****************************************************************************/
void Tile::transform(Matrix& mat)
  {
  for (int i=0; i< (m_numVertices+1); i++)
     m_vertex[i].transform(mat); // VERTICES+1 ist redundant!

 Plane::set(m_vertex[0], m_vertex[2], m_vertex[1]); // TODO: wg. Dreieck
  }

/****************************************************************************/
/** \brief Projiziere die Raumkoordinaten auf die ViewPlane (2D)
    \param d 
*****************************************************************************/
void Tile::project(float d)
   {
   m_d = d;
   // Achtung: Die Camera steht am Punkt (0,0,0). Wenn z.B. ein Bodentile 
   // mit einem (oder mehreren, aber nicht allen) Eckpunkten 'hinter' der Camera 
   // liegt, wird q negativ. (-q)* (-y) = (+)z und das kann nicht sein!
   // Deshalb wird hier mit dem Betrag von q gerechnet.
   // Wenn die Tile komplett 'hinter' der Camera liegt, sollte es vorher gecullt werden,
   // und erst garnicht projiziert werden.
   float q=0;

   for (int i = 0; i < (m_maxFC+1); i++)
     {
     q = (float)fabs(m_d / m_vFC[i].m_z);
     m_x[i] = (q * m_vFC[i].m_x);
     m_y[i] = (q * m_vFC[i].m_y);
     }
   }
 
/****************************************************************************/
/** \brief UV-Mapper: Berechnet zu jedem Vertex die UV-Werte. Diese Methode 
           muss nur einmal fuer jede Tile (Polygon) aufgerufen werden.
           Alternativ koennen spaeter die UV-Werte von einem UV-Mapper 
           importiert werden (ist aber noch nicht implementiert)
*****************************************************************************/
void Tile::calcUV(void)
{
int i=0;
float epsilon = 0.0001f;
float PI = 3.1416f;

float xmin, ymin, zmin, xmax, ymax, zmax;

Vec v, vt, vN;

Vec *vv  = new Vec[m_numVertices+1];

Matrix matTranslate; 
Matrix matRotateX;   
Matrix matRotateY;   

for (i=0; i < m_numVertices+1; i++)
   vv[i].set(m_vertex[i]);
vN.set(m_N);

// -----------------------------------      
// Translation in den Ursprung (v0)
// -----------------------------------      
vt.set(vv[0]);
vt.negative();
matTranslate.translate(vt);

for (i=0; i < m_numVertices+1; i++)
   vv[i].transform(matTranslate);

// -----------------------------------      
// Rotation um die Y-Achse:
// -----------------------------------      
float ww2=0, ww3=0;
float ddx = (float)fabs(vN.m_x);
if (ddx > epsilon)
   {
   ww2 = (float)atan(vN.m_z / vN.m_x);
   if (ww2 > 0)
      ww2 = ww2 - (PI / 2.0f); // 1.57;
   else
      ww2 = ww2 + (PI / 2.0f) ; // 1.57;
   }
else
   ww2=0;

matRotateY.rotateYRad(ww2);

for (i=0; i < m_numVertices+1; i++)
   vv[i].transform(matRotateY);
vN.transform(matRotateY);

// -----------------------------------      
// Rotation um die X-Achse:
// -----------------------------------      
float ddy = (float)fabs(vN.m_y);
if (ddy > epsilon)
   {
   ww3 = (float)atan(vN.m_z  / vN.m_y);
   if (ww3 > 0)
      ww3 = ww3 - (PI / 2.0f); // 1.57;
   else
      ww3 = ww3 + (PI / 2.0f);
   }
else
   ww3 = 0;

matRotateX.rotateXRad(-ww3);

for (i=0; i < m_numVertices+1; i++)
   vv[i].transform(matRotateX);
vN.transform(matRotateX);


if (vv[1].m_x < 0) // Hack !!!!
   {
   matRotateY.clear();
   matRotateY.rotateYRad(PI);
   for (i=0; i < m_numVertices+1; i++)
      vv[i].transform(matRotateY);
   vN.transform(matRotateY);
   }

if (vv[2].m_y > 0) // Hack !!!!
   {
   matRotateX.clear();
   matRotateX.rotateXRad(PI);
   for (i=0; i < m_numVertices+1; i++)
      vv[i].transform(matRotateX);
   vN.transform(matRotateX);
   }

//-----------------------------------      
//MinMax-Werte ermitteln
//-----------------------------------      
xmin = xmax = vv[0].m_x;
ymin = ymax = vv[0].m_y;
zmin = zmax = vv[0].m_z;

for (i=1; i < m_numVertices; i++)
   {
   if (vv[i].m_x < xmin)
      xmin = vv[i].m_x;
   else if (vv[i].m_x > xmax)
      xmax = vv[i].m_x;
   
   if (vv[i].m_y < ymin)
      ymin = vv[i].m_y;
   else if (vv[i].m_y > ymax)
      ymax = vv[i].m_y;

   if (vv[i].m_z < zmin)    // Nur zu Testzwecken: Sollte immer 0 sein!
      zmin = vv[i].m_z;
   else if (vv[i].m_z > zmax)
      zmax = vv[i].m_z;
   }

float dx = xmax - xmin;
float dy = ymax - ymin;
//float dz = zmax - zmin;

for (i=0; i < m_numVertices +1; i++)
   {
   m_vertex[i].m_u = (vv[i].m_x - xmin) / dx;
   m_vertex[i].m_v = (vv[i].m_y - ymax) / dy;
   }


delete[] vv; // !!!!!!!!!
}

/*******************************************************************************
* Berechnet anhand der geclippten Vertices die Texelkoordinaten
*******************************************************************************/
void Tile::calcTexelVertices()
{
   int i;

   Vec v; 
   Vec vt; 
   
   Vec vU; 
   Vec vV; 
   Vec vN; 

   Vec va; 
   Vec vb; 
   
   Matrix matTranslate; 
   Matrix matWT; 
   
   // -----------------------------------      
   // Verschubse die Tile in den Ursprung
   // -----------------------------------
   vt.set(m_vertex[0]);
   vt.negative();
   matTranslate.translate(vt);

   // ---------------------------------------------  
   // Tangent-space   
   // ---------------------------------------------
   Texture* tex = MaterialManager::getInstance()->get(m_textureID);

   float width  = (float)tex->getWidth(); 
   float height = (float)tex->getHeight();  
   
   float u1 = (width  * m_vertex[0].m_u); 
   float v1 = -(height * m_vertex[0].m_v); 
   
   float u2 = (width  * m_vertex[1].m_u); 
   float v2 = -(height * m_vertex[1].m_v); 
   
   float u3 = (width  * m_vertex[2].m_u);   //TODO: wg Dreieck 2 statt 3
   float v3 = -(height * m_vertex[2].m_v); 
   
   float d21x = m_vertex[1].m_x - m_vertex[0].m_x;
   float d21y = m_vertex[1].m_y - m_vertex[0].m_y;
   float d21z = m_vertex[1].m_z - m_vertex[0].m_z;
   float d21u = u2 - u1;
   float d21v = v2 - v1;
   
   float d31x = m_vertex[2].m_x - m_vertex[0].m_x;  //TODO: wg Dreieck 2 statt 3
   float d31y = m_vertex[2].m_y - m_vertex[0].m_y;
   float d31z = m_vertex[2].m_z - m_vertex[0].m_z;
   float d31u = u3 - u1;
   float d31v = v3 - v1;
   
   va.set(d21x, d21u, d21v);
   vb.set(d31x, d31u, d31v);
   v.cross(va, vb);
   if (v.m_x != 0)
      {
      vU.m_x = -v.m_y / v.m_x;   
      vV.m_x = -v.m_z / v.m_x;
      }

   va.set(d21y, d21u, d21v);
   vb.set(d31y, d31u, d31v);
   v.cross(va, vb);
   if (v.m_x != 0)
      {
      vU.m_y = -v.m_y / v.m_x;   
      vV.m_y = -v.m_z / v.m_x;
      }
   
   va.set(d21z, d21u, d21v);
   vb.set(d31z, d31u, d31v);
   v.cross(va, vb);
   if (v.m_x != 0)
      {
      vU.m_z = -v.m_y / v.m_x;   
      vV.m_z = -v.m_z / v.m_x;
      }
   
   vN.cross(vV, vU);
   vN.normalize(); 
   
   vU.normalize();
   vV.normalize();
   
   matWT.set(vU, vV, vN);
   v.set(m_vertex[2]);
   v.transform(matTranslate);
   v.transform(matWT); 
   
   for (i=0; i < m_maxFC; i++)
      {
      v.set(m_vFC[i]);
      v.transform(matTranslate);
      v.transform(matWT);

      int uu = (int)(u1 + (v.m_x + 0.5f));
      int vv = (int)(v1 + (v.m_y + 0.5f));
      
      this->m_u[i] = (float)uu; 
      this->m_v[i] = (float)vv; 
//      TRACE("u[%d]=%d\tv[%d]=%d\n", i, uu, i, vv); 
      }
}

/****************************************************************************/
/** \brief Zerlegt das (geclippte) Polygon in Dreiecke
*****************************************************************************/
void Tile::triangulate()
  {
   int i, n;
   m_maxTri = m_maxFC-2; // Die Anzahl der Dreiecke ist immer (Anzahl Vertices)-2
   
   n=1;
   for (i=0; i < m_maxTri; i++)
      {
      m_tri[i].m_textureID        = this->m_textureID;
      m_tri[i].m_sid              = this->m_sid;
      m_tri[i].m_ambientLight     = this->m_ambientLight;
      m_tri[i].m_directionalLight = this->m_directionalLight;
      m_tri[i].m_lightMap         = this->m_lightMap;
      
      m_tri[i].set(this->m_textureID, m_vFC[0], m_vFC[n], m_vFC[n+1]);

      m_tri[i].x[0] = this->m_x[0];
      m_tri[i].y[0] = this->m_y[0];

      m_tri[i].x[1] = this->m_x[n];
      m_tri[i].y[1] = this->m_y[n];

      m_tri[i].x[2] = this->m_x[n+1];
      m_tri[i].y[2] = this->m_y[n+1];
      
      m_tri[i].m_u0 = this->m_u[0];
      m_tri[i].m_v0 = this->m_v[0];

      m_tri[i].m_u1 = this->m_u[n];
      m_tri[i].m_v1 = this->m_v[n];

      m_tri[i].m_u2 = this->m_u[n+1];
      m_tri[i].m_v2 = this->m_v[n+1];
      n+=1;
      }
  }

/****************************************************************************/
/** \brief Berechnet die min und max Distanz der Tile zum Ursprung zureck
           Dabei werden alle Vertices verglichen und die min/max. Distanz ermittelt
           Das Ergebnis wir jeweils in m_minDist und m_maxDist abgelegt
    \param d 
*****************************************************************************/
void Tile::calcDistances(float d)
{
float x, y, z, q;

m_minXDist3D = m_vertex[0].m_x;
m_maxXDist3D = m_vertex[0].m_x;
m_minYDist3D = m_vertex[0].m_y;
m_maxYDist3D = m_vertex[0].m_y;
m_minZDist3D = m_vertex[0].m_z;
m_maxZDist3D = m_vertex[0].m_z;

q = (float)fabs(d / m_vertex[0].m_z);
m_minXDist2D = (q * m_vertex[0].m_x);
m_maxXDist2D = m_minXDist2D;

m_minYDist2D = (q * m_vertex[0].m_y);
m_maxYDist2D = m_minYDist2D;

m_minZDist3D = m_vertex[0].m_z;
m_maxZDist3D = m_minZDist3D;

for (int i = 1; i < (m_numVertices); i++)
   {
   if (m_minXDist2D > m_vertex[i].m_x)
      m_minXDist2D = m_vertex[i].m_x;
   else if (m_maxXDist2D < m_vertex[i].m_x)
      m_maxXDist2D = m_vertex[i].m_x;
   
   if (m_minYDist2D > m_vertex[i].m_y)
      m_minYDist2D = m_vertex[i].m_y;
   else if (m_maxYDist2D < m_vertex[i].m_y)
      m_maxYDist2D = m_vertex[i].m_y;
   
   if (m_minZDist3D > m_vertex[i].m_z)
      m_minZDist3D = m_vertex[i].m_z;
   else if (m_maxZDist3D < m_vertex[i].m_z)
      m_maxZDist3D = m_vertex[i].m_z;


   q = (float)fabs(d / m_vertex[i].m_z);
   x = (q * m_vertex[i].m_x);
   y = (q * m_vertex[i].m_y);
   z = m_vertex[i].m_z;
   
   if (x < m_minXDist2D)
      m_minXDist2D = x;
   else if (x > m_maxXDist2D)
      m_maxXDist2D = x;

   if (y < m_minYDist2D)
      m_minYDist2D = y;
   else if  (y > m_maxYDist2D)
      m_maxYDist2D = y;
   
   if (z < m_minZDist3D)
      m_minZDist3D = z;
   else if  (z > m_maxZDist3D)
      m_maxZDist3D = z;
   }
}

/****************************************************************************/
/** \brief Registriert eine Lightmap fur diese Tile
    \param lightMap Pointer auf die Lightmap 
*****************************************************************************/
void Tile::setLightMap(LightMap* lightMap)
{
this->m_lightMap = lightMap;
}

/****************************************************************************/
/** \brief Obligatorische Dump-Methode
*****************************************************************************/
 void Tile::dump()
{
int u, v;

FILE *p = fopen ("c:\\Tile.dump", "w");

if (p != 0)
   {
   for (v=0; v < 32; v++)
      {
      for (u=0; u < 32; u++)
         {
         fprintf(p, "%3d ", m_lightMapGrid[u][v]);
         }
      fprintf(p, "\n");
      }

   fclose(p);
   }
}

/****************************************************************************/
/** \brief Liest das Tile-Objekt aus dem Inputstream
*   \param dataIn DataInputStream
*******************************************************************************/
void Tile::load(DataInputStream& dataIn) 
{
   int i;
   int numVertices = 0;

   try
      {
      m_typ        = dataIn.readInt();
      m_textureID  = dataIn.readInt();
      m_zoneTHIS   = dataIn.readInt();
      m_zoneOTHER  = dataIn.readInt();  

      m_scrollFlag  = dataIn.readInt();  
      m_animationID = dataIn.readInt();  

      numVertices = dataIn.readInt();  // Anzahl der Vertices
      for (i=0; i < numVertices; i++)
         {
         m_vertexOrg[i].m_x = (float)dataIn.readDouble();
         m_vertexOrg[i].m_y = (float)dataIn.readDouble();
         m_vertexOrg[i].m_z = (float)dataIn.readDouble();
         m_vertexOrg[i].m_u = (float)dataIn.readDouble();
         m_vertexOrg[i].m_v = (float)dataIn.readDouble();
         }
      
      m_vertexOrg[i].m_x = m_vertexOrg[0].m_x;
      m_vertexOrg[i].m_y = m_vertexOrg[0].m_y;
      m_vertexOrg[i].m_z = m_vertexOrg[0].m_z;
      m_vertexOrg[i].m_u = m_vertexOrg[0].m_u;
      m_vertexOrg[i].m_v = m_vertexOrg[0].m_v;

      Plane::set(m_vertexOrg[0], m_vertexOrg[2], m_vertexOrg[1]); // TODO: wg Dreieck

      resetVertices();
      }
   catch (std::exception eof)
      {
      printf("EOF" );  // TODO: Logfile schreiben
      }
}

/******************************************************************************/
/** \brief Serialisiert das Tile-Objekt in den Outputstream
    \param dataOut DataOutputStream
    \throws IOException 
*******************************************************************************/
void Tile::save(DataOutputStream& dataOut) 
{
int i;

dataOut.writeInt(m_typ);          // Typ TILE, WALL, FLOOR, PORTAL
dataOut.writeInt(m_textureID);    // Texture ID
dataOut.writeInt(m_zoneTHIS);     // Diese Portalzone
dataOut.writeInt(m_zoneOTHER);    // Die 'andere' Portalzone

dataOut.writeInt(m_scrollFlag);   // Scrollflag
dataOut.writeInt(m_animationID);  // DoorFlag

dataOut.writeInt(m_numVertices);  // Anzahl der Vertices
for (i=0; i < m_numVertices; i++)
   {
   dataOut.writeDouble(m_vertexOrg[i].m_x);
   dataOut.writeDouble(m_vertexOrg[i].m_y);
   dataOut.writeDouble(m_vertexOrg[i].m_z);
   dataOut.writeDouble(m_vertexOrg[i].m_u);
   dataOut.writeDouble(m_vertexOrg[i].m_v);
   }
}
