/*
 * surface.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: surface.c,v 4.0 91/07/17 14:40:55 kolb Exp Locker: kolb $
 *
 * $Log:	surface.c,v $
 * Revision 4.0  91/07/17  14:40:55  kolb
 * Initial version.
 * 
 */
#include "atmosphere.h"
#include "surface.h"

#define blend(a, b, p, q)	(a * p + b * q)

Color	Black = {0., 0., 0.},
	White = {1., 1., 1.};

/*
 * Create and return pointer to surface with given properties.
 */
Surface *
SurfaceCreate()
{
	Surface *stmp;

	stmp = (Surface *)RayMalloc(sizeof(Surface));

	stmp->amb = stmp->diff = stmp->spec =
		stmp->translu = Black;

	stmp->body = White;

	stmp->srexp = stmp->stexp = DEFAULT_PHONGPOW;
	stmp->statten = 1.;	/* No attenuation by default */

	stmp->reflect = stmp->transp = 0.;

	stmp->noshadow = FALSE;

	stmp->index = DEFAULT_INDEX;

	stmp->name = (char *)NULL;
	stmp->next = (Surface *)NULL;

	return stmp;
}

Surface *
SurfaceCopy(surf)
Surface *surf;
{
	Surface *res;

	if (!surf)
		return (Surface *)NULL;

	res = SurfaceCreate();
	*res = *surf;
	res->next = (Surface *)NULL;
	res->name = (char *)NULL;
	return res;
}

/*
 * Compute combination of two surfaces. Resulting surface is copied into surf1.
 */
void
SurfaceBlend(surf1, surf2, p, q)
Surface *surf1, *surf2;
Float p, q;
{
	/*
 	 * P is weight of surf1.  q is weight of surf2.
	 * Result is placed in surf1.
	 */
	if (q < EPSILON)
		return;	/* keep surf1 as-is */

	ColorBlend(&surf1->amb, &surf2->amb, p, q);
	ColorBlend(&surf1->diff, &surf2->diff, p, q);
	ColorBlend(&surf1->spec, &surf2->spec, p, q);
	ColorBlend(&surf1->translu, &surf2->translu, p, q);
	ColorBlend(&surf1->body, &surf2->body, p, q);

	surf1->srexp = blend(surf1->srexp, surf2->srexp, p, q);
	surf1->stexp = blend(surf1->stexp, surf2->stexp, p, q);

	surf1->reflect = blend(surf1->reflect, surf2->reflect, p, q);
	surf1->transp  = blend(surf1->transp,  surf2->transp,  p, q);
	surf1->translucency = blend(surf1->translucency, surf2->translucency,
			p, q);
	/*
	 * Questionable...
	 */
	surf1->statten = blend(surf1->statten, surf2->statten, p, q);
	surf1->index = blend(surf1->index, surf2->index, p, q);

	if (p < EPSILON) {
		surf1->noshadow = surf2->noshadow;
	} else {
		/* else there's a blend of some kind... */
		surf1->noshadow = (surf1->noshadow && surf2->noshadow);
	}
}

/*
 * Blend two colors.  Result is placed in color1.
 */
void
ColorBlend(color1, color2, p, q)
Color *color1, *color2;
Float p, q;
{
	color1->r = blend(color1->r, color2->r, p, q);
	color1->g = blend(color1->g, color2->g, p, q);
	color1->b = blend(color1->b, color2->b, p, q);
}

SurfList *
SurfPop(list)
SurfList *list;
{
	SurfList *stmp = list->next;

	free((voidstar)list);
	return stmp;
}

SurfList *
SurfPush(surf, list)
Surface *surf;
SurfList *list;
{
	SurfList *stmp;

	stmp = (SurfList *)RayMalloc(sizeof(SurfList));
	stmp->surf = surf;
	stmp->next = list;
	return stmp;
}
