#include "gray_scale_cpu.h"

Gray_Scale_cpu::Gray_Scale_cpu()
{
}
Gray_Scale_cpu::Gray_Scale_cpu(textureWidget* tx)
{
    this->texturewidget = tx;
}
GLubyte* Gray_Scale_cpu::raycastingCPU(Parametres* p){

    Camera cam = p->camera;
    Capsa3D cub = p->capsaminima;
    int colorMode = p->colorMode;
    Llum* llum = p->llum;
    float crem = p->crem;
    raig = new Raig;

    CarregaParametres(p);

   this->hit = 0;

   int vwidth = p->camera.vp.a;  //amplitud de la imatge final (viewport)
   int vheight = p->camera.vp.h; //altura de la imatge final (viewport)
   int index = 0;

   mat4 MSIV;
   cam.CreaMatSiv(MSIV);

   vec3 pw;

   vec3 colors[vwidth*vheight];
   bool interseccio = false;

    // per cada pixel de la imatge
  // cout << "crem "<<crem<<endl;
   for(int i = 0; i < vheight; i++){
       for(int j = 0; j < vwidth; j++){
            //colors[index] = vec3(0.0,0.0,0.0);
           /*  CALCULEM EL RAIG    */
           pw.x = (j*cam.wd.a)/(float)vwidth + cam.wd.pmin[0];
           pw.y = ((i)/(float)vheight)*cam.wd.h + cam.wd.pmin[1];
           raig->calculRaig(j, i, cam.piram.d, cam.piram.proj, pw, MSIV);

           /*  TROBEM LES INTERSECCIONS tnear tfar DEL RAIG AMB EL MON DE VOXELS (CUB)    */
           tnear = -INFINITY;
           tfar = INFINITY;
           interseccio = intersecta(raig, cub, -300.0f, 300.0f);

           //Calculem la iluminacio del pixel final a dibuixar
           if(interseccio){
//                   colors[index] = calculIluminacioFTB(cub, *raig);
               vec4 aux = calculIluminacioFTB(cub, *raig, colorMode, llum);
               aux.x = aux.x*crem; if (aux.x > 255) aux.x=255; if (aux.x < 0) aux.x=0;
               aux.y = aux.y*crem; if (aux.y > 255) aux.y=255; if (aux.y < 0) aux.y=0;
               aux.z = aux.z*crem; if (aux.z > 255) aux.z=255;if (aux.z < 0) aux.z=0;
               colors[index] = vec3(255-aux.x, 255-aux.y, 255-aux.z);

           }else{
               colors[index] = vec3(255,255,255);
           }

       index++;

       }
   }

   const int dimx = vwidth, dimy = vheight;
   int nb = dimx * dimy * 3;
   GLubyte *bytes;
   bytes = (GLubyte  *) malloc(nb);

 int m = 0;
 int n = 0;
 index = 0;
 FILE *fp = fopen("imatge.ppm", "wb"); /* b - binary mode */
// FILE *fp = fopen("../imatge.ppm", "wb"); /* b - binary mode */

 (void) fprintf(fp, "P6\n%d %d\n255\n", dimx, dimy);
 for (n = dimy; n >= 0; n--)
 {
   for (m = 0; m < dimx; m++)
   {
    unsigned char tmp[3];
       tmp[0] = (unsigned char)colors[m+n*dimx][0];
       tmp[1] = (unsigned char)colors[m+n*dimx][1];
       tmp[2] = (unsigned char)colors[m+n*dimx][2];
       (void) fwrite(tmp, sizeof(unsigned char), 3, fp);

     index++;
   }
//        (void) fprintf(fp, "\n");
 }
 (void) fclose(fp);


 return bytes;

}
vec4 Gray_Scale_cpu::calculIluminacioFTB(Capsa3D cub, Raig raig, int colorMode, Llum *llum){
    vec3 samplingPoint;
    vec3 pmins, pmaxs; /* PUNTS DEL CUB QUE ENVOLTA EL PUNT QUE CERQUEM (INTERPOLACIO TRILINEAL) */
    float d000, d100, d010, d001, d101, d011, d110, d111, dxyz;

    vec4 coloracum = vec4(0.0,0.0,0.0,0.0);
    vec4 colorActual = vec4(-1.0, -1.0, -1.0, -1.0);
    float alfaacum, alfaActual, v;
    float x, y ,z, fx, fy, fz;
    int x0, y0, z0, x1, y1, z1;
    int i,j,k;
    coloracum = vec4(0,0,0,0);
    alfaacum = 0;

    float lambda = tnear;
    float vmask = 0.0;


    while(lambda < tfar && alfaacum < 1.0){

        /* INTERPOLACIO TRILINEAL (CERCA DEL PUNT A MOSTREJAR DEL MON) */

        samplingPoint = raig.p + lambda*raig.v;
        pmins = vec3(((int)samplingPoint.x), ((int)samplingPoint.y), ((int)samplingPoint.z));
        pmaxs = vec3((int)samplingPoint.x+1, (int)samplingPoint.y+1, (int)samplingPoint.z+1);

        x = samplingPoint.x; y = samplingPoint.y; z = samplingPoint.z;

        z0 = (int)z;z1 = z0 + 1;fz = z - z0;
        y0 = (int)y;y1 = y0 + 1;fy = y - y0;
        x0 = (int)x;x1 = x0 + 1;fx = x - x0;

        if(x0>=0&&x1<cub.a&&y0>=0&&y1<cub.h&&z0>=0&&z1<cub.p){

            d000 = getVoxel(x0,y0,z0);
            vmask = getVoxelMask(x0,y0,z0);
            d001 = getVoxel(x0,y0,z0+1);
            d010 = getVoxel(x0,y0+1,z0);
            d011 = getVoxel(x0,y0+1,z0+1);

            d100 = getVoxel(x1,y0,z0);
            d101 = getVoxel(x1,y0,z1);
            d110 = getVoxel(x1,y1,z0);
            d111 = getVoxel(x1,y1,z1);

            dxyz = (((d000*(1-fx)+d001*fx)*(1-fy)+(d010*(1-fx)+d011*fx )*fy)*(1-fz)
            + ((d100*(1-fx)+d101*fx)*(1-fy)+(d110*(1-fx)+d111*fx)*fy)*fz);

        } else {
            dxyz = 0.0f;
        }

        v = dxyz;
        if (vmask > 0) {
          //  coloracum = vec4(0.0,d000,d000,0.0);
           // colorActual = vec4(0.0,d000,d000,0.0);
           // coloracum = *(this->colormascara);
           // colorActual = *(this->colormascara);
           // alfaacum = colormascara->w;
            alfaacum = 1.0;
            return *(this->colormascara);
            //cout << "Color Mascara "<<this->colormascara->x<<" "<<this->colormascara->y<< " "<<this->colormascara->z <<" "<<this->colormascara->w<<endl;

        }
        else {
            if(v > UMBRAL_SATURACIO){
                alfaActual = (v)*UMBRAL_OPACITAT; //fer constants factor alfa / factor color
                if(alfaActual > 0){

                    colorActual = getColorActual(colorMode, v, x0, y0, z0, llum, colorActual);

                    coloracum = coloracum + (1-(alfaacum))*colorActual*alfaActual;

                    alfaacum = alfaacum + (1-alfaacum)*alfaActual;
                    if(alfaacum > 1.0){
                        alfaacum = 1.0;
                    }
                }
            }
        }
        lambda += raig.incrementMostreig;
    }

    if(fabs(alfaacum-1) < 0.001)
        hit++;

    coloracum = vec4((int)(coloracum.x*255),(int)(coloracum.y*255),(int)(coloracum.z*255), (int)(coloracum.w*255));
    return coloracum;

}

vec4 Gray_Scale_cpu::getColorActual(int mode, float v, int i, int j, int k, Llum *llum, vec4 colorMax)
{

    vec4 color = vec4(0.0,0.0,0.0,0.0);


        color = vec4(v, v, v, v);
        if(color.x < UMBRAL_SATURACIO)color = vec4(0.0,0.0,0.0,0.0);


    return color;

}
