#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "structures.h"
#include "prototypes.h"



void creerImage2D (RepertoireDObjets objets, Couleur tableauPixel[][HAUTEUR_IMAGE])
{
    Coordonnees coinSupGauche = {0.0, 0.0, 0.0}, pixel3D = {0.0, 0.0, 0.0};
    Vecteur upVec = {0.0, 1.0, 0.0}, rightVec = {0.0, 0.0, 0.0}, camVectDir = {0.0, 0.0, 0.0};
    double viewplaneDist = 400.0, viewplaneHeight = 0.35, viewplaneWidth = 1.0, xIndent = 0.0, yIndent = 0.0;
    int x = 0, y = 0;
    Rayon rayon = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};

    if (objets.nbCamera == 0)
    {
        return;
    }


    camVectDir.x = (objets.camera[objets.nbCamera-1].lookAt.x - objets.camera[objets.nbCamera-1].location.x);
    camVectDir.y = (objets.camera[objets.nbCamera-1].lookAt.y - objets.camera[objets.nbCamera-1].location.y);
    camVectDir.z = (objets.camera[objets.nbCamera-1].lookAt.z - objets.camera[objets.nbCamera-1].location.z);

    normalise(&camVectDir);

    rightVec = produitVectoriel(upVec, camVectDir);
    normalise(&rightVec);
    upVec = produitVectoriel(camVectDir, rightVec);
    normalise(&upVec);




    coinSupGauche.x = objets.camera[objets.nbCamera-1].location.x + (camVectDir.x*viewplaneDist) + (upVec.x*(viewplaneHeight/2.0)) - (rightVec.x*(viewplaneWidth/2.0));
    coinSupGauche.y = objets.camera[objets.nbCamera-1].location.y + (camVectDir.y*viewplaneDist) + (upVec.y*(viewplaneHeight/2.0)) - (rightVec.y*(viewplaneWidth/2.0));
    coinSupGauche.x = objets.camera[objets.nbCamera-1].location.z + (camVectDir.z*viewplaneDist) + (upVec.z*(viewplaneHeight/2.0)) - (rightVec.z*(viewplaneWidth/2.0));



    xIndent = viewplaneHeight/((double)HAUTEUR_IMAGE);
    yIndent = viewplaneWidth/((double)LARGEUR_IMAGE);


    rayon.origine.x = objets.camera[objets.nbCamera-1].location.x;
    rayon.origine.y = objets.camera[objets.nbCamera-1].location.y;
    rayon.origine.z = objets.camera[objets.nbCamera-1].location.z;


    for (x = 0; x < LARGEUR_IMAGE; x++)
    {
        for (y = 0; y < HAUTEUR_IMAGE; y++)
        {
            pixel3D.x = coinSupGauche.x - upVec.x*xIndent*x + rightVec.x*yIndent*y;
            pixel3D.y = coinSupGauche.y - upVec.y*xIndent*x + rightVec.y*yIndent*y;
            pixel3D.z = coinSupGauche.z - upVec.z*xIndent*x + rightVec.z*yIndent*y;



            //rayon.direction.x = (pixel3D.x - rayon.origine.x);
            //rayon.direction.y = (pixel3D.y - rayon.origine.y);
            //rayon.direction.z = (pixel3D.z - rayon.origine.z);

            rayon.direction.x = (camVectDir.x*viewplaneDist)-(double)(x-LARGEUR_IMAGE/2)*upVec.x + (double)(y-HAUTEUR_IMAGE/2)*rightVec.x - rayon.origine.x;
            rayon.direction.y = (camVectDir.y*viewplaneDist)-(double)(x-LARGEUR_IMAGE/2)*upVec.y + (double)(y-HAUTEUR_IMAGE/2)*rightVec.y - rayon.origine.y;
            rayon.direction.z = (camVectDir.z*viewplaneDist)-(double)(x-LARGEUR_IMAGE/2)*upVec.z + (double)(y-HAUTEUR_IMAGE/2)*rightVec.z - rayon.origine.z;



            normalise(&rayon.direction);




            tableauPixel[x][y] = determineCouleurPixel(objets, rayon);
        }
    }


}



Couleur determineCouleurPixel (RepertoireDObjets objets, Rayon rayon)
{
    Couleur pixel = {0, 0, 0}, pixelFinal = {0, 0, 0};
    Couleur *couleurLumiere = NULL;
    Coordonnees intersection = {0.0, 0.0, 0.0}, petitX = {0.0, 0.0, 0.0}, grandX = {0.0, 0.0, 0.0}, petitY = {0.0, 0.0, 0.0};
    Coordonnees grandY = {0.0, 0.0, 0.0}, petitZ = {0.0, 0.0, 0.0}, grandZ = {0.0, 0.0, 0.0};
    Objet objetTouche = {RIEN, 0};
    Vecteur normal = {0.0, 0.0, 0.0};
    int i = 0;



    if (objets.nbBackground > 0)
    {
        pixel = objets.background[objets.nbBackground - 1].couleur;
    }

    objetTouche = envoieRayon(objets, rayon, &intersection);



    if (objetTouche.type == RIEN)
    {
        return pixel;
    }
    else
    {
        if (objetTouche.type == PLAN)
        {
            pixel = objets.plan[objetTouche.index].couleur;
            normal = objets.plan[objetTouche.index].vecteurNormal;
        }
        else if (objetTouche.type == BOX)
        {
            pixel = objets.box[objetTouche.index].couleur;

            if (objets.box[objetTouche.index].point1.x < objets.box[objetTouche.index].point2.x)
            {
                petitX = objets.box[objetTouche.index].point1;
                grandX = objets.box[objetTouche.index].point2;
            }
            else
            {
                petitX = objets.box[objetTouche.index].point2;
                grandX = objets.box[objetTouche.index].point1;
            }

            if (objets.box[objetTouche.index].point1.y < objets.box[objetTouche.index].point2.y)
            {
                petitY = objets.box[objetTouche.index].point1;
                grandY = objets.box[objetTouche.index].point2;
            }
            else
            {
                petitY = objets.box[objetTouche.index].point2;
                grandY = objets.box[objetTouche.index].point1;
            }

            if (objets.box[objetTouche.index].point1.z < objets.box[objetTouche.index].point2.z)
            {
                petitZ = objets.box[objetTouche.index].point1;
                grandZ = objets.box[objetTouche.index].point2;
            }
            else
            {
                petitZ = objets.box[objetTouche.index].point2;
                grandZ = objets.box[objetTouche.index].point1;
            }


            normal.x = 1.0;
            normal.y = 0.0;
            normal.z = 0.0;


            if (appartientAuPlan(normal, grandX, intersection))
            {
                normal.x = 1.0;
                normal.y = 0.0;
                normal.z = 0.0;
            }
            else if (appartientAuPlan(normal, petitX, intersection))
            {
                normal.x = -1.0;
                normal.y = 0.0;
                normal.z = 0.0;
            }
            else
            {
                normal.x = 0.0;
                normal.y = 1.0;
                normal.z = 0.0;

                if (appartientAuPlan(normal, grandY, intersection))
                {
                    normal.x = 0.0;
                    normal.y = 1.0;
                    normal.z = 0.0;
                }
                else if (appartientAuPlan(normal, petitY, intersection))
                {
                    normal.x = 0.0;
                    normal.y = -1.0;
                    normal.z = 0.0;
                }
                else
                {
                    normal.x = 0.0;
                    normal.y = 0.0;
                    normal.z = 1.0;

                    if (appartientAuPlan(normal, grandZ, intersection))
                    {
                        normal.x = 0.0;
                        normal.y = 0.0;
                        normal.z = 1.0;
                    }
                    else
                    {
                        normal.x = 0.0;
                        normal.y = 0.0;
                        normal.z = -1.0;
                    }
                }

            }
        }
        else if (objetTouche.type == SPHERE)
        {
            pixel = objets.sphere[objetTouche.index].couleur;

            normal.x = intersection.x - objets.sphere[objetTouche.index].centre.x;
            normal.y = intersection.y - objets.sphere[objetTouche.index].centre.y;
            normal.z = intersection.z - objets.sphere[objetTouche.index].centre.z;
        }
        else if (objetTouche.type == CYLINDRE)
        {

        }
        else if (objetTouche.type == CONE)
        {

        }
        else if (objetTouche.type == TORUS)
        {

        }


    }

    normalise(&normal);


    couleurLumiere = malloc(objets.nbLumiere * sizeof(Couleur));

    if (couleurLumiere == NULL)
    {
        exit(0);
    }

    for (i = 0; i < objets.nbLumiere; i++)
    {
        couleurLumiere[i] = getLumiere(objets, i, objetTouche, intersection, normal, pixel);
    }

    for (i = 0; i < objets.nbLumiere; i++)
    {
        pixelFinal.r = pixelFinal.r + couleurLumiere[i].r; //pixelFinal.r = pixelFinal.r + couleurLumiere[i].r + objets.lumiere[i].couleur.r;
        pixelFinal.g = pixelFinal.g + couleurLumiere[i].g; //pixelFinal.g = pixelFinal.g + couleurLumiere[i].g + objets.lumiere[i].couleur.g;
        pixelFinal.b = pixelFinal.b + couleurLumiere[i].b; //pixelFinal.b = pixelFinal.b + couleurLumiere[i].b + objets.lumiere[i].couleur.b;
    }

    pixelFinal.r = (int)(((double)pixelFinal.r)/((double)objets.nbLumiere)); //pixelFinal.r = (int)(((double)pixelFinal.r)/((double)objets.nbLumiere*2));
    pixelFinal.g = (int)(((double)pixelFinal.g)/((double)objets.nbLumiere)); //pixelFinal.g = (int)(((double)pixelFinal.g)/((double)objets.nbLumiere*2));
    pixelFinal.b = (int)(((double)pixelFinal.b)/((double)objets.nbLumiere)); //pixelFinal.b = (int)(((double)pixelFinal.b)/((double)objets.nbLumiere*2));

    free(couleurLumiere);

    return pixelFinal;
}





Objet envoieRayon (RepertoireDObjets objets, Rayon rayon, Coordonnees *intersectionADeterminer)
{
    int i = 0;
    Coordonnees intersectionTemp = {0.0, 0.0, 0.0}, intersection = {0.0, 0.0, 0.0};
    double distance = -1.0;
    Objet objLePlusProche = {RIEN, 0};



    for (i = 0; i < objets.nbPlan; i++)
    {
        if (intersectPlan(rayon, objets.plan[i], &intersectionTemp))
        {
            if (distance > calculDistance(rayon.origine, intersectionTemp) || distance == -1.0)
            {
                intersection.x = intersectionTemp.x;
                intersection.y = intersectionTemp.y;
                intersection.z = intersectionTemp.z;

                distance = calculDistance(rayon.origine, intersection);
                objLePlusProche.type = PLAN;
                objLePlusProche.index = i;
            }
        }
    }


    for (i = 0; i < objets.nbSphere; i++)
    {
        if (intersectSphere(rayon, objets.sphere[i], &intersectionTemp))
        {
            if (distance > calculDistance(rayon.origine, intersectionTemp) || distance == -1.0)
            {
                intersection.x = intersectionTemp.x;
                intersection.y = intersectionTemp.y;
                intersection.z = intersectionTemp.z;

                distance = calculDistance(rayon.origine, intersection);
                objLePlusProche.type = SPHERE;
                objLePlusProche.index = i;
            }
        }
    }


    for (i = 0; i < objets.nbBox; i++)
    {
        if (intersectBox(rayon, objets.box[i], &intersectionTemp))
        {
            if (distance > calculDistance(rayon.origine, intersectionTemp) || distance == -1.0)
            {
                intersection.x = intersectionTemp.x;
                intersection.y = intersectionTemp.y;
                intersection.z = intersectionTemp.z;

                distance = calculDistance(rayon.origine, intersection);
                objLePlusProche.type = BOX;
                objLePlusProche.index = i;
            }
        }
    }





    intersectionADeterminer->x = intersection.x;
    intersectionADeterminer->y = intersection.y;
    intersectionADeterminer->z = intersection.z;

    return objLePlusProche;
}





Couleur getLumiere (RepertoireDObjets objets, int indexLumiere, Objet objEclairer, Coordonnees intersection, Vecteur normal, Couleur intersectionCouleur)
{
    Vecteur lumiereVec = {0.0, 0.0, 0.0};
    double angle = 0.0, coefLumR = 0.0, coefLumG = 0.0, coefLumB = 0.0;
    Couleur noir = {0, 0, 0}, couleurFinale = {0, 0, 0};
    Objet objLePlusProche = {RIEN, 0};
    Coordonnees interLaPlusProche = {0.0, 0.0, 0.0};
    Rayon rayon = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};


    lumiereVec.x = intersection.x - objets.lumiere[indexLumiere].location.x;
    lumiereVec.y = intersection.y - objets.lumiere[indexLumiere].location.y;
    lumiereVec.z = intersection.z - objets.lumiere[indexLumiere].location.z;
    normalise(&lumiereVec);

    rayon.origine = objets.lumiere[indexLumiere].location;
    rayon.direction = lumiereVec;
    objLePlusProche = envoieRayon(objets, rayon, &interLaPlusProche);


    lumiereVec.x = -lumiereVec.x;
    lumiereVec.y = -lumiereVec.y;
    lumiereVec.z = -lumiereVec.z;

    angle = calculAngle(lumiereVec, normal);
    angle = (angle + 0.8)/2;

    coefLumR = ((double)objets.lumiere[indexLumiere].couleur.r)/255.0;
    coefLumG = ((double)objets.lumiere[indexLumiere].couleur.g)/255.0;
    coefLumB = ((double)objets.lumiere[indexLumiere].couleur.b)/255.0;


    if (angle <= 0)
    {
        return noir;
    }
    else
    {
        if (estIdentique(objLePlusProche, objEclairer))
        {
            couleurFinale.r = (int)(((double)(intersectionCouleur.r)) * angle * coefLumR);
            couleurFinale.g = (int)(((double)(intersectionCouleur.g)) * angle * coefLumG);
            couleurFinale.b = (int)(((double)(intersectionCouleur.b)) * angle * coefLumB);
        }
        else
        {
            couleurFinale.r = (int)(((double)(intersectionCouleur.r)) * angle * 0.5 * coefLumR);
            couleurFinale.g = (int)(((double)(intersectionCouleur.g)) * angle * 0.5 * coefLumG);
            couleurFinale.b = (int)(((double)(intersectionCouleur.b)) * angle * 0.5 * coefLumB);
        }

        return couleurFinale;
    }


}







