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

  1. /*
  2.  * box.c -- standard routines for boxes.
  3.  * 
  4.  * (c) 1993, 1994, Han-Wen Nienhuys <hanwen@stack.urc.tue.nl>
  5.  * 
  6.  * This program is free software; you can redistribute it and/or modify it
  7.  * under the terms of the GNU General Public License as published by the
  8.  * Free Software Foundation;
  9.  * 
  10.  * This program is distributed in the hope that it will be useful, but
  11.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  * General Public License for more details.
  14.  * 
  15.  * You should have received a copy of the GNU General Public License along
  16.  * with this program; if not, write to the Free Software Foundation, Inc.,
  17.  * 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. #include "ray.h"
  21. #include "proto.h"
  22. #include "extern.h"
  23.  
  24. extern struct methods my_methods;
  25.  
  26.  
  27. PRIVATE bool
  28. all_box_intersections(dqueue * q, object *o, struct ray *r,
  29.               int flags, bool *isinside)
  30. {
  31.     int             no_int;
  32.     dqueue          q_ent;
  33.     double          d[2];
  34.     struct box_data *b = o->data.box;
  35.  
  36.  
  37.  
  38.     if (o->inv_trans) {
  39.     struct ray      localray;
  40.  
  41.     localray = *r;
  42.     transform_ray(&localray, o);
  43.     no_int = intersect_rawbox(b->p1, b->p2, &localray, d);
  44.     } else {
  45.     no_int = intersect_rawbox(b->p1, b->p2, r, d);
  46.     }
  47.  
  48.     *isinside = (no_int % 2) ^ o->inverted;
  49.  
  50.     if (!no_int)
  51.     return FALSE;
  52.  
  53.     q_ent.t = d[0];
  54.     q_ent.obj = o;
  55.     q_ent.entering = !(*isinside);
  56.     add_to_queue(q, q_ent);
  57.  
  58.     if (no_int > 1 && flags & CHKALL) {
  59.     q_ent.t = d[1];
  60.     q_ent.obj = o;
  61.     q_ent.entering = (*isinside);
  62.     add_to_queue(q, q_ent);
  63.     }
  64.     return TRUE;
  65. }
  66.  
  67. PRIVATE void
  68. precompute_box(object *o)
  69. {
  70.     struct box_data *b = o->data.box;
  71.     vector          p1,
  72.                     p2;
  73.     matrix          m;
  74.  
  75.  
  76.     /* make sure the points are in the right order */
  77.     p1.x = MIN(b->p1.x, b->p2.x);
  78.     p2.x = MAX(b->p1.x, b->p2.x);
  79.     p1.y = MIN(b->p1.y, b->p2.y);
  80.     p2.y = MAX(b->p1.y, b->p2.y);
  81.     p1.z = MIN(b->p1.z, b->p2.z);
  82.     p2.z = MAX(b->p1.z, b->p2.z);
  83.  
  84.     b->p1 = p1;
  85.     b->p2 = p2;
  86.     if (o->inv_trans)
  87.     copy_matrix(m, *o->inv_trans);
  88.     else
  89.     unit_matrix(m);
  90.     do_box_bound(&o->bmin, &o->bmax, m, p1, p2);
  91.     my_methods.howmuch++;
  92.     global_stats.prims++;
  93. }
  94.  
  95. PUBLIC void
  96. do_box_bound(vector *bmin, vector *bmax, matrix inv_trans, vector p1, vector p2)
  97. {
  98.     matrix          trans;
  99.     vector          point;
  100.  
  101.     invert_trans(trans, inv_trans);
  102.  
  103.     p1 = mvproduct(trans, p1);
  104.     p2 = mvproduct(trans, p2);
  105.  
  106.     setvector(point, p1.x, p1.y, p1.z);
  107.     update_min_and_max(bmin, bmax, point);
  108.     setvector(point, p2.x, p1.y, p1.z);
  109.     update_min_and_max(bmin, bmax, point);
  110.     setvector(point, p1.x, p2.y, p1.z);
  111.     update_min_and_max(bmin, bmax, point);
  112.     setvector(point, p1.x, p1.y, p2.z);
  113.     update_min_and_max(bmin, bmax, point);
  114.     setvector(point, p2.x, p2.y, p1.z);
  115.     update_min_and_max(bmin, bmax, point);
  116.     setvector(point, p1.x, p2.y, p2.z);
  117.     update_min_and_max(bmin, bmax, point);
  118.     setvector(point, p2.x, p1.y, p2.z);
  119.     update_min_and_max(bmin, bmax, point);
  120.     setvector(point, p2.x, p2.y, p2.z);
  121. }
  122.  
  123. /*
  124.  * intersect a ray with a box which has unit_matrix for inv_trans. It
  125.  * could be used for automatic bounding boxes in the future
  126.  * 
  127.  * after having looked to the PoV sources again, I have found that they
  128.  * essentially use the same routine.  The difference is:  their routines
  129.  * are very optimized, and mine are not. The ABS() calls take up too much
  130.  * time. (I think)
  131.  */
  132.  
  133. PUBLIC int
  134. intersect_rawbox(vector p1, vector p2, struct ray *r, double *params)
  135. {
  136.     double          t1,
  137.                     t2,
  138.                     tmin,
  139.                     tmax,
  140.                     tmp;
  141.  
  142.     tmin = -INFTY;
  143.     tmax = INFTY;
  144.  
  145.     my_methods.test++;
  146.  
  147.     /* intersect YZ-planes */
  148.     if (!ISZERO(r->dir.x)) {    /* it's not parallel to YZ plane */
  149.     /*
  150.      * calculate two plane intersection, optimised version We are
  151.      * still using the formula (x,n) = mov, but since n is (1,0,0),
  152.      * calculations can be greatly simplified.
  153.      */
  154.  
  155.     t1 = (p1.x - r->pos.x) / r->dir.x;
  156.     t2 = (p2.x - r->pos.x) / r->dir.x;
  157.     if (t1 > t2) {        /* swap t1 and t2 if t1 is not the
  158.                  * minimum. */
  159.         tmp = t1;
  160.         t1 = t2;
  161.         t2 = tmp;
  162.     }
  163.     /* intersect previous domain with current */
  164.     tmin = MAX(tmin, t1);
  165.     tmax = MIN(tmax, t2);
  166.  
  167.     if (tmax < tolerance)
  168.         return 0;
  169.     } else if (p1.x > r->pos.x || r->pos.x > p2.x)
  170.     return 0;
  171.  
  172.     /* y part */
  173.     if (!ISZERO(r->dir.y)) {
  174.     t1 = (p1.y - r->pos.y) / r->dir.y;
  175.     t2 = (p2.y - r->pos.y) / r->dir.y;
  176.  
  177.     if (t1 > t2) {        /* swap? */
  178.         tmp = t1;
  179.         t1 = t2;
  180.         t2 = tmp;
  181.     }
  182.     /*
  183.      * [t1, t2] is the domain for the intersection parameter t, ie if
  184.      * x = p +t*d is inside the box, then t in [t1,t2] holds. but t
  185.      * also has to be in [tmin,tmax], so intersect these two sets.
  186.      */
  187.  
  188.     tmin = MAX(tmin, t1);
  189.     tmax = MIN(tmax, t2);
  190.     if (tmax < tolerance ||    /* the intersection will be behind us. */
  191.         tmax < tmin)    /* the domain is empty */
  192.         return 0;
  193.     } else if (p1.y > r->pos.y || r->pos.y > p2.y)
  194.     return 0;
  195.  
  196.     /* z part. It works in the same way as the X and Y parts do. */
  197.     if (!ISZERO(r->dir.z)) {
  198.     t1 = (p1.z - r->pos.z) / r->dir.z;
  199.     t2 = (p2.z - r->pos.z) / r->dir.z;
  200.  
  201.     if (t1 > t2) {        /* swap */
  202.         tmp = t1;
  203.         t1 = t2;
  204.         t2 = tmp;
  205.     }
  206.     tmin = MAX(tmin, t1);
  207.     tmax = MIN(tmax, t2);
  208.  
  209.     if (tmax < tolerance || tmax < tmin)
  210.         return 0;
  211.     } else if (p1.z > r->pos.z || r->pos.z > p2.z)
  212.     return 0;
  213.  
  214.  
  215.     /*
  216.      * OK. We've checked wether the ray r(t) is inside the box: the
  217.      * solutions set for t is not empty. both tmin and tmax are
  218.      * intersection points of the ray with the box boundary (the 6
  219.      * rectangles) Now choose the least positive of the two intersection
  220.      * points, and return it.
  221.      */
  222.  
  223.  
  224.     my_methods.hit++;
  225.     if (tmin < tolerance) {
  226.     *params = tmax;
  227.     return 1;
  228.     } else {
  229.     *params++ = tmin;
  230.     *params = tmax;
  231.     return 2;
  232.     }
  233. }
  234.  
  235. PRIVATE bool
  236. inside_box(object *o, vector org)
  237. {
  238.     struct box_data *b = o->data.box;
  239.  
  240.     if (o->inv_trans)
  241.     org = mvproduct(*o->inv_trans, org);
  242.  
  243.     /* no fudges here! */
  244.     if (org.x < b->p2.x && org.y < b->p2.y && org.z < b->p2.z &&
  245.     org.x > b->p1.x && org.y > b->p1.y && org.z > b->p1.z)
  246.     return !o->inverted;
  247.     else
  248.     return o->inverted;
  249. }
  250.  
  251. PRIVATE vector
  252. box_normal(struct intersect i, vector x)
  253. {
  254.     vector          n;
  255.     object         *o = i.q_ent.obj;
  256.     struct box_data *b;
  257.  
  258.     b = o->data.box;
  259.  
  260.     setvector(n, 0, 0, 0);
  261.  
  262.     if (o->inv_trans)
  263.     x = mvproduct(*o->inv_trans, x);
  264.  
  265.     if (ISZERO(x.x - b->p1.x) || ISZERO(x.x - b->p2.x)) {
  266.     n.x = 1.0;
  267.     } else if (ISZERO(x.y - b->p1.y) || ISZERO(x.y - b->p2.y)) {
  268.     n.y = 1.0;
  269.     } else if (ISZERO(x.z - b->p1.z) || ISZERO(x.z - b->p2.z)) {
  270.     n.z = 1.0;
  271.     } else
  272.     assert(FALSE);
  273.  
  274.     if (o->inv_trans)
  275.     n = transform_normal(*o->inv_trans, n);
  276.  
  277.     norm(n, n);
  278.  
  279.     return n;
  280. }
  281.  
  282. PRIVATE void
  283. init_box(struct box_data *b)
  284. {
  285.     setvector(b->p2, 1, 1, 1);
  286.     setvector(b->p2, -1, -1, -1);
  287. }
  288.  
  289. PRIVATE struct box_data *
  290. get_new_box(void)
  291. {
  292.     struct box_data *b;
  293.  
  294.     b = ALLOC(struct box_data);
  295.  
  296.     CHECK_MEM(b, my_methods.name);
  297.     init_box(b);
  298.  
  299.     return b;
  300. }
  301.  
  302. PRIVATE void
  303. free_box(object *o)
  304. {
  305.     struct box_data *p = o->data.box;
  306.  
  307.     free((void *) p);
  308.  
  309.     o->type = NOSHAPE;
  310. }
  311.  
  312. PRIVATE void
  313. scale_box(object *o, vector s)
  314. {
  315.     struct box_data *b = o->data.box;
  316.  
  317.     if (o->inv_trans) {
  318.     generic_scale_object(o, s);
  319.     } else {
  320.     vcproduct(b->p1, s, b->p1);
  321.     vcproduct(b->p2, s, b->p2);
  322.     }
  323. }
  324.  
  325. PRIVATE void
  326. rotate_box(object *o, matrix rotmat)
  327. {
  328.     generic_rotate_object(o, rotmat);
  329. }
  330.  
  331. PRIVATE void
  332. copy_box(object *dst, object *src)
  333. {
  334.     struct box_data *d;
  335.  
  336.     assert(dst != NULL && src != NULL);
  337.  
  338.     if (dst->type != BOX)
  339.     d = dst->data.box = get_new_box();
  340.  
  341.     *d = *src->data.box;
  342.     dst->type = src->type;
  343. }
  344.  
  345. PRIVATE void
  346. translate_box(object *o, vector t)
  347. {
  348.     struct box_data *b = o->data.box;
  349.  
  350.     if (o->inv_trans) {
  351.     generic_translate_object(o, t);
  352.     } else {
  353.     vadd(b->p1, b->p1, t);
  354.     vadd(b->p2, b->p2, t);
  355.     }
  356. }
  357.  
  358. PRIVATE void
  359. print_box(object *o)
  360. {
  361. #ifdef DEBUG
  362.     struct box_data *b = o->data.box;
  363.  
  364.     print_v("p1", b->p1);
  365.     print_v("p2", b->p2);
  366. #endif
  367. }
  368.  
  369. PRIVATE struct methods my_methods =
  370. {
  371.     all_box_intersections,
  372.     box_normal,
  373.     copy_box,
  374.     inside_box,
  375.     rotate_box,
  376.     translate_box,
  377.     scale_box,
  378.     free_box,
  379.     print_box,
  380.     precompute_box,
  381.     "box",
  382. };
  383.  
  384.  
  385. PUBLIC object  *
  386. get_new_box_object(void)
  387. {
  388.     object         *o;
  389.  
  390.     o = get_new_object();
  391.     o->data.box = get_new_box();
  392.     o->methods = &my_methods;
  393.     o->type = BOX;
  394.  
  395.     return o;
  396. }
  397.