/*
 * lightdef.c
 *
 * Copyright (C) 1989, 1991, Craig E. Kolb
 * All rights reserved.
 *
 * This software may be freely copied, modified, and redistributed
 * provided that this copyright notice is preserved on all copies.
 *
 * You may not distribute this software, in whole or in part, as part of
 * any commercial product without the express consent of the authors.
 *
 * There is no warranty or other guarantee of fitness of this software
 * for any purpose.  It is provided solely "as is".
 *
 * $Id: lightdef.c,v 4.0 91/07/17 14:46:25 kolb Exp Locker: kolb $
 *
 * $Log:	lightdef.c,v $
 * Revision 4.0  91/07/17  14:46:25  kolb
 * Initial version.
 * 
 */
#include "rayshade.h"
#include "options.h"
#include "liblight/light.h"
#include "liblight/infinite.h"	/* to create default infinite light */
#include "liblight/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);
	}
}
