CCL Home Page
Up Directory CCL Part14
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh 'libray/libcommon/transform.c' <<'END_OF_FILE'
X/*
X * transform.c
X *
X * Copyright (C) 1989, 1991, Craig E. Kolb
X * All rights reserved.
X *
X * This software may be freely copied, modified, and redistributed
X * provided that this copyright notice is preserved on all copies.
X *
X * You may not distribute this software, in whole or in part, as part of
X * any commercial product without the express consent of the authors.
X *
X * There is no warranty or other guarantee of fitness of this software
X * for any purpose.  It is provided solely "as is".
X *
X * $Id: transform.c,v 4.0.1.1 91/09/29 15:37:06 cek Exp Locker: cek $
X *
X * $Log:	transform.c,v $
X * Revision 4.0.1.1  91/09/29  15:37:06  cek
X * patch1: CoordSysTransform did not detect up-Z == -1.
X * 
X * Revision 4.0  91/07/17  14:32:25  kolb
X * Initial version.
X * 
X */
X#include "common.h"
X
X/*
X * Matrices are indexed row-first; that is:
X * matrix[ROW][COLUMN]
X */
X/*
X * Allocate new structure that holds both object-to-world and
X * world-to-object space transformation structures.  It probably
X * should hold pointers to these structures.
X */
XTrans *
XTransCreate(tr, meth)
XTransRef tr;
XTransMethods *meth;
X{
X	Trans *res;
X
X	res = (Trans *)share_malloc(sizeof(Trans));
X	res->tr = tr;
X	res->methods = meth;
X	res->animated = FALSE;
X	res->assoc = (ExprAssoc *)NULL;
X	res->prev = res->next = (Trans *)NULL;
X	MatrixInit(&res->trans);
X	MatrixInit(&res->itrans);
X	return res;
X}
X
Xvoid
XTransFree(trans)
XTrans *trans;
X{
X	if (trans->tr)
X		free((voidstar)trans->tr);
X	free((voidstar)trans);
X}
X
Xvoid
XTransAssoc(trans, ptr, expr)
XTrans *trans;
XFloat *ptr;
XExpr *expr;
X{
X	ExprAssoc *assoc;
X
X	if (expr->timevary) {
X		/*
X		 * Gotta store the sucker.
X		 */
X		trans->assoc = AssocCreate(ptr, expr, trans->assoc);
X		trans->animated = TRUE;
X	} else {
X		*ptr = expr->value;
X	}
X	fflush(stderr);
X}
X
X/*
X * Allocate new transformation 'matrix'.
X */
XRSMatrix *
XMatrixCreate()
X{
X	RSMatrix *res;
X
X	res = (RSMatrix *)share_malloc(sizeof(RSMatrix));
X	MatrixInit(res);
X	return res;
X}
X
X/*
X * Multiply m1 and m2, copy result into "res".
X */
Xvoid
XMatrixMult(t1, t2, res)
XRSMatrix *t1, *t2, *res;
X{
X	register int i;
X	RSMatrix tmp;
X
X	for (i = 0; i < 3; i++) {
X		tmp.matrix[i][0] = t1->matrix[i][0] * t2->matrix[0][0] +
X			  	   t1->matrix[i][1] * t2->matrix[1][0] +
X			  	   t1->matrix[i][2] * t2->matrix[2][0];
X		tmp.matrix[i][1] = t1->matrix[i][0] * t2->matrix[0][1] +
X			  	   t1->matrix[i][1] * t2->matrix[1][1] +
X			  	   t1->matrix[i][2] * t2->matrix[2][1];
X		tmp.matrix[i][2] = t1->matrix[i][0] * t2->matrix[0][2] +
X			  	   t1->matrix[i][1] * t2->matrix[1][2] +
X		  		   t1->matrix[i][2] * t2->matrix[2][2];
X	}
X
X	tmp.translate.x = t1->translate.x * t2->matrix[0][0] +
X			  t1->translate.y * t2->matrix[1][0] +
X			  t1->translate.z * t2->matrix[2][0] + t2->translate.x;
X	tmp.translate.y = t1->translate.x * t2->matrix[0][1] +
X			  t1->translate.y * t2->matrix[1][1] +
X			  t1->translate.z * t2->matrix[2][1] + t2->translate.y;
X	tmp.translate.z = t1->translate.x * t2->matrix[0][2] +
X			  t1->translate.y * t2->matrix[1][2] +
X			  t1->translate.z * t2->matrix[2][2] + t2->translate.z;
X	MatrixCopy(&tmp, res);
X}
X
X/*
X * Return transformation information to map the "coordinate system"
X * with the given origin, "up" vector, radius, and up axis lengths to
X * one in which the "up" vector is the Z axis and the x/y/up axes
X * have unit length.  This is useful for transforming a general
X * form of a primitive into a canonical, Z-axis aligned, unit size
X * primitive, facilitating intersection testing.
X * Assumes that "up" is normalized.
X */
Xvoid
XCoordSysTransform(origin, up, r, len, trans)
XVector *origin, *up;
XFloat r, len;
XTrans *trans;
X{
X	RSMatrix tmp;
X	Vector atmp;
X
X	ScaleMatrix(r, r, len, &trans->trans);
X	if (1. - fabs(up->z) < EPSILON) {
X		atmp.x = 1.;
X		atmp.y = atmp.z = 0.;
X	} else {
X		atmp.x = up->y;
X		atmp.y = -up->x;
X		atmp.z= 0.;
X	}
X	/*
X	 * Might want to make sure that |up->z| is < 1.
X	 */
X	RotationMatrix(atmp.x, atmp.y, atmp.z, -acos(up->z), &tmp);
X	MatrixMult(&trans->trans, &tmp, &trans->trans);
X	TranslationMatrix(origin->x, origin->y, origin->z, &tmp);
X	MatrixMult(&trans->trans, &tmp, &trans->trans);
X	MatrixInvert(&trans->trans, &trans->itrans);
X}
X
Xvoid
XTransCopy(from, into)
XTrans *into, *from;
X{
X	MatrixCopy(&from->trans, &into->trans);
X	MatrixCopy(&from->itrans, &into->itrans);
X}
X
Xvoid
XTransInvert(from, into)
XTrans *into, *from;
X{
X	RSMatrix ttmp;
X	/*
X	 * In case into == from...
X	 */
X	if (from == into) {
X		ttmp = from->trans;
X		into->trans = from->itrans;
X		into->itrans = ttmp;
X	} else {
X		into->trans = from->itrans;
X		into->itrans = from->trans;
X	}
X}
X
X/*
X * Copy a given transformation structure.
X */
Xvoid
XMatrixCopy(from, into)
XRSMatrix *into, *from;
X{
X	into->matrix[0][0] = from->matrix[0][0];
X	into->matrix[0][1] = from->matrix[0][1];
X	into->matrix[0][2] = from->matrix[0][2];
X	into->matrix[1][0] = from->matrix[1][0];
X	into->matrix[1][1] = from->matrix[1][1];
X	into->matrix[1][2] = from->matrix[1][2];
X	into->matrix[2][0] = from->matrix[2][0];
X	into->matrix[2][1] = from->matrix[2][1];
X	into->matrix[2][2] = from->matrix[2][2];
X	into->translate = from->translate;
X}
X
Xvoid
XTransInit(trans)
XTrans *trans;
X{
X	MatrixInit(&trans->trans);
X	MatrixInit(&trans->itrans);
X}
X
Xvoid
XTransCompose(t1, t2, res)
XTrans *t1, *t2, *res;
X{
X	MatrixMult(&t1->trans, &t2->trans, &res->trans);
X	MatrixMult(&t2->itrans, &t1->itrans, &res->itrans);
X}
X
X/*
X * Initialize transformation structure.
X */
Xvoid
XMatrixInit(trans)
XRSMatrix *trans;
X{
X	trans->matrix[0][0] = trans->matrix[1][1] = trans->matrix[2][2] = 1.;
X	trans->matrix[0][1] = trans->matrix[0][2] = trans->matrix[1][0] =
X	trans->matrix[1][2] = trans->matrix[2][0] = trans->matrix[2][1] = 0.;
X	trans->translate.x = trans->translate.y = trans->translate.z = 0.;
X}
X
X/*
X * Calculate inverse of the given transformation structure.
X */
Xvoid
XMatrixInvert(trans, inverse)
XRSMatrix *inverse, *trans;
X{
X	RSMatrix ttmp;
X	int i;
X	Float d;
X	extern int yylineno;
X
X	ttmp.matrix[0][0] = trans->matrix[1][1]*trans->matrix[2][2] -
X			    trans->matrix[1][2]*trans->matrix[2][1];
X	ttmp.matrix[1][0] = trans->matrix[1][0]*trans->matrix[2][2] -
X			    trans->matrix[1][2]*trans->matrix[2][0];
X	ttmp.matrix[2][0] = trans->matrix[1][0]*trans->matrix[2][1] -
X			    trans->matrix[1][1]*trans->matrix[2][0];
X
X	ttmp.matrix[0][1] = trans->matrix[0][1]*trans->matrix[2][2] -
X			    trans->matrix[0][2]*trans->matrix[2][1];
X	ttmp.matrix[1][1] = trans->matrix[0][0]*trans->matrix[2][2] -
X			    trans->matrix[0][2]*trans->matrix[2][0];
X	ttmp.matrix[2][1] = trans->matrix[0][0]*trans->matrix[2][1] -
X			    trans->matrix[0][1]*trans->matrix[2][0];
X
X	ttmp.matrix[0][2] = trans->matrix[0][1]*trans->matrix[1][2] -
X			    trans->matrix[0][2]*trans->matrix[1][1];
X	ttmp.matrix[1][2] = trans->matrix[0][0]*trans->matrix[1][2] -
X			    trans->matrix[0][2]*trans->matrix[1][0];
X	ttmp.matrix[2][2] = trans->matrix[0][0]*trans->matrix[1][1] -
X			    trans->matrix[0][1]*trans->matrix[1][0];
X
X	d = trans->matrix[0][0]*ttmp.matrix[0][0] -
X	    trans->matrix[0][1]*ttmp.matrix[1][0] +
X	    trans->matrix[0][2]*ttmp.matrix[2][0];
X
X	if (fabs(d) < EPSILON*EPSILON)
X		RLerror(RL_PANIC, "Singular matrix.\n",yylineno);
X
X	ttmp.matrix[0][0] /= d;
X	ttmp.matrix[0][2] /= d;
X	ttmp.matrix[1][1] /= d;
X	ttmp.matrix[2][0] /= d;
X	ttmp.matrix[2][2] /= d;
X
X	d = -d;
X
X	ttmp.matrix[0][1] /= d;
X	ttmp.matrix[1][0] /= d;
X	ttmp.matrix[1][2] /= d;
X	ttmp.matrix[2][1] /= d;
X
X	ttmp.translate.x = -(ttmp.matrix[0][0]*trans->translate.x +
X			     ttmp.matrix[1][0]*trans->translate.y +
X			     ttmp.matrix[2][0]*trans->translate.z);
X	ttmp.translate.y = -(ttmp.matrix[0][1]*trans->translate.x +
X			     ttmp.matrix[1][1]*trans->translate.y +
X			     ttmp.matrix[2][1]*trans->translate.z);
X	ttmp.translate.z = -(ttmp.matrix[0][2]*trans->translate.x +
X			     ttmp.matrix[1][2]*trans->translate.y +
X			     ttmp.matrix[2][2]*trans->translate.z);
X
X	MatrixCopy(&ttmp, inverse);
X}
X
X/*
X * Apply a transformation to a point (translation affects the point).
X */
Xvoid
XPointTransform(vec, trans)
XVector *vec;
XRSMatrix *trans;
X{
X	Vector tmp;
X
X	tmp.x = vec->x * trans->matrix[0][0] + vec->y * trans->matrix[1][0] +
X			vec->z * trans->matrix[2][0] + trans->translate.x;
X	tmp.y = vec->x * trans->matrix[0][1] + vec->y * trans->matrix[1][1] +
X			vec->z * trans->matrix[2][1] + trans->translate.y;
X	tmp.z = vec->x * trans->matrix[0][2] + vec->y * trans->matrix[1][2] +
X			vec->z * trans->matrix[2][2] + trans->translate.z;
X	*vec = tmp;
X}
X
X/*
X * 'c1x' is the X (0th) component of the first column, and so on.
X */
Xvoid
XArbitraryMatrix(c1x, c2x, c3x, c1y, c2y, c3y, c1z, c2z, c3z, tx, ty, tz, trans)
XFloat c1x, c1y, c1z, c2x, c2y, c2z, c3x, c3y, c3z, tx, ty, tz;
XRSMatrix *trans;
X{
X	trans->matrix[0][0] = c1x;
X	trans->matrix[1][0] = c1y;
X	trans->matrix[2][0] = c1z;
X
X	trans->matrix[0][1] = c2x;
X	trans->matrix[1][1] = c2y;
X	trans->matrix[2][1] = c2z;
X
X	trans->matrix[0][2] = c3x;
X	trans->matrix[1][2] = c3y;
X	trans->matrix[2][2] = c3z;
X
X	trans->translate.x = tx;
X	trans->translate.y = ty;
X	trans->translate.z = tz;
X}
X
X/*
X * Apply transformation to a vector (translations have no effect).
X */
Xvoid
XVecTransform(vec, trans)
XVector *vec;
XRSMatrix *trans;
X{
X	Vector tmp;
X
X	tmp.x = vec->x*trans->matrix[0][0] +
X		vec->y*trans->matrix[1][0] + vec->z*trans->matrix[2][0];
X	tmp.y = vec->x*trans->matrix[0][1] +
X		vec->y*trans->matrix[1][1] + vec->z*trans->matrix[2][1];
X	tmp.z = vec->x*trans->matrix[0][2] +
X		vec->y*trans->matrix[1][2] + vec->z*trans->matrix[2][2];
X
X	*vec = tmp;
X}
X
X/*
X * Transform normal -- multiply by the transpose of the given
X * matrix (which is the inverse of the 'desired' transformation).
X */
Xvoid
XNormalTransform(norm, it)
XVector *norm;
XRSMatrix *it;
X{
X	Vector onorm;
X
X	onorm = *norm;
X
X	norm->x = onorm.x*it->matrix[0][0] + onorm.y*it->matrix[0][1] +
X				onorm.z*it->matrix[0][2];
X	norm->y = onorm.x*it->matrix[1][0] + onorm.y*it->matrix[1][1] +
X				onorm.z*it->matrix[1][2];
X	norm->z = onorm.x*it->matrix[2][0] + onorm.y*it->matrix[2][1] +
X				onorm.z*it->matrix[2][2];
X	(void)VecNormalize(norm);
X}
X
X/*
X * Transform "ray" by transforming the origin point and direction vector.
X */
XFloat
XRayTransform(ray, trans)
XRay *ray;
XRSMatrix *trans;
X{
X	PointTransform(&ray->pos, trans);
X	VecTransform(&ray->dir, trans);
X	return VecNormalize(&ray->dir);
X}
X
Xvoid
XTransPropagate(trans)
XTrans *trans;
X{
X	(*trans->methods->propagate)(trans->tr, &trans->trans, &trans->itrans);
X}
X
Xvoid
XTransResolveAssoc(trans)
XTrans *trans;
X{
X	Trans *curtrans;
X	ExprAssoc *curassoc;
X
X	for (curtrans = trans; curtrans; curtrans = curtrans->next) {
X		for (curassoc = curtrans->assoc; curassoc; curassoc = curassoc->next) {
X			*curassoc->lhs = ExprEval(curassoc->expr);
X		}
X		if (curtrans->assoc)
X			TransPropagate(curtrans);
X	}
X}
X
Xvoid
XTransComposeList(list, result)
XTrans *list, *result;
X{
X	TransCopy(list, result);
X	for (list = list->next; list; list = list->next)
X		TransCompose(list, result, result);
X}
END_OF_FILE
if test 10843 -ne `wc -c <'libray/libcommon/transform.c'`; then
    echo shar: \"'libray/libcommon/transform.c'\" unpacked with wrong size!
fi
# end of 'libray/libcommon/transform.c'
fi
if test -f 'libray/libobj/csg.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'libray/libobj/csg.c'\"
else
echo shar: Extracting \"'libray/libobj/csg.c'\" \(10585 characters\)
sed "s/^X//" >'libray/libobj/csg.c' <<'END_OF_FILE'
X/*
X * csg.c
X *
X * Copyright (C) 1991, Rod G. Bogart, Craig E. Kolb
X * All rights reserved.
X *
X * This software may be freely copied, modified, and redistributed
X * provided that this copyright notice is preserved on all copies.
X *
X * You may not distribute this software, in whole or in part, as part of
X * any commercial product without the express consent of the authors.
X *
X * There is no warranty or other guarantee of fitness of this software
X * for any purpose.  It is provided solely "as is".
X *
X * $Id: csg.c,v 4.0 91/07/17 14:37:00 kolb Exp Locker: kolb $
X *
X * $Log:	csg.c,v $
X * Revision 4.0  91/07/17  14:37:00  kolb
X * Initial version.
X * 
X */
X#include "geom.h"
X#include "csg.h"
X
X#define csg_set_enter(l, f) ((l)->data[0].enter = (f) + 1)
X
Xstatic Methods *iCsgMethods = NULL;
Xstatic char csgName[] = "csg";
X
Xstatic int	CsgUnionInt(), CsgDifferenceInt(),
X		CsgIntersectInt();
Xstatic void	CsgHitlistCopy(), CsgSetBounds();
X
XCsg *
XCsgCreate(op)
Xint op;
X{
X	Csg *csg;
X
X	csg = (Csg *)share_malloc(sizeof(Csg));
X	csg->operator = op;
X	csg->obj1 = csg->obj2 = (Geom *)NULL;
X
X
X	switch(op) {
X		case CSG_UNION:
X			csg->intmeth = CsgUnionInt;
X			break;
X		case CSG_INTERSECT:
X			csg->intmeth = CsgIntersectInt;
X			break;
X		case CSG_DIFFERENCE:
X			csg->intmeth = CsgDifferenceInt;
X			break;
X		default:
X			RLerror(RL_ABORT, "Unknown csg op type %d?\n",op);
X	}
X	return csg;
X}
X
XMethods *
XCsgMethods()
X{
X	if (iCsgMethods== (Methods *)NULL) {
X		iCsgMethods = MethodsCreate();
X		iCsgMethods->create = (GeomCreateFunc *)CsgCreate;
X		iCsgMethods->convert = CsgConvert;
X		iCsgMethods->methods = CsgMethods;
X		iCsgMethods->name = CsgName;
X		iCsgMethods->intersect = CsgIntersect;
X		iCsgMethods->bounds = CsgBounds;
X		iCsgMethods->checkbounds = FALSE;
X		iCsgMethods->closed = TRUE;
X	}
X	return iCsgMethods;
X}
X
Xchar *
XCsgName()
X{
X	return csgName;
X}
X
Xcsg_intersect_objs(csg, ray, hit1, hit2, mindist, dist1, dist2)
XCsg *csg;
XRay *ray;
XHitList *hit1, *hit2;
XFloat mindist, *dist1, *dist2;
X{
X	int operator;
X
X	hit1->nodes = 0;
X	hit2->nodes = 0;
X	*dist1 = FAR_AWAY;
X	*dist2 = FAR_AWAY;
X	operator = csg->operator;
X
X	if (!intersect(csg->obj1, ray, hit1, mindist, dist1) &&
X	    ((operator == CSG_INTERSECT) || (operator == CSG_DIFFERENCE))) {
X		/*
X		 * Intersection and Difference cases: if you miss the first
X		 * object, you missed the whole thing.
X		 */
X		return FALSE;
X	}
X
X	if (!intersect(csg->obj2, ray, hit2, mindist, dist2) &&
X	    ((operator == CSG_INTERSECT) ||
X	     (hit1->nodes == 0) && (operator == CSG_UNION))) {
X		/*
X		 * Intersect case:  if you miss either object, you miss whole
X		 * Union case: if you miss both object, you miss whole
X		 */
X		return FALSE;
X	}
X
X	return TRUE;
X}
X
Xint
Xcsg_enter_obj(hitp)
XHitList *hitp;
X{
X	if (hitp->data[0].enter)
X		return hitp->data[0].enter - 1;
X
X	return PrimEnter(hitp->data[0].obj, &hitp->data[0].ray,
X			hitp->data[0].mindist, hitp->data[0].dist);
X}
X
Xstatic int
XCsgUnionInt(ray, hit1p, hit2p, dist1, dist2, hitclose, distclose)
XRay *ray;
XHitList *hit1p, *hit2p, **hitclose;
XFloat dist1, dist2, *distclose;
X{
X	Float distnext;
X	HitList hitnext, *hittmp;
X
X	while (TRUE) {
X		if (hit2p->nodes == 0 ||
X		    csg_enter_obj(hit2p)) {
X			/* return hit1 */
X			*hitclose = hit1p;
X			*distclose = dist1;
X			csg_set_enter(hit1p, csg_enter_obj(hit1p));
X			return TRUE;
X		} else {
X			distnext = FAR_AWAY;
X			hitnext.nodes = 0;
X			if (!intersect(hit1p->data[hit1p->nodes-1].obj,
X			    ray, &hitnext, dist2+EPSILON, &distnext)) {
X				/*
X				 * None of obj1 beyond, return hit2 (leaving)
X				 */
X				*hitclose = hit2p;
X				*distclose = dist2;
X				csg_set_enter(hit2p, FALSE);
X				return TRUE;
X			} else {
X				/*
X				 * Since hit1 is supposed to be the close one,
X				 * swap them and copy hitnext into hit2.
X	     			 */
X				hittmp = hit1p;
X				hit1p = hit2p;
X				hit2p = hittmp;
X				dist1 = dist2;
X				CsgHitlistCopy(&hitnext, hit2p);
X				dist2 = distnext;
X				/* and continue */
X			}
X		}
X	}
X}
X
Xstatic int
XCsgIntersectInt(ray, hit1p, hit2p, dist1, dist2, hitclose, distclose)
XRay *ray;
XHitList *hit1p, *hit2p, **hitclose;
XFloat dist1, dist2, *distclose;
X{
X	HitList *hittmp, hitnext;
X	Float distnext;
X
X	while (TRUE) {
X		if (!csg_enter_obj(hit2p)) {
X			/* Ray is leaving obj2 */
X			/* Return hit1 info */
X			*hitclose = hit1p;
X			*distclose = dist1;
X			csg_set_enter(hit1p, csg_enter_obj(hit1p));
X			return TRUE;
X		} else {
X			distnext = FAR_AWAY;
X			hitnext.nodes = 0;
X			if (!intersect(hit1p->data[hit1p->nodes-1].obj,
X			    ray, &hitnext, dist2+EPSILON, &distnext)) {
X				/*
X				 * None of obj1 beyond, so return miss
X				 */
X				return FALSE;
X			} else {
X				/*
X				 * Since hit1 is supposed to be the
X				 * close one, swap them and copy
X				 * hitnext into hit2.
X				 */
X				hittmp = hit1p;
X				hit1p = hit2p;
X				hit2p = hittmp;
X				dist1 = dist2;
X				CsgHitlistCopy(&hitnext, hit2p);
X				dist2 = distnext;
X				/* and continue */
X			}
X		}
X	}
X}
X
Xstatic int
XCsgDifferenceInt(ray, hit1p, hit2p, dist1, dist2, hitclose, distclose)
XRay *ray;
XHitList *hit1p, *hit2p, **hitclose;
XFloat dist1, dist2, *distclose;
X{
X	Float distnext;
X	HitList hitnext;
X
X	while (TRUE) {
X		if (dist1 < dist2) {
X			if (hit2p->nodes == 0 ||
X			    csg_enter_obj(hit2p)) {
X				/* return hit1 */
X				*hitclose = hit1p;
X				*distclose = dist1;
X				csg_set_enter(hit1p, csg_enter_obj(hit1p));
X				return TRUE;
X			} else {
X				distnext = FAR_AWAY;
X				hitnext.nodes = 0;
X				if (!intersect(hit1p->data[hit1p->nodes-1].obj,
X				    ray, &hitnext, dist2+EPSILON, &distnext)) {
X					/*
X					 * None of obj1 beyond, so
X					 * return miss
X					 */
X					return FALSE;
X				} else {
X					dist1 = distnext;
X					CsgHitlistCopy(&hitnext, hit1p);
X					/* and continue */
X				}
X			}
X		} else { /* dist1 <= dist2 */
X			if (hit1p->nodes == 0) {
X				/* return a miss */
X				return FALSE;
X			}
X			if (!csg_enter_obj(hit1p)) {
X				/*
X				 * return hit2, but invert hit2
X				 * Enter/Leave flag
X				 */
X				*hitclose = hit2p;
X				*distclose = dist2;
X				csg_set_enter(hit2p, !csg_enter_obj(hit2p));
X				return TRUE;
X			} else {
X				distnext = FAR_AWAY;
X				hitnext.nodes = 0;
X				if (!intersect(hit2p->data[hit2p->nodes-1].obj,
X				    ray, &hitnext, dist1+EPSILON, &distnext)) {
X					/*
X					 * None of obj2 beyond, so
X					 * return hit1
X					 */
X					*hitclose = hit1p;
X					*distclose = dist1;
X					/* we know we're entering obj1 */
X					csg_set_enter(hit1p, TRUE);
X					return TRUE;
X				} else {
X					dist2 = distnext;
X					CsgHitlistCopy(&hitnext, hit2p);
X					/* and continue */
X				}
X			}
X		}
X	}
X}
X
Xint
XCsgIntersect(csg, ray, hitlist, mindist, maxdist)
XCsg *csg;
XRay *ray;
XHitList *hitlist;
XFloat mindist, *maxdist;
X{
X	Float dist1, dist2, disttmp, distclose;
X	HitList hit1, hit2, *hit1p, *hit2p, *hitclose;
X
X	hit1p = &hit1;
X	hit2p = &hit2;
X	if (!csg_intersect_objs(csg, ray, hit1p, hit2p, mindist,
X	    &dist1, &dist2)) {
X		/* missed the csg object */
X		return FALSE;
X	}
X
X	if ((dist1 > dist2) &&
X	    (csg->operator == CSG_UNION || csg->operator == CSG_INTERSECT)) {
X		/* swap so 1 is closest (except in difference case) */
X		disttmp = dist2;  
X		dist2 = dist1;  
X		dist1 = disttmp;
X		hit1p = &hit2;  
X		hit2p = &hit1;
X	}
X
X	/*
X	 * Call appropriate intersection method.  If FALSE is return,
X	 * no hit of any kind was found.
X	 */
X	if (!(*csg->intmeth)(ray, hit1p, hit2p, dist1, dist2,
X	    &hitclose, &distclose))
X		return FALSE;
X
X	/*
X	 * At this time, the closest hit is in hitclose and
X	 * distclose.
X	 */
X	if (distclose < mindist || distclose > *maxdist)
X		return FALSE;
X
X	CsgHitlistCopy(hitclose, hitlist);
X	*maxdist = distclose;
X	return TRUE;
X}
X
Xstatic void
XCsgHitlistCopy(from, to)
XHitList *from, *to;
X{
X	int i;
X
X	to->nodes = from->nodes;
X	for (i = 0; i < from->nodes; i++)
X		to->data[i] = from->data[i];
X}
X
Xstatic void
XCsgSetBounds(csg, bounds)
XCsg *csg;
XFloat bounds[2][3];
X{
X	GeomComputeBounds(csg->obj1);
X	GeomComputeBounds(csg->obj2);
X
X	switch (csg->operator) {
X	case CSG_UNION:
X		bounds[LOW][X] = min(csg->obj1->bounds[LOW][X], csg->obj2->bounds[LOW][X]);
X		bounds[HIGH][X] = max(csg->obj1->bounds[HIGH][X], csg->obj2->bounds[HIGH][X]);
X		bounds[LOW][Y] = min(csg->obj1->bounds[LOW][Y], csg->obj2->bounds[LOW][Y]);
X		bounds[HIGH][Y] = max(csg->obj1->bounds[HIGH][Y], csg->obj2->bounds[HIGH][Y]);
X		bounds[LOW][Z] = min(csg->obj1->bounds[LOW][Z], csg->obj2->bounds[LOW][Z]);
X		bounds[HIGH][Z] = max(csg->obj1->bounds[HIGH][Z], csg->obj2->bounds[HIGH][Z]);
X		break;
X	case CSG_INTERSECT:
X		bounds[LOW][X] = max(csg->obj1->bounds[LOW][X], csg->obj2->bounds[LOW][X]);
X		bounds[HIGH][X] = min(csg->obj1->bounds[HIGH][X], csg->obj2->bounds[HIGH][X]);
X		bounds[LOW][Y] = max(csg->obj1->bounds[LOW][Y], csg->obj2->bounds[LOW][Y]);
X		bounds[HIGH][Y] = min(csg->obj1->bounds[HIGH][Y], csg->obj2->bounds[HIGH][Y]);
X		bounds[LOW][Z] = max(csg->obj1->bounds[LOW][Z], csg->obj2->bounds[LOW][Z]);
X		bounds[HIGH][Z] = min(csg->obj1->bounds[HIGH][Z], csg->obj2->bounds[HIGH][Z]);
X		break;
X	case CSG_DIFFERENCE:
X		bounds[LOW][X] = csg->obj1->bounds[LOW][X];
X		bounds[HIGH][X] = csg->obj1->bounds[HIGH][X];
X		bounds[LOW][Y] = csg->obj1->bounds[LOW][Y];
X		bounds[HIGH][Y] = csg->obj1->bounds[HIGH][Y];
X		bounds[LOW][Z] = csg->obj1->bounds[LOW][Z];
X		bounds[HIGH][Z] = csg->obj1->bounds[HIGH][Z];
X		break;
X	default:
X		RLerror(RL_ABORT, "Unknown csg operator type %d?\n",
X			csg->operator);
X	}
X}
X
X/*
X * Return index of hitlist node closest to the leaf and not below any
X * CSG object.
X */
Xint
XFirstCSGGeom(hitlist)
XHitList *hitlist;
X{
X	int i;
X
X	/*
X	 * UUUUGLY -- detect if obj is a CsgGeom by comparing
X	 * methods with iCsgMethods.
X	 */
X	for (i = hitlist->nodes -1; i; i--)
X		if (hitlist->data[i].obj->methods == iCsgMethods)
X			return i;
X	return 0;
X}
X
Xvoid
XCsgBounds(csg, bounds)
XCsg *csg;
XFloat bounds[2][3];
X{
X	CsgSetBounds(csg, csg->bounds);
X	BoundsCopy(csg->bounds, bounds);
X}
X
Xint
XCsgConvert(csg, list)
XCsg *csg;
XGeom *list;
X{
X	static int OpenAdvised = FALSE;
X	/*
X	 * Currently, this only handles two objects.
X	 * Will be fixed in the future.
X	 * No really we promise.
X	 */
X	if (!list || !list->next) {
X		RLerror(RL_WARN, "CSG needs at least two objects.\n");
X		return 0;
X	}
X	if (list->next->next) {
X		RLerror(RL_WARN, "Currently, CSG only handles two objects.\n");
X		return 0;
X	}
X	/*
X	 * Things are put into lists backwards....
X	 */
X	csg->obj2 = list;
X	csg->obj1 = list->next;
X	if ((!csg->obj1->methods->closed || !csg->obj2->methods->closed) &&
X	    !OpenAdvised) {
X		RLerror(RL_ADVISE,
X			"Performing CSG with non-closed object(s).\n");
X		OpenAdvised = TRUE;
X	}
X	return csg->obj1->prims + csg->obj2->prims;
X}
X
Xvoid
XCsgMethodRegister(meth)
XUserMethodType meth;
X{
X	if (iCsgMethods)
X		iCsgMethods->user = meth;
X}
END_OF_FILE
if test 10585 -ne `wc -c <'libray/libobj/csg.c'`; then
    echo shar: \"'libray/libobj/csg.c'\" unpacked with wrong size!
fi
# end of 'libray/libobj/csg.c'
fi
if test -f 'libray/libobj/grid.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'libray/libobj/grid.c'\"
else
echo shar: Extracting \"'libray/libobj/grid.c'\" \(11807 characters\)
sed "s/^X//" >'libray/libobj/grid.c' <<'END_OF_FILE'
X/*
X * grid.c
X *
X * Copyright (C) 1989, 1991, Craig E. Kolb
X * All rights reserved.
X *
X * This software may be freely copied, modified, and redistributed
X * provided that this copyright notice is preserved on all copies.
X *
X * You may not distribute this software, in whole or in part, as part of
X * any commercial product without the express consent of the authors.
X *
X * There is no warranty or other guarantee of fitness of this software
X * for any purpose.  It is provided solely "as is".
X *
X * $Id: grid.c,v 4.0.1.1 91/10/04 15:55:37 cek Exp Locker: cek $
X *
X * $Log:	grid.c,v $
X * Revision 4.0.1.1  91/10/04  15:55:37  cek
X * patch1: Removed straight floating point comparisons.
X * 
X * Revision 4.0  91/07/17  14:38:02  kolb
X * Initial version.
X * 
X */
X#include "geom.h"
X#include "grid.h"
X
Xstatic Methods *iGridMethods = NULL;
Xstatic char gridName[] = "grid";
X
Xstatic unsigned long raynumber = 1;		/* Current "ray number". */
X						/* (should be "grid number") */
Xstatic void engrid(), GridFreeVoxels();
Xstatic int pos2grid(), CheckVoxel();
X
XGrid *
XGridCreate(x, y, z)
Xint x, y, z;
X{
X	Grid *grid;
X
X	if (x < 1 || y < 1 || z < 1) {
X		RLerror(RL_WARN, "Invalid grid specification.\n");
X		return (Grid *)NULL;
X	}
X	grid = (Grid *)share_calloc(1, sizeof(Grid));
X	grid->xsize = x;
X	grid->ysize = y;
X	grid->zsize = z;
X	return grid;	
X}
X
Xchar *
XGridName()
X{
X	return gridName;
X}
X
X/*
X * Intersect ray with grid, returning distance from "pos" to
X * nearest intersection with an object in the grid.  Returns 0.
X * if no intersection.
X */
Xint
XGridIntersect(grid, ray, hitlist, mindist, maxdist)
XGrid *grid;
XRay *ray;
XHitList *hitlist;
XFloat mindist, *maxdist;
X{
X	GeomList *list;
X	Geom *obj;
X	int hit;
X	Float offset, tMaxX, tMaxY, tMaxZ;
X	Float tDeltaX, tDeltaY, tDeltaZ, *raybounds[2][3];
X	int stepX, stepY, stepZ, outX, outY, outZ, x, y, z;
X	Vector curpos, nXp, nYp, nZp, np, pDeltaX, pDeltaY, pDeltaZ;
X	unsigned long counter;
X
X	hit = FALSE;
X	/*
X	 * Check unbounded objects.
X	 */
X	for (obj = grid->unbounded ; obj; obj = obj->next) {
X		if (intersect(obj, ray, hitlist, mindist, maxdist))
X			hit = TRUE;
X	}
X
X	/*
X	 * If outside of the bounding box, check to see if we
X	 * hit it.
X	 */
X	VecAddScaled(ray->pos, mindist, ray->dir, &curpos);
X	if (OutOfBounds(&curpos, grid->bounds)) {
X		offset = *maxdist;
X		if (!BoundsIntersect(ray, grid->bounds, mindist, &offset))
X			/*
X			 * Ray never hit grid space.
X			 */
X			return hit;
X		/*
X		 * else
X		 *	The ray enters voxel space before it hits
X		 * 	an unbounded object.
X		 */
X		VecAddScaled(ray->pos, offset, ray->dir, &curpos);
X	} else
X		offset = mindist;
X
X	counter = raynumber++;
X
X	/*
X	 * tMaxX is the absolute distance from the ray origin we must move
X	 *		to get to the next voxel in the X
X	 *		direction.  It is incrementally updated
X	 * 		by DDA as we move from voxel-to-voxel.
X	 * tDeltaX is the relative amount along the ray we move to
X	 *		get to the next voxel in the X direction. Thus,
X	 *		when we decide to move in the X direction,
X	 * 		we increment tMaxX by tDeltaX.
X	 */
X	x = x2voxel(grid, curpos.x);
X	if (x == grid->xsize)
X		x--;
X	if (fabs(ray->dir.x) < EPSILON) {
X		tMaxX = FAR_AWAY;
X		raybounds[LOW][X] = &curpos.x;
X		raybounds[HIGH][X] = &np.x;
X		tDeltaX = 0.;
X	} else if (ray->dir.x < 0.) {
X		tMaxX = offset + (voxel2x(grid, x) - curpos.x) / ray->dir.x;
X		tDeltaX = grid->voxsize[X] / - ray->dir.x;
X		stepX = outX = -1;
X		raybounds[LOW][X] = &np.x;
X		raybounds[HIGH][X] = &curpos.x;
X	} else {
X		tMaxX = offset + (voxel2x(grid, x+1) - curpos.x) / ray->dir.x;
X		tDeltaX = grid->voxsize[X] / ray->dir.x;
X		stepX = 1;
X		outX = grid->xsize;
X		raybounds[LOW][X] = &curpos.x;
X		raybounds[HIGH][X] = &np.x;
X	}
X
X	y = y2voxel(grid, curpos.y);
X	if (y == grid->ysize)
X		y--;
X
X	if (fabs(ray->dir.y) < EPSILON) {
X		tMaxY = FAR_AWAY;
X		raybounds[LOW][Y] = &curpos.y;
X		raybounds[HIGH][Y] = &np.y;
X		tDeltaY = 0.;
X	} else if (ray->dir.y < 0.) {
X		tMaxY = offset + (voxel2y(grid, y) - curpos.y) / ray->dir.y;
X		tDeltaY = grid->voxsize[Y] / - ray->dir.y;
X		stepY = outY = -1;
X		raybounds[LOW][Y] = &np.y;
X		raybounds[HIGH][Y] = &curpos.y;
X	} else {
X		tMaxY = offset + (voxel2y(grid, y+1) - curpos.y) / ray->dir.y;
X		tDeltaY = grid->voxsize[Y] / ray->dir.y;
X		stepY = 1;
X		outY = grid->ysize;
X		raybounds[LOW][Y] = &curpos.y;
X		raybounds[HIGH][Y] = &np.y;
X	}
X
X	z = z2voxel(grid, curpos.z);
X	if (z == grid->zsize)
X		z--;
X	if (fabs(ray->dir.z) < EPSILON) {
X		tMaxZ = FAR_AWAY;
X		raybounds[LOW][Z] = &curpos.z;
X		raybounds[HIGH][Z] = &np.z;
X		tDeltaZ = 0.;
X	} else if (ray->dir.z < 0.) {
X		tMaxZ = offset + (voxel2z(grid, z) - curpos.z) / ray->dir.z;
X		tDeltaZ = grid->voxsize[Z] / - ray->dir.z;
X		stepZ = outZ = -1;
X		raybounds[LOW][Z] = &np.z;
X		raybounds[HIGH][Z] = &curpos.z;
X	} else {
X		tMaxZ = offset + (voxel2z(grid, z+1) - curpos.z) / ray->dir.z;
X		tDeltaZ = grid->voxsize[Z] / ray->dir.z;
X		stepZ = 1;
X		outZ = grid->zsize;
X		raybounds[LOW][Z] = &curpos.z;
X		raybounds[HIGH][Z] = &np.z;
X	}
X
X	VecScale(tDeltaX, ray->dir, &pDeltaX);
X	VecScale(tDeltaY, ray->dir, &pDeltaY);
X	VecScale(tDeltaZ, ray->dir, &pDeltaZ);
X
X	VecAddScaled(ray->pos, tMaxX, ray->dir, &nXp);
X	VecAddScaled(ray->pos, tMaxY, ray->dir, &nYp);
X	VecAddScaled(ray->pos, tMaxZ, ray->dir, &nZp);
X
X	while (TRUE) {
X		list = grid->cells[x][y][z];
X		if (tMaxX < tMaxY && tMaxX < tMaxZ) {
X			if (list) {
X				np = nXp;
X			    	if (CheckVoxel(list,ray,raybounds,
X			    	    hitlist,counter,offset,maxdist))
X					hit = TRUE;
X			}
X			x += stepX;
X			if (*maxdist < tMaxX || x == outX)
X				break;
X			tMaxX += tDeltaX;
X			curpos = nXp;
X			nXp.x += pDeltaX.x;
X			nXp.y += pDeltaX.y;
X			nXp.z += pDeltaX.z;
X		} else if (tMaxZ < tMaxY) {
X			if (list) {
X				np = nZp;
X			    	if (CheckVoxel(list,ray, raybounds,
X			    	    hitlist,counter,offset,maxdist))
X					hit = TRUE;
X			}
X			z += stepZ;
X			if (*maxdist < tMaxZ || z == outZ)
X				break;
X			tMaxZ += tDeltaZ;
X			curpos = nZp;
X			nZp.x += pDeltaZ.x;
X			nZp.y += pDeltaZ.y;
X			nZp.z += pDeltaZ.z;
X		} else {
X			if (list) {
X				np = nYp;
X			    	if (CheckVoxel(list,ray,raybounds,
X			    	    hitlist,counter,offset,maxdist))
X					hit = TRUE;
X			}
X			y += stepY;
X			if (*maxdist < tMaxY || y == outY)
X				break;
X			tMaxY += tDeltaY;
X			curpos = nYp;
X			nYp.x += pDeltaY.x;
X			nYp.y += pDeltaY.y;
X			nYp.z += pDeltaY.z;
X		}
X	}
X	return hit;
X}
X
X/*
X * Intersect ray with objects in grid cell.  Note that there are a many ways
X * to speed up this routine, all of which uglify the code to a large extent.
X */
Xstatic int
XCheckVoxel(list,ray,raybounds,hitlist,counter,mindist,maxdist)
XGeomList *list;
XRay *ray;
XFloat *raybounds[2][3];
XHitList *hitlist;
Xunsigned long counter;
XFloat mindist, *maxdist;
X{
X	Geom *obj;
X	int hit;
X	Float lx, hx, ly, hy, lz, hz;
X
X	lx = *raybounds[LOW][X];
X	hx = *raybounds[HIGH][X];
X	ly = *raybounds[LOW][Y];
X	hy = *raybounds[HIGH][Y];
X	lz = *raybounds[LOW][Z];
X	hz = *raybounds[HIGH][Z];
X
X	hit = FALSE;
X
X	do {
X		obj = list->obj;
X		/*
X		 * If object's counter is greater than or equal to the
X		 * number associated with the current grid,
X		 * don't bother checking again.  In addition, if the
X		 * bounding box of the ray's extent in the voxel does
X		 * not intersect the bounding box of the object, don't bother.
X		 */
X#ifdef SHAREDMEM
X		if (*obj->counter < counter &&
X#else
X		if (obj->counter < counter &&
X#endif
X		    obj->bounds[LOW][X] <= hx  &&
X		    obj->bounds[HIGH][X] >= lx &&
X		    obj->bounds[LOW][Y] <= hy  &&
X		    obj->bounds[HIGH][Y] >= ly &&
X		    obj->bounds[LOW][Z] <= hz  &&
X		    obj->bounds[HIGH][Z] >= lz) {
X#ifdef SHAREDMEM
X			*obj->counter = counter;
X#else
X			obj->counter = counter;
X#endif
X			if (intersect(obj, ray, hitlist, mindist, maxdist))
X				hit = TRUE;
X		}
X	} while ((list = list->next) != (GeomList *)0);
X
X	return hit;
X}
X
Xint
XGridConvert(grid, objlist)
XGrid *grid;
XGeom *objlist;
X{
X	int num;
X
X	/*
X	 * Keep linked list of all bounded objects in grid; it may come
X	 * in handy.
X	 */
X	grid->objects = objlist;
X	for (num = 0; objlist; objlist = objlist->next)
X		num += objlist->prims;
X
X	return num;
X}
X
Xvoid
XGridBounds(grid, bounds)
XGrid *grid;
XFloat bounds[2][3];
X{
X	Geom *obj, *ltmp;
X	int x, y, i;
X
X	BoundsInit(bounds);
X	/*
X	 * For each object on the list,
X	 * compute its bounds...
X	 */
X	/*
X	 * Find bounding box of bounded objects and get list of
X	 * unbounded objects.
X	 */
X	grid->unbounded = GeomComputeAggregateBounds(&grid->objects,
X				grid->unbounded, grid->bounds);
X
X	BoundsCopy(grid->bounds, bounds);
X
X	grid->voxsize[X] = (grid->bounds[HIGH][X]-grid->bounds[LOW][X])/
X				grid->xsize;
X	grid->voxsize[Y] = (grid->bounds[HIGH][Y]-grid->bounds[LOW][Y])/
X				grid->ysize;
X	grid->voxsize[Z] = (grid->bounds[HIGH][Z]-grid->bounds[LOW][Z])/
X				grid->zsize;
X
X	if (grid->cells == (GeomList ****)NULL) {
X		/*
X	 	 * Allocate voxels.
X	 	 */
X		grid->cells = (GeomList ****)share_malloc(grid->xsize *
X					sizeof(GeomList ***));
X		for (x = 0; x < grid->xsize; x++) {
X			grid->cells[x] = (GeomList ***)share_malloc(grid->ysize *
X				sizeof(GeomList **));
X			for (y = 0; y < grid->ysize; y++)
X				grid->cells[x][y] = (GeomList **)share_calloc(
X					(unsigned)grid->zsize,sizeof(GeomList *));
X		}
X	} else {
X		/*
X		 * New frame...
X		 * Free up the objlists in each voxel.
X		 */
X		GridFreeVoxels(grid);
X	}
X
X	/*
X	 * objlist now holds a linked list of bounded objects.
X	 */
X	for (ltmp = grid->objects; ltmp != (Geom *)0; ltmp = ltmp->next)
X		engrid(ltmp, grid);
X}
X
Xstatic void
XGridFreeVoxels(grid)
XGrid *grid;
X{
X	int x, y, z;
X	GeomList *cell, *next;
X
X	for (x = 0; x < grid->xsize; x++) {
X		for (y = 0; y < grid->ysize; y++) {
X			for (z = 0; z < grid->zsize; z++) {
X				for (cell = grid->cells[x][y][z]; cell; cell = next) {
X					next = cell->next;
X					free((voidstar)cell);
X				}
X				grid->cells[x][y][z] = (GeomList *)NULL;
X			}
X		}
X	}
X}
X
XMethods *
XGridMethods()
X{
X	if (iGridMethods == (Methods *)NULL) {
X		iGridMethods = MethodsCreate();
X		iGridMethods->methods = GridMethods;
X		iGridMethods->create = (GeomCreateFunc *)GridCreate;
X		iGridMethods->intersect = GridIntersect;
X		iGridMethods->name = GridName;
X		iGridMethods->convert = GridConvert;
X		iGridMethods->bounds = GridBounds;
X		iGridMethods->checkbounds = FALSE;
X		iGridMethods->closed = TRUE;
X	}
X	return iGridMethods;
X}
X
X/*
X * Place an object in a grid.
X */
Xstatic void
Xengrid(obj, grid)
XGeom *obj;
XGrid *grid;
X{
X	int x, y, z, low[3], high[3];
X	GeomList *ltmp;
X
X	/*
X	 * This routine should *never* be passed an unbounded object, but...
X	 */
X	if (!pos2grid(grid, obj->bounds[LOW], low) ||
X	    !pos2grid(grid, obj->bounds[HIGH], high) ||
X	    obj->bounds[LOW][X] > obj->bounds[HIGH][X]) {
X		/*
X		 * Geom is partially on wholly outside of
X		 * grid -- this should never happen, but just
X		 * in case...
X		 */
X		RLerror(RL_ABORT, "Engrid got an unbounded object?!\n");
X		return;
X	    }
X
X	/*
X	 * For each voxel that intersects the object's bounding
X	 * box, add pointer to this object to voxel's linked list.
X 	 */
X	for (x = low[X]; x <= high[X]; x++) {
X		for (y = low[Y]; y <= high[Y]; y++) {
X			for (z = low[Z]; z <= high[Z]; z++) {
X				ltmp = (GeomList *)share_malloc(sizeof(GeomList));
X				ltmp->obj = obj;
X				ltmp->next = grid->cells[x][y][z];
X				grid->cells[x][y][z] = ltmp;
X			}
X		}
X	}
X}
X
X/*
X * Convert 3D point to index into grid's voxels.
X */
Xstatic int
Xpos2grid(grid, pos, index)
XGrid *grid;
XFloat pos[3];
Xint index[3];
X{
X	index[X] = (int)(x2voxel(grid, pos[0]));
X	index[Y] = (int)(y2voxel(grid, pos[1]));
X	index[Z] = (int)(z2voxel(grid, pos[2]));
X
X	if (index[X] == grid->xsize)
X		index[X]--;
X	if (index[Y] == grid->ysize)
X		index[Y]--;
X	if (index[Z] == grid->zsize)
X		index[Z]--;
X
X	if (index[X] < 0 || index[X] >= grid->xsize ||
X	    index[Y] < 0 || index[Y] >= grid->ysize ||
X	    index[Z] < 0 || index[Z] >= grid->zsize)
X		return FALSE;
X	return TRUE;
X}
X
Xvoid
XGridMethodRegister(meth)
XUserMethodType meth;
X{
X	if (iGridMethods)
X		iGridMethods->user = meth;
X}
END_OF_FILE
if test 11807 -ne `wc -c <'libray/libobj/grid.c'`; then
    echo shar: \"'libray/libobj/grid.c'\" unpacked with wrong size!
fi
# end of 'libray/libobj/grid.c'
fi
if test -f 'rayshade/raytrace.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rayshade/raytrace.c'\"
else
echo shar: Extracting \"'rayshade/raytrace.c'\" \(11927 characters\)
sed "s/^X//" >'rayshade/raytrace.c' <<'END_OF_FILE'
X/*
X * raytrace.c
X *
X * Copyright (C) 1989, 1991, Craig E. Kolb
X * All rights reserved.
X *
X * This software may be freely copied, modified, and redistributed
X * provided that this copyright notice is preserved on all copies.
X *
X * You may not distribute this software, in whole or in part, as part of
X * any commercial product without the express consent of the authors.
X *
X * There is no warranty or other guarantee of fitness of this software
X * for any purpose.  It is provided solely "as is".
X *
X * $Id: raytrace.c,v 4.0.1.1 92/01/10 17:13:02 cek Exp Locker: cek $
X *
X * $Log:	raytrace.c,v $
X * Revision 4.0.1.1  92/01/10  17:13:02  cek
X * patch3: Made status report print actual scanline number.
X * 
X * Revision 4.0  91/07/17  14:50:49  kolb
X * Initial version.
X * 
X */
X
X#include "rayshade.h"
X#include "libsurf/atmosphere.h"
X#include "libsurf/surface.h"
X#include "libcommon/sampling.h"
X#include "options.h"
X#include "stats.h"
X#include "raytrace.h"
X#include "viewing.h"
X
X#define UNSAMPLED	-1
X#define SUPERSAMPLED	-2
X
Xtypedef struct {
X	Pixel	*pix;	/* Pixel values */
X	int	*samp;	/* Sample number */
X} Scanline;
X
Xstatic int		*SampleNumbers;
Xstatic void	RaytraceInit();
X
Xstatic Ray	TopRay;				/* Top-level ray. */
XFloat		SampleTime();
X
XPixel		WhitePix = {1., 1., 1., 1.},
X		BlackPix = {0., 0., 0., 0.};
X
X/*
X * "Dither matrices" used to encode the 'number' of a ray that samples a
X * particular portion of a pixel.  Hand-coding is ugly, but...
X */
Xstatic int OneSample[1] = 	{0};
Xstatic int TwoSamples[4] =	{0, 2,
X				 3, 1};
Xstatic int ThreeSamples[9] =	{0, 2, 7,
X				 6, 5, 1,
X				 3, 8, 4};
Xstatic int FourSamples[16] =	{ 0,  8,  2, 10,
X				 12,  4, 14,  6,
X				  3, 11,  1,  9,
X				 15,  7, 13,  5};
Xstatic int FiveSamples[25] =	{ 0,  8, 23, 17,  2,
X				 19, 12,  4, 20, 15,
X				  3, 21, 16,  9,  6,
X				 14, 10, 24,  1, 13,
X				 22,  7, 18, 11,  5};
Xstatic int SixSamples[36] =	{ 6, 32,  3, 34, 35,  1,
X				  7, 11, 27, 28,  8, 30,
X				 24, 14, 16, 15, 23, 19,
X				 13, 20, 22, 21, 17, 18,
X				 25, 29, 10,  9, 26, 12,
X				 36,  5, 33,  4,  2, 31};
Xstatic int SevenSamples[49] =	{22, 47, 16, 41, 10, 35,  4,
X				  5, 23, 48, 17, 42, 11, 29,
X				 30,  6, 24, 49, 18, 36, 12,
X				 13, 31,  7, 25, 43, 19, 37,
X				 38, 14, 32,  1, 26, 44, 20,
X				 21, 39,  8, 33,  2, 27, 45,
X				 46, 15, 40,  9, 34,  3, 28};
Xstatic int EightSamples[64] =	{ 8, 58, 59,  5,  4, 62, 63,  1,
X				 49, 15, 14, 52, 53, 11, 10, 56,
X				 41, 23, 22, 44, 45, 19, 18, 48,
X				 32, 34, 35, 29, 28, 38, 39, 25,
X				 40, 26, 27, 37, 36, 30, 31, 33,
X				 17, 47, 46, 20, 21, 43, 42, 24,
X				  9, 55, 54, 12, 13, 51, 50, 16,
X				 64,  2,  3, 61, 60,  6,  7, 57};
X
Xvoid	AdaptiveRefineScanline(), FullySamplePixel(), FullySampleScanline(),
X	SingleSampleScanline();
Xstatic int	ExcessiveContrast();
Xstatic Scanline scan0, scan1, scan2;
X
X
Xvoid
Xraytrace(argc, argv)
Xint argc;
Xchar **argv;
X{
X	int y, *tmpsamp;
X	Pixel *tmppix;
X	Float usertime, systime, lasttime;
X
X	/*
X	 * If this is the first frame,
X	 * allocate scanlines, etc.
X	 */
X	if (Options.framenum == Options.startframe)
X		RaytraceInit();
X	/*
X	 * The top-level ray TopRay always has as its origin the
X	 * eye position and as its medium NULL, indicating that it
X	 * is passing through a medium with index of refraction
X	 * equal to DefIndex.
X	 */
X	TopRay.pos = Camera.pos;
X	TopRay.media = (Medium *)0;
X	TopRay.depth = 0;
X
X	/*
X	 * Always fully sample the bottom and top rows and the left
X	 * and right column of pixels.  This minimizes artifacts that
X	 * may arise when piecing together images.
X	 */
X	FullySampleScanline(0, &scan0);
X
X	SingleSampleScanline(1, &scan1);
X	FullySamplePixel(0, 1, &scan1.pix[0], &scan1.samp[0]);
X	FullySamplePixel(Screen.xsize -1, 1, &scan1.pix[Screen.xsize -1],
X		&scan1.samp[Screen.xsize -1]);
X
X	lasttime = 0;
X	for (y = 1; y < Screen.ysize; y++) {
X		SingleSampleScanline(y+1, &scan2);
X		FullySamplePixel(0, y+1, &scan2.pix[0], &scan2.samp[0]);
X		FullySamplePixel(Screen.xsize -1, y+1,
X			&scan2.pix[Screen.xsize -1],
X			&scan2.samp[Screen.xsize -1]);
X
X		if (Sampling.sidesamples > 1)
X			AdaptiveRefineScanline(y,&scan0,&scan1,&scan2);
X
X		PictureWriteLine(scan0.pix);
X
X		tmppix = scan0.pix;
X		tmpsamp = scan0.samp;
X		scan0.pix = scan1.pix;
X		scan0.samp = scan1.samp;
X		scan1.pix = scan2.pix;
X		scan1.samp = scan2.samp;
X		scan2.pix = tmppix;
X		scan2.samp = tmpsamp;
X
X		if ((y+Screen.miny-1) % Options.report_freq == 0) {
X			fprintf(Stats.fstats,"Finished line %d (%lu rays",
X						y+Screen.miny-1,
X						Stats.EyeRays);
X			if (Options.verbose) {
X				/*
X				 * Report total CPU and split times.
X				 */
X				RSGetCpuTime(&usertime, &systime);
X				fprintf(Stats.fstats,", %2.2f sec,",
X						usertime+systime);
X				fprintf(Stats.fstats," %2.2f split",
X						usertime+systime-lasttime);
X				lasttime = usertime+systime;
X			}
X			fprintf(Stats.fstats,")\n");
X			(void)fflush(Stats.fstats);
X		}
X
X	}
X	/*
X	 * Supersample last scanline.
X	 */
X	for (y = 1; y < Screen.xsize -1; y++) {
X		if (scan0.samp[y] != SUPERSAMPLED)
X			FullySamplePixel(y, Screen.ysize -1,
X				&scan0.pix[y],
X				&scan0.samp[y]);
X	}
X	PictureWriteLine(scan0.pix);
X}
X
Xvoid
XSingleSampleScanline(line, data)
Xint line;
XScanline *data;
X{
X	Float upos, vpos, yp;
X	int x, usamp, vsamp;
X	Pixel tmp;
X
X	yp = line + Screen.miny - 0.5*Sampling.filterwidth;
X	for (x = 0; x < Screen.xsize; x++) {
X		/*
X		 * Pick a sample number...
X		 */
X		data->samp[x] = nrand() * Sampling.totsamples;
X		/*
X		 * Take sample corresponding to sample #.
X		 */
X		usamp = data->samp[x] % Sampling.sidesamples;
X		vsamp = data->samp[x] / Sampling.sidesamples;
X
X		vpos = yp + vsamp * Sampling.filterdelta;
X		upos = x + Screen.minx - 0.5*Sampling.filterwidth +
X				usamp*Sampling.filterdelta;
X		if (Options.jitter) {
X			vpos += nrand()*Sampling.filterdelta;
X			upos += nrand()*Sampling.filterdelta;
X		}
X		TopRay.time = SampleTime(SampleNumbers[data->samp[x]]);
X		SampleScreen(upos, vpos, &TopRay,
X			&data->pix[x], SampleNumbers[data->samp[x]]);
X		if (Options.samplemap)
X			data->pix[x].alpha = 0;
X	}
X}
X
Xvoid
XFullySampleScanline(line, data)
Xint line;
XScanline *data;
X{
X	int x;
X
X	for (x = 0; x < Screen.xsize; x++) {
X		data->samp[x] = UNSAMPLED;
X		FullySamplePixel(x, line, &data->pix[x], &data->samp[x]);
X	}
X}
X
Xvoid
XFullySamplePixel(xp, yp, pix, prevsamp)
Xint xp, yp;
XPixel *pix;
Xint *prevsamp;
X{
X	Float upos, vpos, u, v;
X	int x, y, sampnum;
X	Pixel ctmp;
X
X	if (*prevsamp == SUPERSAMPLED)
X		return;	/* already done */
X
X	Stats.SuperSampled++;
X	if (*prevsamp == UNSAMPLED) {
X		/*
X		 * No previous sample; initialize to black.
X		 */
X		pix->r = pix->g = pix->b = pix->alpha = 0.;
X	} else {
X		if (Sampling.sidesamples == 1) {
X			*prevsamp = SUPERSAMPLED;
X			return;
X		}
X		x = *prevsamp % Sampling.sidesamples;
X		y = *prevsamp / Sampling.sidesamples;
X		pix->r *= Sampling.filter[x][y];
X		pix->g *= Sampling.filter[x][y];
X		pix->b *= Sampling.filter[x][y];
X		pix->alpha *= Sampling.filter[x][y];
X	}
X
X	sampnum = 0;
X	xp += Screen.minx;
X	vpos = Screen.miny + yp - 0.5*Sampling.filterwidth;
X	for (y = 0; y < Sampling.sidesamples; y++,
X	     vpos += Sampling.filterdelta) {
X		upos = xp - 0.5*Sampling.filterwidth;
X		for (x = 0; x < Sampling.sidesamples; x++,
X		     upos += Sampling.filterdelta) {
X			if (sampnum != *prevsamp) {
X				if (Options.jitter) {
X					u = upos + nrand()*Sampling.filterdelta;
X					v = vpos + nrand()*Sampling.filterdelta;
X				} else {
X					u = upos;
X					v = vpos;
X				}
X				TopRay.time = SampleTime(SampleNumbers[sampnum]);
X				SampleScreen(u, v, &TopRay, &ctmp,
X					SampleNumbers[sampnum]);
X				pix->r += ctmp.r*Sampling.filter[x][y];
X				pix->g += ctmp.g*Sampling.filter[x][y];
X				pix->b += ctmp.b*Sampling.filter[x][y];
X				pix->alpha += ctmp.alpha*Sampling.filter[x][y];
X			}
X			if (++sampnum == Sampling.totsamples)
X				sampnum = 0;
X		}
X	}
X
X	if (Options.samplemap)
X		pix->alpha = 255;
X
X	*prevsamp = SUPERSAMPLED;
X}
X
Xvoid
XAdaptiveRefineScanline(y, scan0, scan1, scan2)
Xint y;
XScanline *scan0, *scan1, *scan2;
X{
X	int x, done;
X
X	/*
X	 * Walk down scan1, looking at 4-neighbors for excessive contrast.
X	 * If found, supersample *all* neighbors not already supersampled.
X	 * The process is repeated until either there are no
X	 * high-contrast regions or all such regions are already supersampled.
X	 */
X
X	do {
X		done = TRUE;
X		for (x = 1; x < Screen.xsize -1; x++) {
X			/*
X		 	 * Find min and max RGB for area we care about
X			 */
X			if (ExcessiveContrast(x, scan0->pix, scan1->pix,
X			    scan2->pix)) {
X				if (scan1->samp[x-1] != SUPERSAMPLED) {
X					done = FALSE;
X					FullySamplePixel(x-1, y,
X						&scan1->pix[x-1],
X						&scan1->samp[x-1]);
X				}
X				if (scan0->samp[x] != SUPERSAMPLED) {
X					done = FALSE;
X					FullySamplePixel(x, y-1,
X						&scan0->pix[x],
X						&scan0->samp[x]);
X				}
X				if (scan1->samp[x+1] != SUPERSAMPLED) {
X					done = FALSE;
X					FullySamplePixel(x+1, y,
X						&scan1->pix[x+1],
X						&scan1->samp[x+1]);
X				}
X				if (scan2->samp[x] != SUPERSAMPLED) {
X					done = FALSE;
X					FullySamplePixel(x, y+1,
X						&scan2->pix[x],
X						&scan2->samp[x]);
X				}
X				if (scan1->samp[x] != SUPERSAMPLED) {
X					done = FALSE;
X					FullySamplePixel(x, y,
X						&scan1->pix[x],
X						&scan1->samp[x]);
X				}
X			}
X		}
X	} while (!done);
X}
X
Xstatic int
XExcessiveContrast(x, pix0, pix1, pix2)
Xint x;
XPixel *pix0, *pix1, *pix2;
X{
X	Float mini, maxi, sum, diff;
X
X	maxi = max(pix0[x].r, pix1[x-1].r);
X	if (pix1[x].r > maxi) maxi = pix1[x].r;
X	if (pix1[x+1].r > maxi) maxi = pix1[x+1].r;
X	if (pix2[x].r > maxi) maxi = pix2[x].r;
X
X	mini = min(pix0[x].r, pix1[x-1].r);
X	if (pix1[x].r < mini) mini = pix1[x].r;
X	if (pix1[x+1].r < mini) mini = pix1[x+1].r;
X	if (pix2[x].r < mini) mini = pix2[x].r;
X
X	diff = maxi - mini;
X	sum = maxi + mini;
X	if (sum > EPSILON && diff/sum > Options.contrast.r)
X		return TRUE;
X
X	maxi = max(pix0[x].g, pix1[x-1].g);
X	if (pix1[x].g > maxi) maxi = pix1[x].g;
X	if (pix1[x+1].g > maxi) maxi = pix1[x+1].g;
X	if (pix2[x].g > maxi) maxi = pix2[x].g;
X
X	mini = min(pix0[x].g, pix1[x-1].g);
X	if (pix1[x].g < mini) mini = pix1[x].g;
X	if (pix1[x+1].g < mini) mini = pix1[x+1].g;
X	if (pix2[x].g < mini) mini = pix2[x].g;
X
X	diff = maxi - mini;
X	sum = maxi + mini;
X
X	if (sum > EPSILON && diff/sum > Options.contrast.g)
X		return TRUE;
X
X	maxi = max(pix0[x].b, pix1[x-1].b);
X	if (pix1[x].b > maxi) maxi = pix1[x].b;
X	if (pix1[x+1].b > maxi) maxi = pix1[x+1].b;
X	if (pix2[x].b > maxi) maxi = pix2[x].b;
X
X	mini = min(pix0[x].b, pix1[x-1].b);
X	if (pix1[x].b < mini) mini = pix1[x].b;
X	if (pix1[x+1].b < mini) mini = pix1[x+1].b;
X	if (pix2[x].b < mini) mini = pix2[x].b;
X
X	diff = maxi - mini;
X	sum = maxi + mini;
X	if (sum > EPSILON && diff/sum > Options.contrast.b)
X		return TRUE;
X
X	return FALSE;
X}
X
XFloat
XSampleTime(sampnum)
Xint sampnum;
X{
X	Float window, jitter = 0.0, res;
X
X	if (Options.shutterspeed <= 0.)
X		return Options.framestart;
X	if (Options.jitter)
X		jitter = nrand();
X	window = Options.shutterspeed / Sampling.totsamples;
X	res = Options.framestart + window * (sampnum + jitter);
X	TimeSet(res);
X	return res;
X}
X
Xstatic void
XRaytraceInit()
X{
X
X	switch (Sampling.sidesamples) {
X		case 1:
X			SampleNumbers = OneSample;
X			break;
X		case 2:
X			SampleNumbers = TwoSamples;
X			break;
X		case 3:
X			SampleNumbers = ThreeSamples;
X			break;
X		case 4:
X			SampleNumbers = FourSamples;
X			break;
X		case 5:
X			SampleNumbers = FiveSamples;
X			break;
X		case 6:
X			SampleNumbers = SixSamples;
X			break;
X		case 7:
X			SampleNumbers = SevenSamples;
X			break;
X		case 8:
X			SampleNumbers = EightSamples;
X			break;
X		default:
X			RLerror(RL_PANIC,
X				"Sorry, %d rays/pixel not supported.\n",
X					Sampling.totsamples);
X	}
X
X	/*
X 	 * Allocate pixel arrays and arrays to store sampling info.
X 	 */
X	scan0.pix = (Pixel *)Malloc(Screen.xsize * sizeof(Pixel));
X	scan1.pix = (Pixel *)Malloc(Screen.xsize * sizeof(Pixel));
X	scan2.pix = (Pixel *)Malloc(Screen.xsize * sizeof(Pixel));
X
X	scan0.samp = (int *)Malloc(Screen.xsize * sizeof(int));
X	scan1.samp = (int *)Malloc(Screen.xsize * sizeof(int));
X	scan2.samp = (int *)Malloc(Screen.xsize * sizeof(int));
X}
END_OF_FILE
if test 11927 -ne `wc -c <'rayshade/raytrace.c'`; then
    echo shar: \"'rayshade/raytrace.c'\" unpacked with wrong size!
fi
# end of 'rayshade/raytrace.c'
fi
echo shar: End of archive 14 \(of 19\).
cp /dev/null ark14isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 19 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
Modified: Wed Dec 11 17:00:00 1996 GMT
Page accessed 1302 times since Sat Apr 17 21:59:34 1999 GMT