/* geom.c */
#include <stdio.h>
#include <stdlib.h>
#include "geom.h"
#include "error.h"
#include "mymath.h"
#include "Memory.h"

#ifdef BETTER_MEMMAN
static STORAGE *geomStor = (STORAGE *)NULL;
#define NEWGEOM()  	(GEOM *)New(sizeof(GEOM), &geomStor)
#define DISPOSEGEOM(ptr) Dispose((unsigned char *)(ptr), &geomStor)
#else /*BETTER_MEMMAN*/
#define NEWGEOM()	(GEOM *)Alloc(sizeof(GEOM))
#define DISPOSEGEOM(ptr) Free((char *)ptr, sizeof(GEOM))
#endif /*BETTER_MEMMAN*/


GEOM *GeomCreate(void *obj, GEOM_METHODS *methods)
{
	GEOM *p = (GEOM *)NULL;

	if (obj == NULL) return (GEOM *)NULL;

	p = NEWGEOM();
	p->obj = obj;
	p->methods = methods;
	p->bounded = 0;
	if (methods->bounds && methods->bounds(obj, p->bounds)) p->bounded=1; 

	return p;
}

void GeomPrint(FILE *out, GEOM *geom)
{
	geom->methods->print(out, geom->obj);
}

float *GeomBounds(GEOM *geom)
{
	return geom->bounds;
}

void GeomDestroy(GEOM *geom)
{
	geom->methods->destroy(geom->obj);
	DISPOSEGEOM(geom);
}

int GeomIsAggregate(GEOM *geom)
{
	return geom->methods->primlist != (GEOMLIST *(*)(void *))NULL;
}

GEOMLIST *GeomPrimList(GEOM *geom)
{
	return geom->methods->primlist(geom->obj);
}

/* only for primitives */
PATCHLIST *GeomPatchList(GEOM *geom)
{
	return geom->methods->patchlist(geom->obj);
}

/* actually, it only works for patchlists (only patchlists have
 * a method for duplication) - shaftculling only needs it for patchlists */
GEOM *GeomDuplicate(GEOM *geom)
{
	GEOM *p = (GEOM *)NULL;

	if (!geom->methods->duplicate) return geom;

	p = NEWGEOM();
	*p = *geom;
	p->obj = geom->methods->duplicate(geom->obj);

	return p;	
}

PATCH *GeomIntersect(GEOM *geom, RAY *ray, float mindist, float *maxdist,
		     int ShadowTesting)
{
	VECTOR vtmp;
	float nmaxdist;

	if (GEOMBOUNDED(geom)) {
	/*
	 * Check ray/bounding volume intersection
	 */
	       	VECTORSUMSCALED(ray->pos, mindist, ray->dir, vtmp);
       		if (OutOfBounds(&vtmp, geom->bounds)) {
       			nmaxdist = *maxdist;
       			if (!BoundsIntersect(ray, geom->bounds, mindist, &nmaxdist)) 
       				return NULL;
       		}
	}
	return geom->methods->intersect(geom->obj, ray, mindist, maxdist, ShadowTesting);
}

