#ifndef BMPSHADER_HXX
#define BMPSHADER_HXX

#include "Shader.hxx"

#define dPdu             Vec3f(1,0,0)
#define dPdv             Vec3f(0,0,1)

class BumpMappedPhongShader : public Shader
{
public:
	Vec3f color;   // base color
	Vec3f ambient; // ambient radiance 
	Vec3f p;       // intersection point
	float ka;      // ambient coefficient
	float kd;      // diffuse reflection coefficients
	float ks;      // specular refelection coefficients
	float ke;      // shininess exponent

	BumpMappedPhongShader(Scene *scene,
	                      Vec3f color, float ka,float kd, float ks, float ke)
		: Shader(scene),color(color),ka(ka),kd(kd),ks(ks),ke(ke)
	{
		ambient = ka * Product(color, La);
	};

	virtual Vec3f Shade(Ray &ray)
	{
                Vec3f Lr(0,0,0),
                      Ll,
                      N = ray.hit->GetNormal(ray);
                Ray   light_ray;
                float intensity_scale,
		      specular_scale;

                p = ray.org + ray.t * ray.dir;

                if (Dot(N,ray.dir) > 0)
                        N = -N;

		// Bumpmapping must be applied here, even though the sample solution
		// does it 3 lines above... But that is nonsense (which you can also
		// observe in their image)
		N = N
		  + 0.5 * cos( 3 * p.x * sin(p.z)) * dPdu
		  + 0.5 * sin(13 * p.z)            * dPdv;
		Normalize(N);

                for (std::vector<Light*>::iterator it = scene->lights.begin(); it != scene->lights.end(); ++it)
                {
                        light_ray.org  = p;

#ifdef AREALIGHT
                        for (int i = 0; i < NUM_AREA_SAMPLES; ++i)
#endif
                        {
                                (*it)->Illuminate(light_ray, Ll);

                                if (!scene->Occluded(light_ray))
                                {
                                        intensity_scale = Dot(light_ray.dir, N);
                                        if (intensity_scale > 0)
                                                Lr += kd * Product(color, Ll) * intensity_scale;

					specular_scale  = Dot(light_ray.dir, ray.dir - 2 * Dot(N, ray.dir) * N);
					if (specular_scale  > 0)
                                                Lr += ks * Product(cs, Ll) * powf(specular_scale, ke);
                                }
                        }
                }

#ifdef AREALIGHT
                Lr /= NUM_AREA_SAMPLES;
#endif
		Lr += ambient;
                return Lr;
	};
};

#endif
