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

  1. /*
  2.  * cylinder.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.  * cylinder.c,v 4.1 1994/08/09 07:58:24 explorer Exp
  17.  *
  18.  * cylinder.c,v
  19.  * Revision 4.1  1994/08/09  07:58:24  explorer
  20.  * Bump version to 4.1
  21.  *
  22.  * Revision 1.1.1.1  1994/08/08  04:52:08  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:37:12  kolb
  26.  * Initial version.
  27.  * 
  28.  */
  29. #include "geom.h"
  30. #include "cylinder.h"
  31.  
  32. static Methods *iCylinderMethods = NULL;
  33. static char cylName[] = "cylinder";
  34.  
  35. unsigned long CylTests, CylHits;
  36.  
  37. Cylinder *
  38. CylinderCreate(r, bot, top)
  39. Float r;
  40. Vector *bot, *top;
  41. {
  42.     Cylinder *cyl;
  43.     Float len;
  44.     Vector axis;
  45.  
  46.     if (r <= 0.) {
  47.         RLerror(RL_WARN, "Invalid cylinder radius.\n");
  48.         return (Cylinder*)NULL;
  49.     }
  50.  
  51.     VecSub(*top, *bot, &axis);
  52.  
  53.     len = VecNormalize(&axis);
  54.  
  55.     if (len < EPSILON) {
  56.         RLerror(RL_WARN, "Degenerate cylinder.\n");
  57.         return (Cylinder *)NULL;
  58.     }
  59.  
  60.     cyl = (Cylinder *)share_malloc(sizeof(Cylinder));
  61.     CoordSysTransform(bot, &axis, r, len, &cyl->trans);
  62.     return cyl;
  63. }
  64.  
  65. Methods *
  66. CylinderMethods()
  67. {
  68.     if (iCylinderMethods == (Methods *)NULL) {
  69.         iCylinderMethods = MethodsCreate();
  70.         iCylinderMethods->name = CylinderName;
  71.         iCylinderMethods->create = (GeomCreateFunc *)CylinderCreate;
  72.         iCylinderMethods->methods = CylinderMethods;
  73.         iCylinderMethods->intersect = CylinderIntersect;
  74.         iCylinderMethods->normal = CylinderNormal;
  75.         iCylinderMethods->uv = CylinderUV;
  76.         iCylinderMethods->bounds = CylinderBounds;
  77.         iCylinderMethods->stats = CylinderStats;
  78.         iCylinderMethods->checkbounds = TRUE;
  79.         iCylinderMethods->closed = FALSE;
  80.     }
  81.     return iCylinderMethods;
  82. }
  83.  
  84. /*
  85.  * Ray-cylinder intersection test.
  86.  */
  87. int
  88. CylinderIntersect(cyl, ray, mindist, maxdist)
  89. Cylinder *cyl;
  90. Ray *ray;
  91. Float mindist, *maxdist;
  92. {
  93.     Float t1, t2, a, b, c, zpos1, zpos2, disc;
  94.     Float distfact;
  95.     Ray newray;
  96.     Vector nray, npos;
  97.     Float nmin;
  98.  
  99.     CylTests++;
  100.  
  101.     /*
  102.      * Transform ray into canonical cylinder space.
  103.      */
  104.     newray = *ray;
  105.     distfact = RayTransform(&newray, &cyl->trans.itrans);
  106.     nray = newray.dir;
  107.     npos = newray.pos;
  108.     nmin = mindist * distfact;
  109.  
  110.     a = nray.x * nray.x + nray.y * nray.y;
  111.     if (a < EPSILON*EPSILON)
  112.         /* |nray.z| == 1. */
  113.         return FALSE;
  114.  
  115.     b = nray.x * npos.x + nray.y * npos.y;
  116.     c = npos.x*npos.x + npos.y*npos.y - 1;
  117.     disc = b*b - a*c;
  118.     if(disc < 0.)
  119.         return FALSE;
  120.     disc = sqrt(disc);
  121.     t1 = (-b + disc) / a;
  122.     t2 = (-b - disc) / a;
  123.     if (t1 < nmin && t2 < nmin)
  124.         return FALSE;
  125.     zpos1 = npos.z + t1 * nray.z;
  126.     zpos2 = npos.z + t2 * nray.z;
  127.  
  128.     if (t1 < nmin || zpos1 < 0. || zpos1 > 1.) {
  129.         if (t2 < nmin || zpos2 < 0. || zpos2 > 1.)
  130.             return FALSE;
  131.         else
  132.             t1 = t2 / distfact;
  133.  
  134.     } else {
  135.         if (t2 < nmin || zpos2 < 0. || zpos2 > 1.)
  136.             t1 /= distfact;
  137.         else {
  138.             t1 = min(t1, t2) / distfact;
  139.         }
  140.     }
  141.     
  142.     if (t1 < *maxdist) {
  143.         *maxdist = t1;
  144.         CylHits++;
  145.         return TRUE;
  146.     }
  147.     return FALSE;
  148. }
  149.  
  150. int
  151. CylinderNormal(cyl, pos, nrm, gnrm)
  152. Cylinder *cyl;
  153. Vector *pos, *nrm, *gnrm;
  154. {
  155.     /*
  156.      * Transform position into cylinder space.
  157.      */
  158.     *nrm = *pos;
  159.     PointTransform(nrm, &cyl->trans.itrans);
  160.     /*
  161.      * The normal is equal to the point of intersection in cylinder
  162.      * space, but with Z = 0.;
  163.      */
  164.     nrm->z = 0.;
  165.  
  166.     /*
  167.      * Tranform normal back to world space.
  168.      */
  169.     NormalTransform(nrm, &cyl->trans.itrans);
  170.     *gnrm = *nrm;
  171.     return FALSE;
  172. }
  173.  
  174. void
  175. CylinderUV(cyl, pos, norm, uv, dpdu, dpdv)
  176. Cylinder *cyl;
  177. Vector *pos, *norm, *dpdu, *dpdv;
  178. Vec2d *uv;
  179. {
  180.     Vector npos;
  181.  
  182.     npos = *pos;
  183.     PointTransform(&npos, &cyl->trans.itrans);
  184.  
  185.     uv->v = npos.z;
  186.     /*
  187.      * Due to roundoff error, |npos.x| may be > 1.
  188.      */
  189.     if (npos.x > 1.)
  190.         uv->u = 0.;
  191.     else if (npos.x < -1.)
  192.         uv->u = 0.5;
  193.     else
  194.         uv->u = acos(npos.x) / TWOPI;
  195.     if (npos.y < 0.)
  196.         uv->u = 1. - uv->u;
  197.  
  198.     if (dpdu) {
  199.         dpdv->x = dpdv->y = 0.;
  200.         dpdv->z = 1.;
  201.         dpdu->x = -npos.y;
  202.         dpdu->y = npos.x;
  203.         dpdu->z = 0.;
  204.         VecTransform(dpdu, &cyl->trans.trans);
  205.         VecTransform(dpdv, &cyl->trans.trans);
  206.         (void)VecNormalize(dpdu);
  207.         (void)VecNormalize(dpdv);
  208.     }
  209. }
  210.  
  211. void
  212. CylinderBounds(cyl, bounds)
  213. Cylinder *cyl;
  214. Float bounds[2][3];
  215. {
  216.     bounds[LOW][X] = bounds[LOW][Y] = -1;
  217.     bounds[HIGH][X] = bounds[HIGH][Y] = 1;
  218.     bounds[LOW][Z] = 0.;
  219.     bounds[HIGH][Z] = 1;
  220.     /*
  221.      * Transform bounding box to world space.
  222.      */
  223.     BoundsTransform(&cyl->trans.trans, bounds);
  224. }
  225.  
  226. char *
  227. CylinderName()
  228. {
  229.     return cylName;
  230. }
  231.  
  232. void
  233. CylinderStats(tests, hits)
  234. unsigned long *tests, *hits;
  235. {
  236.     *tests = CylTests;
  237.     *hits = CylHits;
  238. }
  239.  
  240. void
  241. CylinderMethodRegister(meth)
  242. UserMethodType meth;
  243. {
  244.     if (iCylinderMethods)
  245.         iCylinderMethods->user = meth;
  246. }
  247.