//#define GL_ARB_draw_instanced 1

#include "escena.h"
#include    <cstdlib>
#include    <ctime>
#include    <sys/timeb.h>
#include <fstream>

Escena::Escena() : QGLWidget()
{

    program = 0;
    Index = 0;

    obj = 0;
    cub = 0;
    anchVolum = 0.0f;
    altVolum = 0.0f;
    profVolum = 0.0f;
    colorMode = 3;
    llum = new Llum();
    LUT = 0;
    crem = 3.0;
    gammaMida = 0.0;
    tamanyVolum =new vec4(100,100,100,100);
    background = false;
    K =0.0;
}

Escena::~Escena()
{
}

// Create a GLSL program object from vertex and fragment shader files
void Escena::InitShader(const char* vShaderFile, const char* fShaderFile)
{

    struct Shader {
        const char*  filename;
        GLenum       type;
        GLchar*      source;
    }  shaders[2] = {
        { vShaderFile, GL_VERTEX_SHADER, NULL },
        { fShaderFile, GL_FRAGMENT_SHADER, NULL }
    };


    QGLShader *vshader = new QGLShader(QGLShader::Vertex, this);
    QGLShader *fshader = new QGLShader(QGLShader::Fragment, this);

    // Es llegeixen els dos shaders: el vertex i el fragment shader
    for ( int i = 0; i < 2; ++i ) {
        Shader& s = shaders[i];
        s.source = Common::readShaderSource( s.filename );
        if ( shaders[i].source == NULL ) {
            std::cerr << "Failed to read " << s.filename << std::endl;
            exit( EXIT_FAILURE );
        }
   }
    vshader->compileSourceCode(shaders[0].source);
    fshader->compileSourceCode(shaders[1].source);
    program = new QGLShaderProgram(this);
    program->addShader(vshader);
    program->addShader(fshader);

    program->link();

    program->bind();

}

void Escena::initShadersGPU()
{
    //cout << "background "<<background <<endl;
  // Carrega dels shaders i posa a punt per utilitzar els programes carregats a la GPU
    InitShader( gpu->getVShader(), gpu->getFShader() );

}
void Escena::refresh()
{
    initializeGL();
    updateGL();
}

void Escena::initializeGL()
{
   // static const GLfloat lightPos[4] = { 5.0f, 5.0f, 10.0f, 1.0f };
    glEnable(GL_COLOR_MATERIAL);
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_BACK);
    glAlphaFunc ( GL_GREATER, 0.2 ) ;
    glEnable ( GL_ALPHA_TEST ) ;
    glEnable(GL_NORMALIZE);
    glDisable(GL_POINT_SMOOTH);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

   // qglClearColor(qtGreen.dark());

    camera.ini(this->size().width(), this->size().height(), capsaMinima,this->tamanyVolum);


    CalculCamera(false, true);

    glViewport(camera.vp.pmin[0], camera.vp.pmin[1], camera.vp.a, camera.vp.h);

  //  cout << "tamany viewport: "<< camera.vp.a<<" "<< camera.vp.h<<endl;
}



void Escena::CameraToGL()
{

    glViewport(0, 0, this->size().width(), this->size().height());
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMultTransposeMatrixf(camera.proj);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glMultTransposeMatrixf(camera.modView);

}

void Escena::paintGL()
{

    if (!this->isVisible())
        return;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    if(cub != 0){

        if(oneStepMode){

            cub->toGPU(program);
            obj->initMaterialsVolum(program);
            camera.toGPU(program);

            dadesRCtoGPU();

            cub->draw(program);

        } else {
            initBackfaceBuffers();
            renderBackface();

            initShadersGPU();

            cub->toGPU(program);
            obj->initMaterialsVolum(program);
            camera.toGPU(program);

            dadesRCtoGPU();

            cub->draw(program);

            //Eliminem els buffers per tal alliberar VRAM i no perdre la backface
            glDeleteFramebuffersEXT(1, &BFframebuffer);

            glDeleteRenderbuffersEXT(1, &BFrenderbuffer);

        }

    }
}

void Escena::textures2DtoGPU(GLuint texName1){

    glActiveTexture(GL_TEXTURE0+texName1);
    glBindTexture(GL_TEXTURE_2D, texName1);
    program->setUniformValue("backface", texName1);

}

void Escena::initBackfaceBuffers(){

    GLsizei w, h;

    GLint viewport[4];
    glGetIntegerv(GL_VIEWPORT,viewport);

    w = (int)viewport[2]; h = (int)viewport[3];


    // Depth buffer
    if(BFrenderbuffer == 0)
    glGenRenderbuffersEXT(1, &BFrenderbuffer);                // Generamos el buffer de renderizado y guardamos el ID en renderbuffer
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, BFrenderbuffer);   // Habilitamos el renderbuffer buffer

    // Establecemos un buffer al componente de profundidad con ancho y alto de ventana
    glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, w, h);

    // Establecemos el buffer de renderizado actual al depth buffer
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, BFrenderbuffer);

    // Deshabilitamos el buffer de renderizado
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);

    glDeleteTextures(1, &backface);
    // Buffer de textura
    if(backface == 0)
    glGenTextures(1, &backface);              // Generamos una textura
    glBindTexture(GL_TEXTURE_2D, backface);   // Asignamos la textura a backface

    // Creamos una textura del tamaño de la ventana
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

    // Parametros básicos para la textura
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    // Deshabilitamos la textura
    glBindTexture(GL_TEXTURE_2D, 0);

    if(BFframebuffer == 0)
    glGenFramebuffersEXT(1, &BFframebuffer);                  // Generamos un frame buffer y guardamos el ID en fbo
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, BFframebuffer);  // Habilitamos el frame buffer

    // Asignamos (attachment) la textura backface al buffer de color de nuestro frame buffer
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, backface, 0);

    // Asignamos (attachment) el depth buffer renderbuffer a nuestro frame buffer
    glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, BFrenderbuffer);

    // Revisamos el estado del frame buffer
    GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

    if (status != GL_FRAMEBUFFER_COMPLETE_EXT) // Si no está completo
    {
        // No se creo el FBO correctamente
    }

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Deshabilitamos nuestro frame buffer

}

void Escena::renderBackface(){

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, BFframebuffer);  // Preparamos el FBO para renderizado
    glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);  // Guardamos los estados de glEnable y glViewport
    glViewport(0, 0, camera.vp.a, camera.vp.h);  // Establecemos el tamaño del viewport del FBO

    //glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Limpia la pantalla y el buffer de profundidad

    glEnable(GL_CULL_FACE);
    glCullFace(GL_FRONT);

    CameraToGL();
    drawQuads(anchVolum, altVolum, profVolum);

    glDisable(GL_CULL_FACE);

    glPopAttrib();  // Reestablecemos los estados de glEnable y glViewport
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);    // Deshabilitamos el FBO
}

void Escena::vertex(float x, float y, float z)
{
    glColor3f(x,y,z);
    glVertex3f(x,y,z);
}
// this method is used to draw the front and backside of the volume
void Escena::drawQuads(float x, float y, float z)
{

    glBegin(GL_QUADS);
    /* Back side */
    glNormal3f(0.0, 0.0, -1.0);
    vertex(0.0, 0.0, 0.0);
    vertex(0.0, y, 0.0);
    vertex(x, y, 0.0);
    vertex(x, 0.0, 0.0);

    /* Front side */
    glNormal3f(0.0, 0.0, 1.0);
    vertex(0.0, 0.0, z);
    vertex(x, 0.0, z);
    vertex(x, y, z);
    vertex(0.0, y, z);

    /* Top side */
    glNormal3f(0.0, 1.0, 0.0);
    vertex(0.0, y, 0.0);
    vertex(0.0, y, z);
    vertex(x, y, z);
    vertex(x, y, 0.0);

    /* Bottom side */
    glNormal3f(0.0, -1.0, 0.0);
    vertex(0.0, 0.0, 0.0);
    vertex(x, 0.0, 0.0);
    vertex(x, 0.0, z);
    vertex(0.0, 0.0, z);

    /* Left side */
    glNormal3f(-1.0, 0.0, 0.0);
    vertex(0.0, 0.0, 0.0);
    vertex(0.0, 0.0, z);
    vertex(0.0, y, z);
    vertex(0.0, y, 0.0);

    /* Right side */
    glNormal3f(1.0, 0.0, 0.0);
    vertex(x, 0.0, 0.0);
    vertex(x, y, 0.0);
    vertex(x, y, z);
    vertex(x, 0.0, z);
    glEnd();

}

// raycastingGPU
void Escena::startRaycasting(){

    clock_t startC, finishC;
    struct timeb startT, finishT;
     double seconds, milliseconds;

    startC = clock();
    ftime(&startT);

    makeCurrent();

    cub = new Cub(anchVolum, altVolum, profVolum);
    cub->make();

    GLubyte *dataLut = getLutBytes(LUT);

    glDeleteTextures(1, &texturaLut);
    glGenTextures(1, &texturaLut);
    glBindTexture(GL_TEXTURE_1D, texturaLut);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256,0, GL_RGBA, GL_UNSIGNED_BYTE, dataLut);

    oneStepMode = true;
    if(oneStepMode){
        initShadersGPU();
    }

    updateGL();

    finishC = clock();
    ftime(&finishT);
    seconds = finishT.time - startT.time - 1;
    milliseconds = (1000.0 - startT.millitm) + finishT.millitm;

 /*   cout << "\n RayCasting GPU "<<endl;
    cout << "Time (clock): "    << (finishC - startC)/CLOCKS_PER_SEC << endl;
    cout << "Time (difftime): " << difftime(finishC, startC) << endl;
    cout << "Time (ftime): " << (milliseconds + seconds * 1000) << endl; */

}

void Escena::resizeGL(int width, int height)
{
    glViewport(0, 0, width, height);
    camera.vp.a = width;
    camera.vp.h=height;
    camera.vp.pmin = vec2(0,0);

}


void Escena::mousePressEvent(QMouseEvent *event)
{

    lastPos = event->pos();
   // cout << "***** CLICK PIXEL " << lastPos.x() << " " << lastPos.y() << endl;

}

void Escena::mouseMoveEvent(QMouseEvent *event)
{
    /*clock_t startC, finishC;
    struct timeb startT, finishT;
    unsigned int seconds, milliseconds;

    startC = clock();
    ftime(&startT);*/

   // cout << "************* DRAGING: " << lastPos.x() << " " << lastPos.y() << endl;

    //--------------------------------------------------------
    //BLOQUEJAR
    int dx = event->x() - lastPos.x();
    int dy = event->y() - lastPos.y();

    if (event->buttons() & Qt::LeftButton)
    {
        // Si no estem a mode seleccio: s'edita la camera
        // Si estem a mode seleccio: cal moure l'objecte clicat

            if(lastPos.y()!= event->y() && lastPos.x()!= event->x()) {
                // Fer les rotacions necessaries
                //setXRotation(dy);
                setYRotation(dx);
                //setZRotation(dx);

            } else if(lastPos.y()!= event->y()) {// rotar la camera
               // Fer les rotacions necessaries
                //setXRotation(dy);
            } else if (lastPos.x()!= event->x()) {

                // Fer les rotacions necessaries
                setYRotation(dx);
                //setZRotation(dx);
            }


    } else if (event->buttons() & Qt::RightButton) {

        // Panning: moure el centre de la window

        Pan(dx, dy);

    } else if (event->buttons() & Qt::MidButton) {

       // Zoom: canviar el tamany de la window
        if(lastPos.y() > event->y())
             Zoom(-1);
        else
             Zoom(1);
    }

    lastPos = event->pos();

    //--------------------------------------------------------
/*
    finishC = clock();
    ftime(&finishT);
    seconds = finishT.time - startT.time - 1;
    milliseconds = (1000 - startT.millitm) + finishT.millitm;
*/
}

static void qNormalizeAngle(double &angle)
{
    while (angle < 0)
        angle += 360;
    while (angle > 360)
        angle -= 360;
}

void Escena::setXRotation(int angle)
{

    if (angle >0) {
        camera.vs.angx -= 5;
    } else if (angle<0)
        camera.vs.angx += 5;
    qNormalizeAngle(camera.vs.angx);

    emit xRotationChanged(angle);
    CalculCamera(false,false);
    updateGL();

}
void Escena::setZRotation(int angle)
{

    if (angle >0) {
        camera.vs.angz -= 5;
    } else if (angle<0)
        camera.vs.angz += 5;
    qNormalizeAngle(camera.vs.angz);

    emit zRotationChanged(angle);
    CalculCamera(false,false);
    updateGL();

}
void Escena::setYRotation(int angle)
{
    //BLOQUEJAR

    if (angle >0) {
        camera.vs.angy -= 5;
    } else if (angle<0)
        camera.vs.angy += 5;

    qNormalizeAngle(camera.vs.angy);

    emit yRotationChanged(angle);
    CalculCamera(false,false);
    updateGL();

}

void Escena::Pan(int dx, int dy) {


    if (dx > 0 ) {
        camera.wd.pmin[0] -= 1.0;
    }
    else if (dx < 0 ) {
        camera.wd.pmin[0] += 1.0;
    }
    if (dy > 0 ) {
        camera.wd.pmin[1] += 1.0;
    }
    else if (dy < 0 ) {
        camera.wd.pmin[1] -= 1.0;
    }
    //cout <<dx <<" "<<dy<<endl;
    emit PanChanged(dx, dy);
    CalculCamera(true,false);
    updateGL();
}

void Escena::Zoom (int positiu) {

    camera.AmpliaWindow(positiu*0.05);
    emit ZoomChanged(positiu);
    CalculCamera(true, false);
    updateGL();

}

void Escena::CapsaMinCont3DEscena()
{

    //Calcula la capsa minima dels objectes de la llista d'objectes

    capsaMinima.pmin = vec3(0.0,0.0,0.0);
    capsaMinima.a = anchVolum;
    capsaMinima.h = altVolum;
    capsaMinima.p = profVolum;
 /*  capsaMinima.a = this->tamanyVolum->x;
    capsaMinima.h = this->tamanyVolum->z;
    capsaMinima.p = this->tamanyVolum->y;*/

}

void Escena::CalculCamera(bool retallat, bool centrat)
{
    double r;

    if(centrat){
        CapsaMinCont3DEscena();

        camera.vs.vrp[0] = capsaMinima.pmin[0]+((tamanyVolum->x)/2.0);
        camera.vs.vrp[1] = capsaMinima.pmin[1]+((tamanyVolum->z)/2.0);
        camera.vs.vrp[2] = capsaMinima.pmin[2]+((tamanyVolum->y)/2.0);

       /* camera.vs.vrp[0] = 72;
        camera.vs.vrp[1] = 72;
        camera.vs.vrp[2] = 106;*/
        capsaMinima.a = tamanyVolum->x;
        capsaMinima.h = tamanyVolum->z;
        capsaMinima.p = tamanyVolum->y;
        camera.CalculWindow(capsaMinima);
        CapsaMinCont3DEscena();

    }

    if(!retallat){
        r = 1.2 * sqrt(pow((capsaMinima.a), 2) +
                pow((capsaMinima.h), 2) +pow((capsaMinima.p), 2));

    /* dist obs-vrp en paral.lela: un valor fictici pero a vegades convenient */
 //   cout<< " radi  "<<r <<endl;
//    cout <<" dant "<<camera.piram.dant <<endl;
 //   cout <<" dpos "<< camera.piram.dpost<<endl;
    camera.piram.dant = camera.piram.d -0.5*r;
     camera.piram.dpost = camera.piram.d + 0.5*r;
   // camera.piram.dant = -8000;
   //  camera.piram.dpost = camera.piram.d + 50*r;
    }

    if(retallat){

        camera.CalculWindowAmbRetallat();
    }

    camera.CalculaMatrius();//sempre
    camera.CalculAngleOberturaHoritzontal();//sempre
    camera.CalculAngleOberturaVertical();//sempre


}

void Escena::addVolumen(volumen *v){
    makeCurrent();

    obj = v;
    anchVolum = v->anchura;
    altVolum = v->altura;
    profVolum = v->profundidad;

    creaTextura3D();
    CapsaMinCont3DEscena();
    CalculCamera(false,true);


}

// Mascara GPU crear clon
void Escena::creaTextura3D(){

    //Pre-condicio: obj inicialitzat amb els voxels.
    Capsa3D capsaVolum = obj->calculCapsa3D();
    int anchura = (int)capsaVolum.a;
    int altura = (int)capsaVolum.h;
    int profundidad = (int)capsaVolum.p;
    int size = anchura*altura*profundidad*sizeof(GLfloat)*4;

    GLfloat *data = (GLfloat *)malloc(size);
    int Index = 0;
    for(int k = 0; k < profundidad; k++){
        for(int j = 0; j < altura; j++){
            for(int i = 0; i < anchura; i++){
                float valor = obj->getVoxel(i, j ,k);
                //int aux = valor;
                data[Index] = valor;
                data[Index+1] = valor;
                data[Index+2] = valor;
                data[Index+3] = valor;
                Index += 4;
            }
        }
    }

    glDeleteTextures(1, &texturaVolum);

    glPixelStorei(GL_UNPACK_ALIGNMENT,1);
    glGenTextures(1, &texturaVolum);
    glBindTexture(GL_TEXTURE_3D, texturaVolum);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
    glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, altura, anchura, profundidad,0, GL_RGBA, GL_FLOAT, data);


    // LO MATEIX PERO ARA AMB LA MASCARA
    GLfloat *mdata = (GLfloat *)malloc(size);
    Index = 0;
    for(int k = 0; k < profundidad; k++){
        for(int j = 0; j < altura; j++){
            for(int i = 0; i < anchura; i++){
                float valor;
                valor = obj->getVoxelMask(i, j ,k);
             //   int aux = valor;
                mdata[Index] = valor;
                mdata[Index+1] = valor;
                mdata[Index+2] = valor;
                mdata[Index+3] = valor;
                Index += 4;
            }
        }
    }

    glDeleteTextures(1, &texturaMask);

    glPixelStorei(GL_UNPACK_ALIGNMENT,1);
    glGenTextures(1, &texturaMask);
    glBindTexture(GL_TEXTURE_3D, texturaMask);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
    glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, altura, anchura, profundidad,0, GL_RGBA, GL_FLOAT, mdata);

}

void Escena::texturaLutToGPU(){
    glActiveTexture(GL_TEXTURE0+texturaLut);
    glBindTexture(GL_TEXTURE_1D, texturaLut);
    program->setUniformValue("texturaLut", texturaLut);

}

GLubyte *Escena::getLutBytes(Lut* lutActual)
{
    GLubyte *dataLut = (GLubyte *)malloc(256*4);
    int idx = 0;
    for(int i = 0; i < 256; i++){
        float *color = lutActual->getColor(i);
        int r = color[0]*255;
        int g = color[1]*255;
        int b = color[2]*255;
        int a = color[3]*255;

       unsigned char rU, gU, bU, aU;
        rU = r;
        gU = g;
        bU = b;
        aU = a;
        dataLut[idx] = rU;
        dataLut[idx+1] = gU;
        dataLut[idx+2] = bU;
        dataLut[idx+3] = aU;
        idx += 4;
    }
    return dataLut;

}

void Escena::eliminaCub()
{

    cub = 0;
}

void Escena::dadesRCtoGPU(){

    program->setUniformValue("anchura", anchVolum);
    program->setUniformValue("altura", altVolum);
    program->setUniformValue("profundidad", profVolum);

    if(!oneStepMode){
        textures2DtoGPU(backface);
        program->setUniformValue("rcMode", -1);
    } else {
        program->setUniformValue("rcMode", 0);
    }


    texturaLutToGPU();
    llum->toGPU(program);

// mascara
    glActiveTexture(GL_TEXTURE0+texturaVolum);
    glBindTexture(GL_TEXTURE_3D, texturaVolum);
    program->setUniformValue("texturaVolum", texturaVolum);
    glActiveTexture(GL_TEXTURE0+texturaMask);
    glBindTexture(GL_TEXTURE_3D, texturaMask);
    program->setUniformValue("texturaMask", texturaMask);


    program->setUniformValue("umbralOpacitat", opacitat/**100*/);
    program->setUniformValue("umbralSaturacio", saturacio);
    program->setUniformValue("stepsize", sampling/(sqrt(3.0f)*max(max(anchVolum, altVolum), profVolum)));
    program->setUniformValue("crem", crem);
    program->setUniformValue("cx",ColorMask.x);
    program->setUniformValue("cy", ColorMask.y);
    program->setUniformValue("cz",ColorMask.z);
    program->setUniformValue("alpha",ColorMask.w);
    program->setUniformValue("gamma", this->gammaMida);
    program->setUniformValue("background",this->background);
    program->setUniformValue("k",this->K);

    GLuint p = program->uniformLocation("colorMask");
    glUniformMatrix4fv(p, 1, GL_TRUE,ColorMask);

}

void Escena::setOpacitat(float op)
{
    opacitat = op;
    updateGL();
}
void Escena::setCrem(float cr)
{
    crem = cr;
    updateGL();
}

void Escena::setSaturacio(float sat)
{
    saturacio = sat;
    updateGL();
    //this->repaint();
   // cout <<"escena sat "<<saturacio<<endl;
}
void Escena::setSampling(float samp)
{
    sampling = samp;
    updateGL();
}

void Escena::setColorMode(int mode)
{
    colorMode = mode;
    updateGL();
}

void Escena::setGamma(float gamma){
    this->gammaMida = gamma;
    updateGL();
}

void Escena::setOneStepRaycastingMode(bool mode)
{
    oneStepMode = mode;
    updateGL();
}

void Escena::setRampColorTable(QVector<unsigned int> qrgbcolors)
{
    LUT = new Lut(qrgbcolors);

    GLubyte *dataLut = getLutBytes(LUT);

    glBindTexture(GL_TEXTURE_1D, texturaLut);
    glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256,0, GL_RGBA, GL_UNSIGNED_BYTE, dataLut);

    updateGL();

}

void Escena::setInitialLUT(QVector<unsigned int> qrgbcolors)
{
    LUT = new Lut(qrgbcolors);
}

void Escena::cargarVolumen(char* fitxer,float anch, float alt,float profu,QString tipoUns){
    volumen* vol = new volumen(fitxer,anch,alt,profu,tipoUns);
    this->addVolumen(vol);
    this->eliminaCub();
  //  this->resize(this->size().width()*2, this->size().height()*2);
  //  this->resizeGL(this->size().width()*2, this->size().height()*2);

}

volumen* Escena::getVolum(){
    return this->obj;
}

Camera Escena::getCamera(){
    return this->camera;
}

Capsa3D Escena::getCapsaMinima(){
    return this->capsaMinima;
}
Llum* Escena::getLlum(){
    return this->llum;
}
void Escena::setLoadedLUT(){
    obj->setLoadedLUT(LUT);
}

void Escena::setGPU(GPU* gp){
    this->gpu = gp;
}

void Escena::activaMask(bool p){
    obj->activamask(p);
    //cout<<"mascara:"<<p<<endl;
    creaTextura3D();
    this->repaint();
    this->updateGL();
}

void Escena::onlyMask(bool p){
    obj->onlyMask(p);
    creaTextura3D();
    this->repaint();
    this->updateGL();
}
void Escena::setColorMask(QColor c){
    ColorMask.x = abs(c.red())/255.0;
    ColorMask.y = abs(c.green())/255.0;
    ColorMask.z = abs(c.blue())/255.0;
    ColorMask.w = abs(c.alpha())/255.0;
    this->repaint();
    updateGL();

}
void Escena::setTamanyVolum(vec4 *TV){
    this->tamanyVolum = TV;

    camera.ini(this->size().width(), this->size().height(), capsaMinima,this->tamanyVolum);
}
void Escena::showLut(){
    obj->showLut();
}

void Escena::setK(float p){
    this->K = p;
    updateGL();
    this->repaint();
   //cout <<K<<endl;
}

void Escena::cambibackground(){
    if (background) {
        background = false;
         glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    }
    else{
        background = true;
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    }
    //cout<<" background "<<background;
    this->repaint();
    updateGL();
}

void Escena::keyPressEvent(QKeyEvent *event)
{

   cout << " moure y" <<endl;
    if ( event->key() == Qt::Key_Right){
       this->setYRotation(1);
    }

    updateGL();

}
