home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Raytrace & Morphing / SOS-RAYTRACE.ISO / programm / source / rayce27s / discs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-02  |  6.8 KB  |  347 lines

  1. /*
  2.  * disc.c -- handle disc type objects This is what an object-file should
  3.  * look like.
  4.  * 
  5.  * (c) 1993, 1994 by Han-Wen Nienhuys <hanwen@stack.urc.tue.nl>
  6.  * 
  7.  * This program is free software; you can redistribute it and/or modify it
  8.  * under the terms of the GNU General Public License as published by the
  9.  * Free Software Foundation;
  10.  * 
  11.  * This program is distributed in the hope that it will be useful, but
  12.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * General Public License for more details.
  15.  * 
  16.  * You should have received a copy of the GNU General Public License along
  17.  * with this program; if not, write to the Free Software Foundation, Inc.,
  18.  * 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. #include "ray.h"
  22. #include "proto.h"
  23. #include "extern.h"
  24.  
  25. extern struct methods my_methods;
  26.  
  27. /* zap memory used by o->data.disc, and its substructures */
  28. PRIVATE void
  29. free_disc(object *o)
  30. {
  31.     free((void *) o->data.disc);
  32.     o->type = NOSHAPE;
  33. }
  34.  
  35. /* initialize a disc_data struct */
  36. PRIVATE void
  37. init_disc(struct disc_data *t)
  38. {
  39.     setvector(t->n, 0, 0, 0);
  40.     setvector(t->center, 0, 0, 0);
  41.     t->R = 1;
  42.     t->r = -1;
  43. }
  44.  
  45. PRIVATE struct disc_data *
  46. get_new_disc(void)
  47. {
  48.     struct disc_data *p;
  49.  
  50.     p = ALLOC(struct disc_data);
  51.  
  52.     CHECK_MEM(p, my_methods.name);
  53.     init_disc(p);
  54.     return p;
  55. }
  56.  
  57. PRIVATE bool
  58. inside_disc(object *o, vector i)
  59. {
  60.     assert(FALSE);
  61. }
  62.  
  63. /* scale it. */
  64. PRIVATE void
  65. scale_disc(object *o, vector s)
  66. {
  67.     struct disc_data *t = o->data.disc;
  68.     double          factor;
  69.  
  70.     if (ABS(s.x) != ABS(s.y) || ABS(s.y) != ABS(s.z)) {
  71.     generic_scale_object(o, s);
  72.     } else {
  73.     t->n.x = t->n.x / s.x;
  74.     t->n.y = t->n.y / s.y;
  75.     t->n.z = t->n.z / s.z;
  76.  
  77.     factor = MAX(ABS(s.x), ABS(s.y));
  78.     factor = MAX(factor, ABS(s.z));
  79.  
  80.     t->R *= factor;
  81.     t->r *= factor;
  82.  
  83.     vcproduct(t->center, t->center, s);
  84.     }
  85. }
  86.  
  87. /* rotation */
  88. PRIVATE void
  89. rotate_disc(object *o, matrix rotmat)
  90. {
  91.     struct disc_data *b = o->data.disc;
  92.  
  93.     if (o->inv_trans)
  94.     generic_rotate_object(o, rotmat);
  95.     else {
  96.     rotate_vector(&b->n, rotmat);
  97.     rotate_vector(&b->center, rotmat);
  98.     }
  99. }
  100.  
  101. /* and translation */
  102. PRIVATE void
  103. translate_disc(object *o, vector t)
  104. {
  105.     struct disc_data *b;
  106.  
  107.     if (o->inv_trans)
  108.     generic_translate_object(o, t);
  109.     else {
  110.  
  111.  
  112.     b = o->data.disc;
  113.     vadd(b->center, b->center, t);
  114.     }
  115. }
  116.  
  117. PUBLIC void
  118. print_disc(object *o)
  119. {
  120. #ifdef DEBUG
  121.     struct disc_data *p = o->data.disc;
  122.  
  123.     print_v("normal", p->n);
  124.     print_v("center", p->center);
  125.     printf("R %f r %f\n", p->R, p->r);
  126. #endif
  127. }
  128.  
  129. /*
  130.  * intersect with the o->data.disc part, return TRUE if intersection
  131.  * found.
  132.  */
  133. PRIVATE bool
  134. all_disc_intersections(dqueue * q, object *o, struct ray *input, int flags, bool *isinside)
  135. {
  136.     dqueue          q_ent;
  137.  
  138.     struct disc_data *d = o->data.disc;
  139.     double          t,
  140.                     dot;
  141.     vector          x;
  142.     double          l;
  143.     struct ray     *r,
  144.                     localray;
  145.  
  146.     if (o->inv_trans) {
  147.     localray = *input;
  148.     r = &localray;
  149.     transform_ray(r, o);
  150.     } else
  151.     r = input;
  152.  
  153.  
  154.     my_methods.test++;
  155.  
  156.     /* do a plane intersection */
  157.     dot = vdot(r->dir, d->n);
  158.  
  159.     if (ISZERO(dot))
  160.     return FALSE;
  161.  
  162.     t = (d->mov - vdot(r->pos, d->n)) / dot;
  163.     if (t < tolerance || t > r->maxt)
  164.     return FALSE;
  165.  
  166.     /* find distance to center */
  167.     svproduct(x, t, r->dir);
  168.     vadd(x, x, r->pos);
  169.     vsub(x, x, d->center);
  170.  
  171.     l = veclen(x);
  172.  
  173.     /* inside? */
  174.     if (l < d->R && l > d->r) {
  175.     my_methods.hit++;
  176.     q_ent.obj = o;
  177.     q_ent.t = t;
  178.     add_to_queue(q, q_ent);
  179.     return TRUE;
  180.     } else
  181.     return FALSE;
  182. }
  183.  
  184. /*
  185.  * returns the normal to the disc
  186.  */
  187. PRIVATE vector
  188. disc_normal(struct intersect i, vector loc)
  189. {
  190.     object         *o = i.q_ent.obj;
  191.     struct disc_data *p = o->data.disc;
  192.  
  193.     if (o->inv_trans) {
  194.     vector          n;
  195.  
  196.     n = transform_normal(*o->inv_trans, p->n);
  197.     norm(n, n);
  198.     return n;
  199.     } else
  200.     return p->n;
  201. }
  202.  
  203. /* copy the shape data */
  204. PRIVATE void
  205. copy_disc(object *dst, object *src)
  206. {
  207.     assert(dst != NULL && src != NULL);
  208.  
  209.     if (dst->type != DISC)
  210.     dst->data.disc = get_new_disc();
  211.     *dst->data.disc = *src->data.disc;
  212.     dst->type = src->type;
  213. }
  214.  
  215. /*
  216.  * bound a disc. It's the same routine as the torus, except, the the minor
  217.  * radius is set to zero.
  218.  */
  219. PRIVATE void
  220. precompute_disc(object *o)
  221. {
  222.     struct disc_data *t = o->data.disc;
  223.  
  224.     double          min[3],
  225.                     max[3];    /* returned minimum and maximum of extent */
  226.     matrix          ctm,
  227.                     tempmatrix;    /* cumulative transformation matrix */
  228.     double          r;        /* major radius of torus */
  229.     int             i;
  230.     double          u1,
  231.                     u2,
  232.                     v1,
  233.                     v2,
  234.                     tmp,
  235.                     denominator;
  236.  
  237.  
  238.     /* precomputation */
  239.     t->mov = vdot(t->n, t->center);
  240.  
  241.     /* do bounding */
  242.     r = t->R;
  243.  
  244.     {
  245.     double          theta,
  246.                     phi;
  247.     vector          rot;
  248.  
  249.     theta = acos(t->n.y / veclen(t->n));
  250.     phi = safe_arctangent(t->n.z, t->n.x);
  251.  
  252.     setvector(rot, 0, 0, -theta);
  253.     rotate_matrix(ctm, rot);
  254.  
  255.     setvector(rot, 0, -phi, 0);
  256.     rotate_matrix(tempmatrix, rot);
  257.     mmproduct(ctm, tempmatrix, ctm);
  258.     }
  259.  
  260.     translate_matrix(tempmatrix, t->center);
  261.     mmproduct(ctm, tempmatrix, ctm);
  262.  
  263.     if (o->inv_trans) {
  264.     invert_trans(tempmatrix, *o->inv_trans);
  265.     mmproduct(tempmatrix, tempmatrix, ctm);
  266.  
  267.     /* Gems do everything transposed. */
  268.     transpose_matrix(ctm, tempmatrix);
  269.     }
  270.     for (i = 0; i < 3; i++) {
  271.  
  272.     /* calculate first extremum.  assure that -PI/2 <= v1 <= PI/2 */
  273.     u1 = safe_arctangent(ctm[2][i], ctm[0][i]);
  274.     denominator = ctm[0][i] * cos(u1) + ctm[2][i] * sin(u1);
  275.     v1 = safe_arctangent(ctm[1][i], denominator);
  276.  
  277.     /* second extremum is +/- PI from u1, negative of v1 */
  278.     if (u1 <= 0)
  279.         u2 = u1 + M_PI;
  280.     else
  281.         u2 = u1 - M_PI;
  282.     v2 = -v1;
  283.  
  284.     /* find and sort extrema locations in this dimension */
  285.     min[i] =
  286.         ctm[0][i] * cos(u1) * (r) +
  287.  
  288.         ctm[2][i] * sin(u1) * (r) +
  289.         ctm[3][i];
  290.     max[i] =
  291.         ctm[0][i] * cos(u2) * (r) +
  292.  
  293.         ctm[2][i] * sin(u2) * (r) +
  294.         ctm[3][i];
  295.     if (min[i] > max[i]) {
  296.         tmp = max[i];
  297.         max[i] = min[i];
  298.         min[i] = tmp;
  299.     }
  300.     }
  301.  
  302.     o->bmin.x = min[0];
  303.     o->bmin.y = min[1];
  304.     o->bmin.z = min[2];
  305.     o->bmax.x = max[0];
  306.     o->bmax.y = max[1];
  307.     o->bmax.z = max[2];
  308.  
  309.     my_methods.howmuch++;
  310.     global_stats.prims++;
  311.  
  312. }
  313.  
  314. /* below, nothings has to be changed. */
  315. PRIVATE struct methods my_methods =
  316. {
  317.     all_disc_intersections,
  318.     disc_normal,
  319.     copy_disc,
  320.     inside_disc,
  321.     rotate_disc,
  322.     translate_disc,
  323.     scale_disc,
  324.     free_disc,
  325.     print_disc,
  326.     precompute_disc,
  327.     "disc",
  328. };
  329.  
  330. /* alloc/init */
  331. PUBLIC object  *
  332. get_new_disc_object(void)
  333. {
  334.     object         *o;
  335.  
  336.     o = get_new_object();
  337.  
  338.     o->data.disc = get_new_disc();
  339.  
  340.     o->methods = &my_methods;
  341.     o->type = DISC;
  342.  
  343.     return o;
  344. }
  345.  
  346. /* eof */
  347.