#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "shaders.h"
#include "perlin.h"
#include "v3math.h"
#include "intersection.h"
#include "scene.h"
#include "quat.h"
#include "constants.h"

// Always return the same color. This shader does no real computations
// based on normal, light position, etc. As such, it merely creates
// a "silhouette" of an object.

vec3
shade_constant(intersection_point ip)
{
    return v3_create(1, 0, 0);
}

vec3
shade_matte(intersection_point ip)
{
    vec3   	l_dir;
    float   f;
    float   res;

    res = scene_ambient_light;

    for (int l = 0; l < scene_num_lights; l++)
    {
        l_dir = v3_subtract(scene_lights[l].position, ip.p);

        // Shoot a shadow ray. If the point to shade is in shadow w.r.t.
        // this light then there is no contribution from the light
        if (shadow_check(v3_add(ip.p, v3_multiply(l_dir, 0.0001)), l_dir))
            continue;

        // Compute and add the contribution from this light
        l_dir = v3_normalize(l_dir);

        f = v3_dotprod(ip.n, l_dir);
        if (f > 0.0)
            res += f * scene_lights[l].intensity;
    }

    if (res > 1.0)
        res = 1.0;

    return v3_create(res, res, res);
}

// Returns the shaded color for the given point to shade.
// Calls the relevant shading function based on the material index.
vec3
shade(intersection_point ip)
{
	switch (ip.material)
	{
        case 0:
            return shade_constant(ip);
		case 1:
			return shade_matte(ip);
        default:
            return shade_constant(ip);
	}
}

// Determine the surface color for the first object intersected by
// the given ray, or return the scene background color when no
// intersection is found
vec3
ray_color(int level, vec3 ray_origin, vec3 ray_direction)
{
    intersection_point  ip;

    // If this ray has been reflected too many times, simply
    // return the background color.
    if (level >= 3)
        return scene_background_color;

    // Check if the ray intersects anything in the scene
    if (find_first_intersection(&ip, ray_origin, ray_direction))
    {
        // Shade the found intersection point
        ip.ray_level = level;
        return shade(ip);
    }

    // Nothing was hit, return background color
    return scene_background_color;
}
