

#include "maths_defs.h"
#include "Cubemap.h"
#include "Png.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;


ostream& operator<<(ostream& o, const Color& _color)
{
  o << '(' << _color.x << ',' << _color.y << ',' << _color.z << ')';
  return o;
}

bool Cubemap::Init(const std::string& nom)
{
  if (nom.find("png") == string::npos)
     return false;
  unsigned char **Textures=0;

  Textures = pngImage.loadPNG(nom,sizeX,sizeY);
  if (!Textures)
  {
    cout << "Cubemap::Init - Error while loading the png texture !" << endl;
    return false;
  }

  // allouer tab
  tab = new Color* [sizeY];
  for (unsigned i=0;i<sizeY;i++)
      tab[i] = new Color [sizeX];


  // convertir Textures en tab
  real r=0,g=0,b=0;

  for (unsigned j=0;j<sizeY;j++)
  {
    for (unsigned i=0;i<sizeX;i++)
    {
      r = static_cast<real>(Textures[j][i*pngImage.bytes_per_pixel+0] / 255.0);
      g = static_cast<real>(Textures[j][i*pngImage.bytes_per_pixel+1] / 255.0);
      b = static_cast<real>(Textures[j][i*pngImage.bytes_per_pixel+2] / 255.0);
      tab[i][j] = Color(r,g,b);
    }
  }
  return true;
}


Color Cubemap::readTexture(const real& u, const real& v)
{
     real _u = ABS(u);
     real _v = ABS(v);
     int umin = static_cast<int>(sizeX * _u);
     int vmin = static_cast<int>(sizeY * _v);

     real ucoef = ABS(sizeX * _u - umin);
     real vcoef = ABS(sizeY * _v - vmin);

     unsigned indexU = umin % sizeX;
     unsigned indexV = vmin % sizeY;
     
     unsigned indexUp = (umin+1) % sizeX;
     unsigned indexVp = (vmin+1) % sizeY;

     Color c1 = tab[indexU][indexV],
           c2 = tab[indexUp][indexV],
           c3 = tab[indexU][indexVp],
           c4 = tab[indexUp][indexVp];

     Color output =  (1.0 - vcoef) * ((1.0 - ucoef) * c1
                        +                    ucoef  * c2)
                        +    vcoef * ((1.0 - ucoef) * c3
                        +                    ucoef  * c4);
     return output;
}

Color Cubemap::Read(const Ray& ray)
{
   Color outputCouleur;
   
   real rdirX = ABS(ray.direction.x);
   real rdirY = ABS(ray.direction.y);
   real rdirZ = ABS(ray.direction.z);


   if ((rdirX >= rdirY) && (rdirX >= rdirZ))
   {
       if (ray.direction.x > 0.0)
       {
           outputCouleur = readTexture(
               1.0 - (ray.direction.z / ray.direction.x + 1.0) * 0.5,
                     (ray.direction.y / ray.direction.x + 1.0) * 0.5);
       }
       else// if (ray.direction.x < 0.0)
       {
           outputCouleur = readTexture(
               1.0 - (ray.direction.z / ray.direction.x + 1.0) * 0.5,
               1.0 - (ray.direction.y / ray.direction.x + 1.0) * 0.5);
       }
   }
   else if ((rdirY >= rdirX) && (rdirY >= rdirZ))
   {
       if (ray.direction.y > 0.0)
       {
           outputCouleur = readTexture(
                     (ray.direction.x / ray.direction.y + 1.0) * 0.5,
               1.0 - (ray.direction.z / ray.direction.y + 1.0) * 0.5);
       }
       else// if (ray.direction.y < 0.0)
       {
           outputCouleur = readTexture(
               1.0 - (ray.direction.x / ray.direction.y + 1.0) * 0.5,
                     (ray.direction.z / ray.direction.y + 1.0) * 0.5);
       }
   }
   else if ((rdirZ >= rdirX) && (rdirZ >= rdirY))
   {
       if (ray.direction.z > 0.0)
       {
           outputCouleur = readTexture(
               (ray.direction.x / ray.direction.z + 1.0) * 0.5,
               (ray.direction.y / ray.direction.z + 1.0) * 0.5);
       }
       else// if (ray.direction.z < 0.0)
       {
           outputCouleur = readTexture(
                   (ray.direction.x / ray.direction.z + 1.0) * 0.5,
               1 - (ray.direction.y / ray.direction.z + 1.0) * 0.5);
       }
   }

   return outputCouleur;
}

