/*
	name:	objects.c

	Various object routines
	-----------------------

*/


#include  <stdlib.h>

#include  "defs.h"
#include  "extern.h"



/*****************************************************************
 *
 *      Calculate the surface-normal for a given point and shape
 *
 *****************************************************************/

void GetSurfaceNormal(VECTOR *SurfNorm, POINT *SurfPoint, OBJECT *Object)
{
	PLANE		*p;
	SPHERE		*s;
	ELLIPSOID	*e;
	TRIANGLE	*t;
	BOX		*b;
	DISC		*d;
	CYLINDER	*c;

	long		i;
	POINT		ReTransformedPoint;
	VECTOR		tempv;
	double		tempd;

	CopyPoint(&ReTransformedPoint,SurfPoint);

	if(Object->Transform.NumTransforms>0) {			/* Retransform the surface point */
	    for(i=Object->Transform.NumTransforms-1L;i>=0L;i--) {
/*	    for(i=0;i<Object->Transform.NumTransforms;i++) { */
		switch(Object->Transform.Entry[i].Type) {
		    case TRANSFORM_SCALE:
			ReTransformedPoint.x=ReTransformedPoint.x/Object->Transform.Entry[i].Values.x;
			ReTransformedPoint.y=ReTransformedPoint.y/Object->Transform.Entry[i].Values.y;
			ReTransformedPoint.z=ReTransformedPoint.z/Object->Transform.Entry[i].Values.z;
			break;
		    case TRANSFORM_MOVE:
			ReTransformedPoint.x=ReTransformedPoint.x-Object->Transform.Entry[i].Values.x;
			ReTransformedPoint.y=ReTransformedPoint.y-Object->Transform.Entry[i].Values.y;
			ReTransformedPoint.z=ReTransformedPoint.z-Object->Transform.Entry[i].Values.z;
			break;
		    case TRANSFORM_ROTATE:
			NegVector(&tempv,&Object->Transform.Entry[i].Values);
			RotatePoint(&ReTransformedPoint,&tempv);
			break;
		    case TRANSFORM_NONE:
		    default:
			break;
		}
	    }
	}

	switch(Object->ShapeType) {
	case SHAPE_PLANE:
		p=(PLANE *)(Object->Shape);
		CopyVector(SurfNorm,&(p->Normal));
		break;
	case SHAPE_SPHERE:
		s=(SPHERE *)(Object->Shape);
		SurfNorm->x=ReTransformedPoint.x-s->Centre.x;
		SurfNorm->y=ReTransformedPoint.y-s->Centre.y;
		SurfNorm->z=ReTransformedPoint.z-s->Centre.z;
		break;
	case SHAPE_ELLIPSOID:
		e=(ELLIPSOID *)(Object->Shape);
		SurfNorm->x=(ReTransformedPoint.x-e->Centre.x)/(e->Radius.x*e->Radius.x);
		SurfNorm->y=(ReTransformedPoint.y-e->Centre.y)/(e->Radius.y*e->Radius.y);
		SurfNorm->z=(ReTransformedPoint.z-e->Centre.z)/(e->Radius.z*e->Radius.z);
		break;
	case SHAPE_TRIANGLE:
		t=(TRIANGLE *)(Object->Shape);
		CopyVector(SurfNorm,&(t->Plane.Normal));
		break;
	case SHAPE_BOX:
		b=(BOX *)(Object->Shape);
		if(ReTransformedPoint.x<(b->Corners[0].x+EPSILON))	/* minx */
			CopyVector(SurfNorm,&b->Planes[0].Normal);
		else if(ReTransformedPoint.x>(b->Corners[1].x-EPSILON))	/* maxx */
			CopyVector(SurfNorm,&b->Planes[1].Normal);
		else if(ReTransformedPoint.y<(b->Corners[0].y+EPSILON))	/* miny */
			CopyVector(SurfNorm,&b->Planes[2].Normal);
		else if(ReTransformedPoint.y>(b->Corners[1].y-EPSILON))	/* maxy */
			CopyVector(SurfNorm,&b->Planes[3].Normal);
		else if(ReTransformedPoint.z<(b->Corners[0].z+EPSILON))	/* minz */
			CopyVector(SurfNorm,&b->Planes[4].Normal);
		else if(ReTransformedPoint.z>(b->Corners[1].z-EPSILON))	/* maxz */
			CopyVector(SurfNorm,&b->Planes[5].Normal);
		break;
	case SHAPE_DISC:
		d=(DISC *)(Object->Shape);
		CopyVector(SurfNorm,&(d->Plane.Normal));
		break;
	case SHAPE_CYLINDER:
		c=(CYLINDER *)(Object->Shape);
		tempd=ReTransformedPoint.x*ReTransformedPoint.x+ReTransformedPoint.y*ReTransformedPoint.y;
		if(sqrt(tempd)>(c->r-EPSILON)) {
			SurfNorm->x=ReTransformedPoint.x;
			SurfNorm->y=ReTransformedPoint.y;
			SurfNorm->z=0.0;
		}
		else {
			if(ReTransformedPoint.z<(c->Ends[1].z-EPSILON))
				CopyVector(SurfNorm,&c->Discs[0].Plane.Normal);
			else CopyVector(SurfNorm,&c->Discs[1].Plane.Normal);
		}
		break;
	}

	if(Object->Transform.NumTransforms>0) {			/* Transform the surface normal */
/*	    for(i=Object->Transform.NumTransforms-1L;i>=0L;i--) { */
	    for(i=0L;i<Object->Transform.NumTransforms;i++) {
		switch(Object->Transform.Entry[i].Type) {
		    case TRANSFORM_SCALE:
			SurfNorm->x=SurfNorm->x/Object->Transform.Entry[i].Values.x;
			SurfNorm->y=SurfNorm->y/Object->Transform.Entry[i].Values.y;
			SurfNorm->z=SurfNorm->z/Object->Transform.Entry[i].Values.z;
			break;
		    case TRANSFORM_ROTATE:
			CopyVector(&tempv,&Object->Transform.Entry[i].Values);
			RevRotateVector(SurfNorm,&tempv);
			break;
		    case TRANSFORM_MOVE:
		    case TRANSFORM_NONE:
		    default:
			break;
		}
	    }
	}
}




/*****************************************************************
 *
 *      Free all memory occupied by object-descriptions
 *
 *****************************************************************/


void FreeAllObjectMemory(void)
{
	long	i;

	if(NumObjects>0) {
	    for(i=0;i<NumObjects;i++) {
		switch(ObjectArray[i]->ShapeType) {
		    case SHAPE_PLANE:
			free((PLANE *)ObjectArray[i]->Shape);
			break;
		    case SHAPE_SPHERE:
			free((SPHERE *)ObjectArray[i]->Shape);
			break;
		    case SHAPE_ELLIPSOID:
			free((ELLIPSOID *)ObjectArray[i]->Shape);
			break;
		    case SHAPE_TRIANGLE:
			free((TRIANGLE *)ObjectArray[i]->Shape);
			break;
		    case SHAPE_BOX:
			free((BOX *)ObjectArray[i]->Shape);
			break;
		    case SHAPE_DISC:
			free((DISC *)ObjectArray[i]->Shape);
			break;
		    case SHAPE_CYLINDER:
			free((CYLINDER *)ObjectArray[i]->Shape);
			break;
		}
		free(ObjectArray[i]);
		ObjectArray[i]=NULL;
	    }
	}

	if(NumLights>0) {
	    for(i=0;i<NumLights;i++) {
		free(LightArray[i]);
		LightArray[i]=NULL;
	    }
	}
}



/*****************************************************************
 *
 *      Transform handling routines
 *
 *****************************************************************/


void ClearTransform(TRANSFORM *t)
{
	int	i;

	t->NumTransforms=0L;
	for(i=0;i<10;i++) {
		t->Entry[i].Type=TRANSFORM_NONE;
		t->Entry[i].Values.x=t->Entry[i].Values.y=t->Entry[i].Values.z=0.0;
	}
}


void CopyTransform(TRANSFORM *t2, TRANSFORM *t1)
{
	int	i;

	t2->NumTransforms=t1->NumTransforms;
	for(i=0;i<10;i++) {
		t2->Entry[i].Type=t1->Entry[i].Type;
		CopyVector(&t2->Entry[i].Values,&t1->Entry[i].Values);
	}
}


void AddTransform(TRANSFORM *t2, TRANSFORM *t1)
{
	long	i,orignumtrans;

	orignumtrans=t2->NumTransforms;
	t2->NumTransforms+=t1->NumTransforms;
	if(t2->NumTransforms>10L) t2->NumTransforms=10L;
	for(i=orignumtrans;i<t2->NumTransforms;i++) {
		t2->Entry[i].Type=t1->Entry[i].Type;
		CopyVector(&t2->Entry[i].Values,&t1->Entry[i].Values);
	}
}


