home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 3 / Amiga Tools 3.iso / grafik / raytracing / rayshade-4.0.6.3 / libray / libobj / sphere.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-09  |  4.9 KB  |  254 lines

  1. /*
  2.  * sphere.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * sphere.c,v 4.1 1994/08/09 08:00:03 explorer Exp
  17.  *
  18.  * sphere.c,v
  19.  * Revision 4.1  1994/08/09  08:00:03  explorer
  20.  * Bump version to 4.1
  21.  *
  22.  * Revision 1.1.1.1  1994/08/08  04:52:10  explorer
  23.  * Initial import.  This is a prerelease of 4.0.6enh3, or 4.1 possibly.
  24.  *
  25.  * Revision 4.0  91/07/17  14:39:17  kolb
  26.  * Initial version.
  27.  * 
  28.  */
  29. #include "geom.h"
  30. #include "sphere.h"
  31.  
  32. static Methods *iSphereMethods = NULL;
  33. static char sphereName[] = "sphere";
  34.  
  35. unsigned long SphTests, SphHits;
  36.  
  37. /*
  38.  * Create & return reference to a sphere.
  39.  */
  40. Sphere *
  41. SphereCreate(r, pos)
  42. Float r;
  43. Vector *pos;
  44. {
  45.     Sphere *sphere;
  46.  
  47.     if (r < EPSILON) {
  48.         RLerror(RL_WARN, "Degenerate sphere.\n");
  49.         return (Sphere *)NULL;
  50.     }
  51.  
  52.     sphere = (Sphere *)share_malloc(sizeof(Sphere));
  53.     /*
  54.      * sphere->rsq holds the square of the radius.
  55.      */
  56.     sphere->r = r;
  57.     sphere->rsq = r*r;
  58.     sphere->x = pos->x;
  59.     sphere->y = pos->y;
  60.     sphere->z = pos->z;
  61.  
  62.     return sphere;
  63. }
  64.  
  65. Methods *
  66. SphereMethods()
  67. {
  68.     if (iSphereMethods == (Methods *)NULL) {
  69.         iSphereMethods = MethodsCreate();
  70.         iSphereMethods->create = (GeomCreateFunc *)SphereCreate;
  71.         iSphereMethods->methods = SphereMethods;
  72.         iSphereMethods->name = SphereName;
  73.         iSphereMethods->intersect = SphereIntersect;
  74.         iSphereMethods->normal = SphereNormal;
  75.         iSphereMethods->uv = SphereUV;
  76.         iSphereMethods->enter = SphereEnter;
  77.         iSphereMethods->bounds = SphereBounds;
  78.         iSphereMethods->stats = SphereStats;
  79.         iSphereMethods->checkbounds = TRUE;
  80.         iSphereMethods->closed = TRUE;
  81.     }
  82.     return iSphereMethods;
  83. }
  84.  
  85. /*
  86.  * Ray/sphere intersection test.
  87.  */
  88. int
  89. SphereIntersect(sph, ray, mindist, maxdist)
  90. Sphere *sph;
  91. Ray *ray;
  92. Float mindist, *maxdist;
  93. {
  94.     Float xadj, yadj, zadj;
  95.     Float b, t, s;
  96.  
  97.     SphTests++;
  98.     /*
  99.      * Translate ray origin to object space and negate everything.
  100.      * (Thus, we translate the sphere into ray space, which saves
  101.      * us a couple of negations below.)
  102.      */
  103.     xadj = sph->x - ray->pos.x;
  104.     yadj = sph->y - ray->pos.y;
  105.     zadj = sph->z - ray->pos.z;
  106.  
  107.     /*
  108.      * Solve quadratic equation.
  109.      */
  110.     b = xadj * ray->dir.x + yadj * ray->dir.y + zadj * ray->dir.z;
  111.     t = b * b - xadj * xadj - yadj * yadj - zadj * zadj + sph->rsq;
  112.     if (t < 0.)
  113.         return FALSE;
  114.     t = (Float)sqrt((double)t);
  115.     s = b - t;
  116.     if (s > mindist) {
  117.         if (s < *maxdist) {
  118.             *maxdist = s;
  119.             SphHits++;
  120.             return TRUE;
  121.         }
  122.         return FALSE;
  123.     }
  124.     s = b + t;
  125.     if (s > mindist && s < *maxdist) {
  126.         *maxdist = s;
  127.         SphHits++;
  128.         return TRUE;
  129.     }
  130.     return FALSE;
  131. }
  132.  
  133. /*
  134.  * Compute normal to sphere at pos
  135.  */
  136. int
  137. SphereNormal(sphere, pos, nrm, gnrm)
  138. Sphere *sphere;
  139. Vector *pos, *nrm, *gnrm;
  140. {
  141.     nrm->x = pos->x - sphere->x;
  142.     nrm->y = pos->y - sphere->y;
  143.     nrm->z = pos->z - sphere->z;
  144.     /*
  145.      * We cannot divide by sphere->r to normalize the vector 
  146.      * because of roundoff errors in the intersection calculation.
  147.      */
  148.     VecNormalize(nrm);
  149.     *gnrm = *nrm;
  150.     return FALSE;
  151. }
  152.  
  153. /*
  154.  * Determine if ray enters (TRUE) or leaves (FALSE) sphere at pos
  155.  */
  156. int
  157. SphereEnter(sphere, ray, mind, hitd)
  158. Sphere *sphere;
  159. Ray *ray;
  160. Float mind, hitd;
  161. {
  162.     Vector pos;
  163.  
  164.     VecAddScaled(ray->pos, mind, ray->dir, &pos);
  165.     pos.x -= sphere->x;
  166.     pos.y -= sphere->y;
  167.     pos.z -= sphere->z;
  168.  
  169.     return dotp(&pos, &pos) > sphere->rsq;
  170. }
  171.  
  172. /*ARGSUSED*/
  173. void
  174. SphereUV(sphere, pos, norm, uv, dpdu, dpdv)
  175. Sphere *sphere;
  176. Vector *pos, *norm, *dpdu, *dpdv;
  177. Vec2d *uv;
  178. {
  179.     Float phi, theta;
  180.     Vector realnorm;
  181.  
  182.     realnorm.x = pos->x - sphere->x;
  183.     realnorm.y = pos->y - sphere->y;
  184.     realnorm.z = pos->z - sphere->z;
  185.     VecNormalize( &realnorm );
  186.     if (realnorm.z > 1.)    /* roundoff */
  187.         phi = PI;
  188.     else if (realnorm.z < -1.)
  189.         phi = 0;
  190.     else
  191.         phi = acos(-realnorm.z);
  192.  
  193.     uv->v = phi / PI;
  194.  
  195.     if (fabs(uv->v) < EPSILON || equal(uv->v, 1.))
  196.         uv->u = 0.;
  197.     else {
  198.         theta = realnorm.x / sin(phi);
  199.         if (theta > 1.)
  200.             theta = 0.;
  201.         else if (theta < -1.)
  202.             theta = 0.5;
  203.         else
  204.             theta = acos(theta) / TWOPI;
  205.  
  206.         if (realnorm.y > 0)
  207.             uv->u = theta;
  208.         else
  209.             uv->u = 1 - theta;
  210.     }
  211.     if (dpdu != (Vector *)0) {
  212.         dpdu->x = -realnorm.y;
  213.         dpdu->y = realnorm.x;
  214.         dpdu->z = 0.;
  215.         (void)VecNormalize(dpdu);
  216.         (void)VecNormCross(&realnorm, dpdu, dpdv);
  217.     }
  218. }
  219.  
  220. void
  221. SphereBounds(s, bounds)
  222. Sphere *s;
  223. Float bounds[2][3];
  224. {
  225.     bounds[LOW][X] = s->x - s->r;
  226.     bounds[HIGH][X] = s->x + s->r;
  227.     bounds[LOW][Y] = s->y - s->r;
  228.     bounds[HIGH][Y] = s->y + s->r;
  229.     bounds[LOW][Z] = s->z - s->r;
  230.     bounds[HIGH][Z] = s->z + s->r;
  231. }
  232.  
  233. char *
  234. SphereName()
  235. {
  236.     return sphereName;
  237. }
  238.  
  239. void
  240. SphereStats(tests, hits)
  241. unsigned long *tests, *hits;
  242. {
  243.     *tests = SphTests;
  244.     *hits = SphHits;
  245. }
  246.  
  247. void
  248. SphereMethodRegister(meth)
  249. UserMethodType meth;
  250. {
  251.     if (iSphereMethods)
  252.         iSphereMethods->user = meth;
  253. }
  254.