#include "stdafx.h"

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

#include "TArc.h"
#include "Matrix.h"
#include "Texture.h"
#include "MaterialManager.h"
#include "Tile.h"
#include "LightManager.h"

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

LightManager* LightManager::_instance = 0;

/****************************************************************************/
/** \brief Liefert die Singleton-Instanz
    \return Pointer auf die Instanz
*****************************************************************************/
LightManager* LightManager::getInstance()
{
 if (_instance == 0) 
   _instance = new LightManager();
 return _instance;
}

/****************************************************************************/
/** \brief Destruktor
*****************************************************************************/
LightManager::~LightManager()
{
unsigned int i;
for (i=0; i < lightZoneList.size(); i++)
   {
   LightZone* lightZone = lightZoneList[i];
   delete (lightZone);
   }

for (i=0; i < lightMaps.size(); i++)
   {
   LightMap* lm = lightMaps[i];
   delete (lm);
   }

_instance = 0; // Singleton !!!
}

/****************************************************************************/
/** \brief Konstruktor, Singleton
*****************************************************************************/
LightManager::LightManager()
  {
  m_AmbientON = true;
  m_DirectionalON = true;
  m_LightMapON = true;

//  m_gammaR = new int[256];
//  m_gammaG = new int[256];
//  m_gammaB = new int[256];
  calcGamma(1);
  }

/******************************************************************************/
/** \brief Fuegt ein LightEnvironment hinzu
    \param zone die zone fuer die diese Parameter gelten
    \param ambient Wert fuer das ambiente Licht (= const)
    \param directionalMax Maximalwert fuer direktes Licht
    \param pointMax Maximalwert fuer Punktlicht
*******************************************************************************/
void LightManager::addEnvironment(int zone, float ambient, float directionalMax, float pointMax)
{
LightZone* lightZone = getLightZone(zone);
lightZone->set(ambient, directionalMax, pointMax);
}

/******************************************************************************/
/** \brief Fuegt DirectionalLight hinzu
    \param zone zone-Nr, bzw. zone-ID
    \param dirX X-Richtungskomponente fuer das Direktional Light
    \param dirY Y-Richtungskomponente fuer das Direktional Light
    \param dirZ Z-Richtungskomponente fuer das Direktional Light
*******************************************************************************/
void LightManager::setDirectionalLight(int zone, float dirX, float dirY, float dirZ)
{
LightZone* lightZone = getLightZone(zone);
lightZone->setDirectionalLight(dirX, dirY, dirZ);
}

/******************************************************************************/
/** \brief Getter fuer das LightEnvironment zu einer Zone
    \param  zone Zonen-Nr, bzw Zonen-ID
    \return Pointer auf das LightEnvironment
*******************************************************************************/
LightZone* LightManager::getLightZone(int zone)
{
LightZone* lightZone = 0;
for (unsigned int i = 0; i < lightZoneList.size(); i++)
   {
   lightZone = (LightZone*)lightZoneList[i];
   if (zone == lightZone->getZone())
      return (lightZone);
   }

lightZone = new LightZone(zone);
lightZoneList.push_back(lightZone);
return (lightZone);
}

/******************************************************************************/
/** \brief Fuegt ein PointLight hinzu
    \param zone Zonen-Nr, bzw. Zonen-ID
    \param x X-Koordinate fuer das Punktlicht
    \param y Y-Koordinate fuer das Punktlicht
    \param z Z-Koordinate fuer das Punktlicht
*******************************************************************************/
void LightManager::addPointLight(int zone, float x, float y, float z)
{
LightZone* lightZone = getLightZone(zone);
lightZone->addPointLight(x, y, z);
}

/******************************************************************************/
/** \brief Berechnet die Lichtintensitaet an den Stuetzstellen einer Tile. 
           Hier werden das Ambient- Directional- und die PoinLight-Komponenten
           beruecksichtigt.
    \param tile die Tile welche das Licht reflektiert
*******************************************************************************/
void LightManager::calcLightMapGrid(Tile& tile)
{
LightZone* lightZone = getLightZone(tile.m_zoneTHIS);
tile.m_ambientLight = lightZone->getAmbient();
tile.m_directionalLight = calcDirectional(tile, *lightZone);

tile.m_hasLightMapGrid = false;
if (lightZone->hasPointLights() == true)
   {
   calcLightMapGrid(tile, *lightZone);
   }
}

/******************************************************************************/
/** \brief Berechnet die Lichtintensitaet fuer eine Tile. Weil das Directional Light 
           unabhaengig von der Cameraposition ist, muss die Lichtintensitaet pro
           Tile nur einmal berechnet werden. Das passiert sinnvoller weise nachden
           die Richtung der Lichtquelle gesetzt wurde, und bevor die Map zum ersten mal 
           transformiert, bzw. gerendert wird.

    \param tile die Tile welche das Licht reflektiert
    \param le LightEnvironment
*******************************************************************************/
float LightManager::calcDirectional(Tile& tile, LightZone& le)
{
float m = le.getDirectionalMax(); 

float x = le.m_dir.dot(tile.m_N);
if (x < 0)
  x = 0;

float y = m * x;

if (y > m) // Directional Light darf nicht groesser als DirectionalMax sein!
  y = m;

tile.m_directionalLight = y;
return (y);
}

/******************************************************************************/
/** \brief Berechnet die Lichtintensitaet fuer eine Tile. Weil das Directional Light 
           unabhaengig von der Cameraposition ist, muss die Lichtintensitaet pro
           Tile nur einmal berechnet werden. Das passiert sinnvoller weise nachden
           die Richtung der Lichtquelle gesetzt wurde, und bevor die Map zum ersten mal 
            transformiert, bzw. gerendert wird.

    \param tile die Tile welche das Licht reflektiert
    \param le LightEnvironment
*******************************************************************************/
void LightManager::calcPointLight(Tile& tile, LightZone& le)
{
MaterialManager* materialManager = MaterialManager::getInstance();
Texture* tex = materialManager->get(tile.m_textureID);
float umax = (float)tex->getWidth();  
float vmax = (float)tex->getHeight();

unsigned int i; 
float  x, y, z; 
LightPoint* lp = 0;

std::vector<LightPoint*> lightPoints;

for (i=0; i < le.lightPointList.size(); i++)
   {
   lp = (LightPoint*)le.lightPointList[i];
   if (tile.check(lp->m_pos) == Tile::INSIDE)
     lightPoints.push_back(lp);
   }

if (lightPoints.size() == 0)
   return;

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(tile.m_vertex[0]);
vt.negative();
matTranslate.translate(vt);

// ---------------------------------------------  
// Tangent-space   
// ---------------------------------------------
float width  = (float)tex->getWidth(); 
float height = (float)tex->getHeight(); 

float u1 = (width  * tile.m_vertex[0].m_u); 
float v1 = -(height * tile.m_vertex[0].m_v); 

float u2 = (width  * tile.m_vertex[1].m_u); 
float v2 = -(height * tile.m_vertex[1].m_v); 

float u3 = (width  * tile.m_vertex[3].m_u); 
float v3 = -(height * tile.m_vertex[3].m_v); 

float d21x = tile.m_vertex[1].m_x - tile.m_vertex[0].m_x;
float d21y = tile.m_vertex[1].m_y - tile.m_vertex[0].m_y;
float d21z = tile.m_vertex[1].m_z - tile.m_vertex[0].m_z;
float d21u = u2 - u1;
float d21v = v2 - v1;

float d31x = tile.m_vertex[3].m_x - tile.m_vertex[0].m_x;
float d31y = tile.m_vertex[3].m_y - tile.m_vertex[0].m_y;
float d31z = tile.m_vertex[3].m_z - tile.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.setInv(vU, vV, vN);

int vv=0, uu=0;

float plsum = 0;

float pointMax= le.getPointMax();

// Zuerst ein paar Samples nehmen und auf Light testen
bool sw= false;
float vvStep = vmax / 3.0f;
float uuStep = umax / 3.0f;

for (vv=0; vv < vmax; vv+=(int)vvStep)
   {
   for (uu=0; uu < umax; uu+=(int)uuStep)
      {
      v.set((float)uu, (float)vv,0);
      v.transform(matWT);
      x = tile.m_vertex[0].m_x + v.m_x;   
      y = tile.m_vertex[0].m_y + v.m_y;
      z = tile.m_vertex[0].m_z + v.m_z;
      
      plsum = calcLPs(lightPoints, x, y, z, pointMax); 
      if (plsum >= 0.01)
         {
         sw=true;      
         break;
         }
      }
   }

if (sw == false)
   {
//   TRACE("Tile hits no pointlight\n");
   return;
   }

// Jetzt erst die Lightmap erzeugen:
LightMap* myLightMap = new LightMap((int)umax, (int)vmax);

for (vv=0; vv < vmax; vv++)
   {
   for (uu=0; uu < umax; uu++)
      {
      v.set((float)uu,(float)vv,0);
      v.transform(matWT);
      x = tile.m_vertex[0].m_x + v.m_x;   
      y = tile.m_vertex[0].m_y + v.m_y;
      z = tile.m_vertex[0].m_z + v.m_z;
      
      plsum = calcLPs(lightPoints, x, y, z, pointMax); 
      BYTE b_plsum = (BYTE)((255.0 * plsum) + 0.5);
      myLightMap->set(uu, vv, b_plsum);
      }
   }

   myLightMap->dump();

   lightMaps.push_back(myLightMap);
   tile.m_lightMap = myLightMap;
}


/******************************************************************************/
/** \brief Berechnet zu einem Pixel die Lightpoint-Intensity
    \param lightPoints Vector mit allen Punktlichtern
    \param x 
    \param y 
    \param z
    \param pointMax 
*******************************************************************************/
float LightManager::calcLPs(std::vector<LightPoint*> &lightPoints, float x, float y, float z, float pointMax)
{
float plsum=0, dx=0, dy=0, dz=0, d=0;

unsigned int i;
LightPoint* lp = 0;

for (i=0; i < lightPoints.size(); i++)
   {
   lp = (LightPoint*)lightPoints[i];
   lp->calcParameters(50, pointMax, 200, 0.1f);
   
   dx = x - lp->m_pos.m_x;
   dy = y - lp->m_pos.m_y; 
   dz = z - lp->m_pos.m_z;
   
   d = (float)sqrt(dx*dx + dy*dy + dz*dz);
   
   plsum += lp->calc(d);
   }

if (plsum > pointMax)  // FAST
   plsum = pointMax;  

return (plsum);
}

/******************************************************************************/
/** \brief Berechnet die Lichtintensitaet an den Stuetzstellen (Grid) fuer eine Tile.
    \param tile die Tile welche das Licht reflektiert
    \param le LightEnvironment
*******************************************************************************/
void LightManager::calcLightMapGrid(Tile& tile, LightZone& le)
{
MaterialManager* materialManager = MaterialManager::getInstance();
Texture* tex = materialManager->get(tile.m_textureID);

float x, y, z; 

LightPoint* lp = 0;

std::vector<LightPoint*> lightPoints;

unsigned int i; 
for (i=0; i < le.lightPointList.size(); i++)
   {
   lp = (LightPoint*)le.lightPointList[i];
   if (tile.check(lp->m_pos) == Tile::INSIDE)
     lightPoints.push_back(lp);
   }

if (lightPoints.size() == 0)
   return;

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(tile.m_vertex[0]);
vt.negative();
matTranslate.translate(vt);

// ---------------------------------------------  
// Tangent-space   
// ---------------------------------------------
float width  = (float)tex->getWidth(); 
float height = (float)tex->getHeight(); 

float u1 =  (width  * tile.m_vertex[0].m_u); 
float v1 = -(height * tile.m_vertex[0].m_v); 

float u2 =  (width  * tile.m_vertex[1].m_u); 
float v2 = -(height * tile.m_vertex[1].m_v); 

float u3 =  (width  * tile.m_vertex[3].m_u); 
float v3 = -(height * tile.m_vertex[3].m_v); 

float d21x = tile.m_vertex[1].m_x - tile.m_vertex[0].m_x;
float d21y = tile.m_vertex[1].m_y - tile.m_vertex[0].m_y;
float d21z = tile.m_vertex[1].m_z - tile.m_vertex[0].m_z;
float d21u = u2 - u1;
float d21v = v2 - v1;

float d31x = tile.m_vertex[3].m_x - tile.m_vertex[0].m_x;
float d31y = tile.m_vertex[3].m_y - tile.m_vertex[0].m_y;
float d31z = tile.m_vertex[3].m_z - tile.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.setInv(vU, vV, vN);


// -----------------------------------      
// Ab hier das Grid berechnen:
// -----------------------------------
//float d = 0, 
float plsum = 0;
//bool sw= false;
BYTE b_plsum;

float pointMax = le.getPointMax(); 


int vv=0, uu=0;
int v_tex,  u_tex;
int v_grid, u_grid;

int umax = tex->getWidth();  
int vmax = tex->getHeight();

// Von der Texture/Polygon werden 3D Punkte abgetastet (sampleling). Das geschieht mit einem 
// Pixelabstand von 16 Pixeln in u und v Richtung. Bei einer max. Texturegroesse 
// von 512*512 Pixel, ist so die Gridgroesse auf (32+1) * (32+1) Abtastwerte vorgegeben.
// z.B: (1, 16, 32, 48, 64, 80, 96, 112, 128) ==> 8+1 Werte
// z.B: (1, 16, 32, 48, 64, 80, 96, 112, 128, 144...512) ==> 32+1 Werte

int vc = (vmax / 16) +1; // Anzahl der Stuetzstellen: z.B.: (128 / 16) + 1 = 9 
int uc = (umax / 16) +1; // ==> 1, 16, 32, 64, 80, 96, 112, 128 

for (v_grid=0; v_grid < 33; v_grid++)           // Grid loeschen
   for (u_grid=0; u_grid < 33; u_grid++)
      tile.m_lightMapGrid[u_grid][v_grid] = 0;

//TRACE ("-----------Calc GRID----------\n");
for (vv=1, v_tex=1, v_grid=0; vv<=vc; vv++, v_grid++)
   {
   for (uu=1, u_tex=1, u_grid=0; uu<=uc; uu++, u_grid++)
      {
      v.set((float)(u_tex-1), (float)(v_tex-1), 0); // 1-1, 16-1, 32-1, 64-1 ... 512-1
//      TRACE ("GRID u_grid=%d v_grid=%d - u_tex=%d v_tex=%d\n", u_grid, v_grid, u_tex, v_tex);
      v.transform(matWT);
      x = tile.m_vertex[0].m_x + v.m_x;   
      y = tile.m_vertex[0].m_y + v.m_y;
      z = tile.m_vertex[0].m_z + v.m_z;
   
      plsum = calcLPs(lightPoints, x, y, z, pointMax); 
      b_plsum = (BYTE)((255.0 * plsum) + 0.5);
      tile.m_lightMapGrid[u_grid][v_grid] = b_plsum;       
  
      u_tex = uu * 16;
      }
   v_tex = vv * 16;
   }

// Falls alle Gridwerte 0 sind, wird keine Lightmap benoetigt:
for (v_grid=0; v_grid < 33; v_grid++)
   for (u_grid=0; u_grid < 33; u_grid++)
      if (tile.m_lightMapGrid[u_grid][u_grid] != 0)
         tile.m_hasLightMapGrid = true; // Lightmap wird benoetigt
}

/******************************************************************************/
/** \brief Berechnet die Lichtintensitaet fuer eine Tile. Weil das Directional Light 
           unabhaengig von der Cameraposition ist, muss die Lichtintensitaet pro
           Tile nur einmal berechnet werden. Das passiert sinnvoller weise nachden
           die Richtung der Lichtquelle gesetzt wurde, und bevor die Map zum ersten mal 
           transformiert, bzw. gerendert wird. 
    \param tile die Tile welche das Licht reflektiert
*******************************************************************************/
void LightManager::calcLightMap(Tile& tile)
{
MaterialManager* materialManager = MaterialManager::getInstance();
Texture* tex = materialManager->get(tile.m_textureID);

int umax = tex->getWidth();  
int vmax = tex->getHeight();

int vv=0, uu=0;

BYTE b_plsum;

LightMap* myLightMap = new LightMap(umax, vmax);

// Bilineare Interpolation:
for (vv=0; vv < vmax; vv++)
   {
   for (uu=0; uu < umax; uu++)
      {
      int xi = uu / 16;
      int yi = vv / 16;

      int q12 = tile.m_lightMapGrid[xi][yi];     // oben links
      int q22 = tile.m_lightMapGrid[xi+1][yi];   // oben rechts

      int q11 = tile.m_lightMapGrid[xi][yi+1];   // unten links
      int q21 = tile.m_lightMapGrid[xi+1][yi+1]; // unten rechts

      int px = uu % 16;
      int py = vv % 16;
      
      b_plsum = biInterpolate (q11, q21, q12, q22, px, py);
      
      myLightMap->set(uu, vv, b_plsum);
      }
   }

//  myLightMap->dump();

   lightMaps.push_back(myLightMap);
   tile.m_lightMap = myLightMap;
}

/******************************************************************************/
/** \brief Bilineare interpolation
    \param q12
    \param q22
    \param q11
    \param q21
    \param q21
    \param x
    \param y
*******************************************************************************/
BYTE LightManager::biInterpolate(int q12, int q22, int q11, int q21, int x, int y)
{
int _16_x = 16-x;
int _16_y = 16-y;

int t1 = (q11 * _16_x * _16_y) >> 8; 
int t2 = (q21 *     x * _16_y) >> 8; 
int t3 = (q12 * _16_x * y)     >> 8; 
int t4 = (q22 * x * y)         >> 8; 
return ((BYTE)(t1+t2+t3+t4));

/*
float x2 = 16;
float x1 = 0;

float y2 = 16;
float y1 = 0;

float t1 = q11 * ((x2-x)*(y2-y)) / ((x2-x1)*(y2-y1));
float t2 = q21 * ((x-x1)*(y2-y)) / ((x2-x1)*(y2-y1));
float t3 = q12 * ((x2-x)*(y-y1)) / ((x2-x1)*(y2-y1));
float t4 = q22 * ((x-x1)*(y-y1)) / ((x2-x1)*(y2-y1));

float p  = t1+t2+t3+t4;

val = (BYTE) p;
*/
}

/******************************************************************************/
/** \brief Schaltet das Ambient Light ein oder aus
*******************************************************************************/
void LightManager::toggleAmbientLight()
{
if (m_AmbientON == true)
   {
   m_AmbientON = false;
   }
else
   {
   m_AmbientON = true;
   }
}

/******************************************************************************/
/** \brief Schaltet das Directional Light ein oder aus
*******************************************************************************/
void LightManager::toggleDirectionalLight()
{
if (m_DirectionalON == true)
   {
   m_DirectionalON = false;
   }
else
   {
   m_DirectionalON = true;
   }
}

/******************************************************************************/
/** \brief Schaltet das Directional Light ein oder aus
*******************************************************************************/
void LightManager::toggleLightMap()
{
if (m_LightMapON == true)
   {
   m_LightMapON = false;
   }
else
   {
   m_LightMapON = true;
   }
}

/******************************************************************************/
/** \brief Korrigiert den Gammawert
    \param up true, false
*******************************************************************************/
void LightManager::stepGamma(bool up)
{
if (up == true)
   {
   m_gamma -= 0.1f;
   if (m_gamma < 0)
      m_gamma = 1;
   }
else
   {
   m_gamma += 0.1f;
   if (m_gamma > 1)
      m_gamma = 0;
   }

calcGamma(m_gamma);
//System.out.println("stepGamma " + (int)(10 * m_gamma));
}

/******************************************************************************/
/** \brief Info ob AmbientLight ON oder OFF
    \return true->ON, false-->OFF
*******************************************************************************/
bool LightManager::isAmbientON() {return (m_AmbientON);}

/******************************************************************************/
/** \brief Info ob DirectionalLight ON oder OFF
    \return true->ON, false-->OFF
*******************************************************************************/
bool LightManager::isDirectionalON() {return (m_DirectionalON);}

/******************************************************************************/
/** \brief Info ob LightMaps ON oder OFF
    \return true->ON, false-->OFF
*******************************************************************************/
bool LightManager::isLightMapON() {return (m_LightMapON);}

/******************************************************************************/
/** \brief Berechnet die Gamma-Rampe
    \param gamma
*******************************************************************************/
void LightManager::calcGamma(float gamma)
{
m_gamma = gamma;
float q;
int n;
for (int i=0; i < 256; i++)
   {
   q = (float)i/255.0f;
   n =           (int) ((255.0 * pow(q, m_gamma))+ 0.5);
   m_gammaR[i] = (int) ((255.0 * pow(q, m_gamma))+ 0.5);
   m_gammaG[i] = (int) ((255.0 * pow(q, m_gamma))+ 0.5);
   m_gammaB[i] = (int) ((255.0 * pow(q, m_gamma))+ 0.5);
   }
}


/****************************************************************************/
/** \brief Liest das Light-Objekt aus dem Inputstream
*   \param dataIn DataInputStream
*******************************************************************************/
void LightManager::load(DataInputStream& dataIn)
{
lightZoneList.clear();
int i, n, size1, size2;

try
   {
   size1 = dataIn.readInt();
   for (i=0; i < size1; i++)
      {
      int    zone       = dataIn.readInt();
      float ambient     = (float)dataIn.readDouble();
      float directional = (float)dataIn.readDouble();
      float omni        = (float)dataIn.readDouble();
      this->addEnvironment(zone, ambient, directional, omni);
      
      size2 = dataIn.readInt();
      for (n=0; n < size2; n++)
         {
         float x = (float)dataIn.readDouble();
         float y = (float)dataIn.readDouble();
         float z = (float)dataIn.readDouble();
         this->addPointLight(zone, x, y, z);    
         }
      }
   }
catch (std::exception eof)
   {
   printf("EOF");  // TODO: Logfile schreiben
   }
}

/******************************************************************************/
/** \brief Serialisiert das Light-Objekt in den Outputstream
    \param dataOut DataOutputStream
    \throws IOException 
*******************************************************************************/
void LightManager::save(DataOutputStream dataOut)
{
int i, n, size1, size2;

size1 = lightZoneList.size();

dataOut.writeInt(size1);
for (i=0; i < size1; i++)
  {
  LightZone* lightZone = (LightZone*)lightZoneList[i];
  int    zone       = lightZone->getZone();
  float ambient     = lightZone->getAmbient();
  float directional = lightZone->getDirectionalMax();
  float omni        = lightZone->getPointMax();

  dataOut.writeInt(zone);
  dataOut.writeDouble(ambient);
  dataOut.writeDouble(directional);
  dataOut.writeDouble(omni);

  size2 = lightZone->lightPointList.size();
  dataOut.writeInt(size2);
  for (n=0; n < size2; n++)
     {
     LightPoint* lp = (LightPoint*)lightZone->lightPointList[n];
     dataOut.writeDouble(lp->m_pos.m_x);
     dataOut.writeDouble(lp->m_pos.m_y);
     dataOut.writeDouble(lp->m_pos.m_z);
     }
  }
}

/******************************************************************************/
/** \brief Obligatorische dump-Methode fuer Debugzwecke
*******************************************************************************/
void LightManager::dump()
{
/*
int i;
System.out.println("----------Light----------");
for (i=0; i < lightEnvironmentList.size(); i++)
   {
   LightEnvironment le = (LightEnvironment)lightEnvironmentList.get(i);
   le.dump();
   }
System.out.println("Anzahl LightMaps=" + lightMaps.size());
System.out.println("----------Light----------");
*/
}
