#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "structures.h"
#include "prototypes.h"




// On détermine les coefficients de l'équation du plan Ax + By + Cz + D = 0, puis on remplace x, y et z par les coordonnées du rayon au temps t.
// Cela nous donne les éventuels temps t où le rayon coupe le plan.

int intersectPlan (Rayon rayon, Plan plan, Coordonnees *intersection)
{
    double a = 0.0, b = 0.0, c = 0.0, d = 0.0, t = 0.0;


    a = plan.vecteurNormal.x;
    b = plan.vecteurNormal.y;
    c = plan.vecteurNormal.z;
    d = -(a*plan.hauteur + b*plan.hauteur + c*plan.hauteur);


    if ((a*rayon.origine.x + b*rayon.origine.y + c*rayon.origine.z + d) == 0)
    {
        *intersection = rayon.origine;

        return 1; // la camera est dans le plan, donc on touche
    }
    else if ((a*rayon.direction.x + b*rayon.direction.y + c*rayon.direction.z) == 0)
    {
        return 0; // direction paralèlle on ne touchera pas
    }


    t = -((a*rayon.origine.x + b*rayon.origine.y + c*rayon.origine.z + d)/(a*rayon.direction.x + b*rayon.direction.y + c*rayon.direction.z));

    if (t >= 0)
    {
        intersection->x = rayon.origine.x + rayon.direction.x*t;
        intersection->y = rayon.origine.y + rayon.direction.y*t;
        intersection->z = rayon.origine.z + rayon.direction.z*t;

        return 1;
    }
    else
    {
        return 0;
    }
}




// On résoud l'équation a*t²+b*t+c = 0, obtenue par l'équation de la sphere (X-Xc)²+(Y-Yc)²+(Z-Zc)²=r² en remplaçant X, Y et Z par les coordonées du rayon au temps t.
// Cela nous donne les éventuels temps t où le rayon coupe la sphere.

int intersectSphere (Rayon rayon, Sphere sphere, Coordonnees *intersection)
{
    double a = 0.0, b = 0.0, c = 0.0, det = 0.0, t1 = 0.0, t2 = 0.0;

    a = (rayon.direction.x*rayon.direction.x) + (rayon.direction.y*rayon.direction.y) + (rayon.direction.z*rayon.direction.z);
    b = 2 * (rayon.direction.x*(rayon.origine.x - sphere.centre.x) + rayon.direction.y*(rayon.origine.y - sphere.centre.y) + rayon.direction.z*(rayon.origine.z - sphere.centre.z));
    c = ((rayon.origine.x - sphere.centre.x)*(rayon.origine.x - sphere.centre.x) + (rayon.origine.y - sphere.centre.y)*(rayon.origine.y - sphere.centre.y) + (rayon.origine.z - sphere.centre.z)*(rayon.origine.z - sphere.centre.z) - sphere.rayon*sphere.rayon);

    det = b*b - 4*a*c;

    if (det >= 0)
    {
        t1 = (-b + sqrt(det))/(2*a);
        t2 = (-b - sqrt(det))/(2*a);

        if (t1 <= t2)
        {
            intersection->x = rayon.origine.x + rayon.direction.x*t1;
            intersection->y = rayon.origine.y + rayon.direction.y*t1;
            intersection->z = rayon.origine.z + rayon.direction.z*t1;
        }
        else
        {
            intersection->x = rayon.origine.x + rayon.direction.x*t2;
            intersection->y = rayon.origine.y + rayon.direction.y*t2;
            intersection->z = rayon.origine.z + rayon.direction.z*t2;
        }

        return 1;
    }


    return 0;
}



// On pose qu'une box est l'union de 6 plan finis

int intersectBox (Rayon rayon, Box box, Coordonnees *intersection)
{
    double temps[6] = {0.0};
    Coordonnees intersectionTab[6];
    double x1 = 0.0, x2 = 0.0, y1 = 0.0, y2 = 0.0, z1 = 0.0, z2 = 0.0, t = 0.0;
    Vecteur normal = {0.0, 0.0, 0.0};
    int i = 0, indexIntersection = 0;


    // On détermine les intervalles

    if (box.point1.x < box.point2.x)
    {
        x1 = box.point1.x;
        x2 = box.point2.x;
    }
    else
    {
        x1 = box.point2.x;
        x2 = box.point1.x;
    }

    if (box.point1.y < box.point2.y)
    {
        y1 = box.point1.y;
        y2 = box.point2.y;
    }
    else
    {
        y1 = box.point2.y;
        y2 = box.point1.y;
    }

    if (box.point1.z < box.point2.z)
    {
        z1 = box.point1.z;
        z2 = box.point2.z;
    }
    else
    {
        z1 = box.point2.z;
        z2 = box.point1.z;
    }


    // faces orthogonales à l'axe x
    normal.x = 1.0;
    normal.y = 0.0;
    normal.z = 0.0;

    temps[0] = intersectPlanFini(rayon, normal, box.point1, y1, y2, z1, z2, &intersectionTab[0]);
    temps[1] = intersectPlanFini(rayon, normal, box.point2, y1, y2, z1, z2, &intersectionTab[1]);

    // faces orthogonales à l'axe y
    normal.x = 0.0;
    normal.y = 1.0;
    normal.z = 0.0;

    temps[2] = intersectPlanFini(rayon, normal, box.point1, x1, x2, z1, z2, &intersectionTab[2]);
    temps[3] = intersectPlanFini(rayon, normal, box.point2, x1, x2, z1, z2, &intersectionTab[3]);

    // faces orthogonales à l'axe y
    normal.x = 0.0;
    normal.y = 0.0;
    normal.z = 1.0;

    temps[4] = intersectPlanFini(rayon, normal, box.point1, x1, x2, y1, y2, &intersectionTab[4]);
    temps[5] = intersectPlanFini(rayon, normal, box.point2, x1, x2, y1, y2, &intersectionTab[5]);

    if (temps[0] != -1.0)
    {
        t = temps[0];
        indexIntersection = 0;
    }
    else if (temps[1] != -1.0)
    {
        t = temps[1];
        indexIntersection = 1;
    }
    else if (temps[2] != -1.0)
    {
        t = temps[2];
        indexIntersection = 2;
    }
    else if (temps[3] != -1.0)
    {
        t = temps[3];
        indexIntersection = 3;
    }
    else if (temps[4] != -1.0)
    {
        t = temps[4];
        indexIntersection = 4;
    }
    else if (temps[5] != -1.0)
    {
        t = temps[5];
        indexIntersection = 5;
    }
    else
    {
        return 0;
    }



    for (i = 0; i < 6; i++)
    {
        if (t > temps[i] && temps[i] != -1.0)
        {
            t = temps[i];
            indexIntersection = i;
        }
    }

    *intersection = intersectionTab[indexIntersection];


    return 1;
}


double intersectPlanFini (Rayon rayon, Vecteur normal, Coordonnees pointPlan, double debutIntervalle1, double finIntervalle1, double debutIntervalle2, double finIntervalle2, Coordonnees *intersection)
{
    double a = 0.0, b = 0.0, c = 0.0, d = 0.0, t = 0.0;
    Coordonnees intersectionTemp = {0.0, 0.0, 0.0};

    a = normal.x;
    b = normal.y;
    c = normal.z;
    d = -(a*pointPlan.x + b*pointPlan.y + c*pointPlan.z);


    if ((a*rayon.direction.x + b*rayon.direction.y + c*rayon.direction.z) == 0)
    {
        return -1.0; // direction paralèlle on ne touchera pas
    }


    t = -((a*rayon.origine.x + b*rayon.origine.y + c*rayon.origine.z + d)/(a*rayon.direction.x + b*rayon.direction.y + c*rayon.direction.z));

    if (t >= 0.0)
    {
        intersectionTemp.x = rayon.origine.x + rayon.direction.x*t;
        intersectionTemp.y = rayon.origine.y + rayon.direction.y*t;
        intersectionTemp.z = rayon.origine.z + rayon.direction.z*t;

        if (a == 1)
        {
            if ((intersectionTemp.y >= debutIntervalle1 && intersectionTemp.y <= finIntervalle1) && (intersectionTemp.z >= debutIntervalle2 && intersectionTemp.z <= finIntervalle2))
            {
                *intersection = intersectionTemp;
                return t;
            }
            else
            {
                return -1.0;
            }
        }
        else if (b == 1)
        {
            if ((intersectionTemp.x >= debutIntervalle1 && intersectionTemp.x <= finIntervalle1) && (intersectionTemp.z >= debutIntervalle2 && intersectionTemp.z <= finIntervalle2))
            {
                *intersection = intersectionTemp;
                return t;
            }
            else
            {
                return -1.0;
            }
        }
        else
        {
            if ((intersectionTemp.x >= debutIntervalle1 && intersectionTemp.x <= finIntervalle1) && (intersectionTemp.y >= debutIntervalle2 && intersectionTemp.y <= finIntervalle2))
            {
                *intersection = intersectionTemp;
                return t;
            }
            else
            {
                return -1.0;
            }
        }
    }
    else
    {
        return -1.0;
    }
}






