This is sphere.c in view mode; [Download] [Up]
/* * sphere.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$ * * $Log$ */ #include "object.h" #include "sphere.h" static Methods *iSphereMethods = NULL; static char sphereName[] = "sphere"; unsigned long SphTests, SphHits; /* * Create & return reference to a sphere. */ Sphere * SphereCreate(r, pos) Float r; Vector *pos; { Sphere *sphere; if (r < EPSILON) { RLerror(RL_WARN, "Degenerate sphere.\n"); return (Sphere *)NULL; } sphere = (Sphere *)Malloc(sizeof(Sphere)); /* * sphere->rsq holds the square of the radius. */ sphere->r = r; sphere->rsq = r*r; sphere->x = pos->x; sphere->y = pos->y; sphere->z = pos->z; return sphere; } Methods * SphereMethods() { if (iSphereMethods == (Methods *)NULL) { iSphereMethods = MethodsCreate(); iSphereMethods->create = (ObjCreateFunc *)SphereCreate; iSphereMethods->methods = SphereMethods; iSphereMethods->name = SphereName; iSphereMethods->intersect = SphereIntersect; iSphereMethods->normal = SphereNormal; iSphereMethods->uv = SphereUV; iSphereMethods->enter = SphereEnter; iSphereMethods->bounds = SphereBounds; iSphereMethods->stats = SphereStats; iSphereMethods->checkbounds = TRUE; iSphereMethods->closed = TRUE; } return iSphereMethods; } /* * Ray/sphere intersection test. */ int SphereIntersect(sph, ray, mindist, maxdist) Sphere *sph; Ray *ray; Float mindist, *maxdist; { Float xadj, yadj, zadj; Float b, t, s; SphTests++; /* * Translate ray origin to object space and negate everything. * (Thus, we translate the sphere into ray space, which saves * us a couple of negations below.) */ xadj = sph->x - ray->pos.x; yadj = sph->y - ray->pos.y; zadj = sph->z - ray->pos.z; /* * Solve quadratic equiation. */ b = xadj * ray->dir.x + yadj * ray->dir.y + zadj * ray->dir.z; t = b * b - xadj * xadj - yadj * yadj - zadj * zadj + sph->rsq; if (t < 0.) return FALSE; t = (Float)sqrt((double)t); s = b - t; if (s > mindist) { if (s < *maxdist) { *maxdist = s; SphHits++; return TRUE; } return FALSE; } s = b + t; if (s > mindist && s < *maxdist) { *maxdist = s; SphHits++; return TRUE; } return FALSE; } /* * Compute normal to sphere at pos */ int SphereNormal(sphere, pos, nrm, gnrm) Sphere *sphere; Vector *pos, *nrm, *gnrm; { nrm->x = (pos->x - sphere->x) / sphere->r; nrm->y = (pos->y - sphere->y) / sphere->r; nrm->z = (pos->z - sphere->z) / sphere->r; *gnrm = *nrm; return FALSE; } /* * Determine if ray enters (TRUE) or leaves (FALSE) sphere at pos */ int SphereEnter(sphere, ray, mind, hitd) Sphere *sphere; Ray *ray; Float mind, hitd; { Vector pos; VecAddScaled(ray->pos, mind, ray->dir, &pos); pos.x -= sphere->x; pos.y -= sphere->y; pos.z -= sphere->z; return dotp(&pos, &pos) > sphere->rsq; } /*ARGSUSED*/ void SphereUV(sphere, pos, norm, uv, dpdu, dpdv) Sphere *sphere; Vector *pos, *norm, *dpdu, *dpdv; Vec2d *uv; { Float phi, theta; if (norm->z > 1.) /* roundoff */ phi = PI; else if (norm->z < -1.) phi = 0; else phi = acos(-norm->z); uv->v = phi / PI; if (fabs(uv->v) < EPSILON || equal(uv->v, 1.)) uv->u = 0.; else { theta = norm->x / sin(phi); if (theta > 1.) theta = 0.; else if (theta < -1.) theta = 0.5; else theta = acos(theta) / TWOPI; if (norm->y > 0) uv->u = theta; else uv->u = 1 - theta; } if (dpdu != (Vector *)0) { dpdu->x = -norm->y; dpdu->y = norm->x; dpdu->z = 0.; (void)VecNormalize(dpdu); (void)VecNormCross(norm, dpdu, dpdv); } } void SphereBounds(s, bounds) Sphere *s; Float bounds[2][3]; { bounds[LOW][X] = s->x - s->r; bounds[HIGH][X] = s->x + s->r; bounds[LOW][Y] = s->y - s->r; bounds[HIGH][Y] = s->y + s->r; bounds[LOW][Z] = s->z - s->r; bounds[HIGH][Z] = s->z + s->r; } char * SphereName() { return sphereName; } void SphereStats(tests, hits) unsigned long *tests, *hits; { *tests = SphTests; *hits = SphHits; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.