/*
 * lightdef.c
 * Revision 4.0  91/07/17  14:46:25  kolb
 * Initial version.
 */
#include "rayshade.h"
#include "options.h"
#include "light.h"
#include "infinite.h"	/* to create default infinite light */
#include "jittered.h"	/* to create jittered light sources */
 
Light *Lights = NULL;		/* Linked list of defined lights */
 
void
LightAddToDefined(light)
Light *light;
{
	if (light) {
		light->next = Lights;
		Lights = light;
	}
}
 
void
LightSetup()
{
	long shadowopts;
	Light *ltmp;
 
	/*
	 * Set shadowing options.
	 */
	shadowopts = 0;
	if (Options.no_shadows)
		shadowopts |= SHADOW_NONE;
	if (Options.shadowtransp)
		shadowopts |= SHADOW_TRANSP;
	if (Options.csg)
		shadowopts |= SHADOW_CSG;
	if (Options.cache)
		shadowopts |= SHADOW_CACHE;
	if (Options.shutterspeed > 0.)
		shadowopts |= SHADOW_BLUR;
	ShadowSetOptions(shadowopts);
 
	/*
	 * If no light sources were defined, add a default.
	 */
	if (Lights == (Light *)NULL) {
		Color ctmp;
		Vector vtmp;
		vtmp.x = vtmp.z = 1.;
		vtmp.y = -1;
		ctmp.r = ctmp.g = ctmp.b = 1.;
 
		LightAddToDefined(LightInfiniteCreate(&ctmp, &vtmp));
	}
	/*
	 * Now that we've parsed the input file, we know what
	 * maxlevel is, and we can allocate the correct amount of
	 * space for each light source's cache.
	 */
	for (ltmp = Lights; ltmp; ltmp = ltmp->next) {
		ltmp->cache = (ShadowCache *)Calloc(
			(unsigned)Options.maxdepth + 1, sizeof(ShadowCache));
	}
}
 
void
AreaLightCreate(color, corner, u, usamp, v, vsamp, shadow)
Color *color;
Vector *corner, *u, *v;
int usamp, vsamp, shadow;
{
	Vector vpos, curpos;
	int i, j, numlight;
	Float ulen, vlen;
	Color intens;
	Light *ltmp;
 
	if (usamp < 1 || vsamp < 1)
		RLerror(RL_ABORT, "Invalid area light specification.\n");
 
	numlight = usamp * vsamp;	/* Total number of jittered sources */
 
	/*
	 * Sum of all intensities is equal to specified intensity.
	 */
	intens.r = color->r / (Float)numlight;
	intens.g = color->g / (Float)numlight;
	intens.b = color->b / (Float)numlight;
 
	VecSub(*u, *corner, u);
	VecSub(*v, *corner, v);
	/*
	 * Make sure that u and v are not degenerate.
	 */
	ulen = VecNormalize(u);
	vlen = VecNormalize(v);
	if (ulen < EPSILON || vlen < EPSILON)
		RLerror(RL_ABORT, "Degenerate area light source.\n");
	/*
	 * Scale u and v such that they define the area covered by a
	 * single sample.
	 */
	VecScale(ulen / (Float)usamp, *u, u); 
	VecScale(vlen / (Float)vsamp, *v, v);
	/*
	 * For each sample...
	 */
	vpos = *corner;
	for (i = 0; i < vsamp; i++) {
		curpos = vpos;
		for (j = 0; j < usamp; j++) {
			/*
			 * current pos is the "corner" of a new light
			 * source.  A jittered position based on
			 * the "corner" and the two edge vectors
			 * is used as the position for the
			 * light source in lighting calculations.
			 */
			ltmp = LightJitteredCreate(&intens, &curpos, u, v);
			ltmp->shadow = shadow;
			LightAddToDefined(ltmp);
			VecAdd(curpos, *u, &curpos);
		}
		VecAdd(vpos, *v, &vpos);
	}
}
