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

  1. /*
  2.  * csg.c -- this implements CSG
  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.  
  21. #include "ray.h"
  22. #include "proto.h"
  23. #include "extern.h"
  24.  
  25. extern struct methods CSGinter_methods;
  26. extern struct methods CSGunion_methods;
  27.  
  28. /*
  29.  * intersect a CSG union.
  30.  * 
  31.  * Actually I could use the same code to do CSG intersections, since
  32.  * 
  33.  * intersection { { A inverse } { B inverse } inverse }
  34.  * 
  35.  * is equivalent to
  36.  * 
  37.  * union { A B }
  38.  * 
  39.  * My algorithm relies on the Jordan curve theorem (Gee, that sounds great...
  40.  * ) Well kindof... Jordan curves have to divide space into a *bounded*
  41.  * and unbouded set.;
  42.  * 
  43.  * Anyway, this works because each crossed boundary means from
  44.  * inside->outside or outside->inside, thus making the number of shapes
  45.  * we're in very easy to keep track of.
  46.  */
  47.  
  48. PRIVATE bool
  49. all_CSGunion_intersections(dqueue * dq, object *o, struct ray *r,
  50.                int flags, bool *isinside)
  51. {
  52.     object         *p,
  53.                    *CSG;
  54.     int             encl_shapes,/* shapes we're inside of. */
  55.                     total;
  56.     bool            b,
  57.                     gotcha,
  58.                     chkall,
  59.                     loc_ins;    /* found an intersection? */
  60.     dqueue         *CSGq,
  61.                    *q;
  62.  
  63.  
  64.     CSGunion_methods.test++;
  65.     chkall = flags & CHKALL;
  66.     CSG = o->data.CSG;
  67.     encl_shapes = 0;
  68.     total = 0;
  69.     CSGq = get_new_queue();    /* set up a new queue for results of this
  70.                  * CSG union. */
  71.     gotcha = FALSE;
  72.  
  73.     /* count the shapes, and intersect them. */
  74.     for (p = CSG; p != NULL; p = p->next) {
  75.     total++;
  76.     p->methods->all_intersections_method(CSGq, p, r, CHKINSIDE | CHKALL, &b);
  77.     if (b)
  78.         encl_shapes++;
  79.     }
  80.  
  81.     if (!encl_shapes)
  82.     loc_ins = *isinside = FALSE;
  83.     else
  84.     loc_ins = *isinside = TRUE;
  85.  
  86.  
  87.     /*
  88.      * encl_shapes now holds the number of shapes we're in
  89.      * 
  90.      * during the following loop, it holds the number of shapes we're in,
  91.      * after we've passed intersection q
  92.      * 
  93.      * During the loop, loc_ins is wether we are inside or outside a shape.
  94.      * Of course, isinside does not have to be init'ed, since it is
  95.      * delivered with the parameters. Note that for every intersection of
  96.      * the CSG we're looking in to, isinside is flipped.
  97.      */
  98.  
  99.     for (q = CSGq; q != NULL && (chkall || !gotcha); q = q->next) {
  100.     if (q->obj == NULL)    /* some kind of void intersection.. Hmmm,
  101.                  * not very elegant. */
  102.         continue;
  103.  
  104.     if (q->entering) {    /* going into a shape */
  105.         ++encl_shapes;
  106.         assert(encl_shapes <= total);    /* we can't be in more
  107.                          * shapes than there are
  108.                          * shapes to be in (huh
  109.                          * :-) */
  110.  
  111.  
  112.         if (encl_shapes == 1) {    /* from outside CSG -> inside CSG,
  113.                      * this is an intersection */
  114.         loc_ins = !loc_ins;
  115.         q->entering = loc_ins;
  116.         add_to_queue(dq, *q);
  117.         gotcha = TRUE;
  118.         }
  119.     } else {
  120.         /* exiting a shape */
  121.         --encl_shapes;
  122.         assert(encl_shapes >= 0);
  123.  
  124.         if (encl_shapes == 0) {    /* just left the CSG structure */
  125.         loc_ins = !loc_ins;
  126.         q->entering = loc_ins;
  127.         add_to_queue(dq, *q);
  128.         gotcha = TRUE;
  129.         }
  130.     }
  131.  
  132.     }
  133.  
  134.     if (gotcha)
  135.     CSGunion_methods.hit++;
  136.  
  137.     free_queue(CSGq);
  138.     return gotcha;
  139. }
  140.  
  141. PRIVATE bool
  142. all_CSGinter_intersections(dqueue * dq, object *o, struct ray *r,
  143.                int flags, bool *isinside)
  144. {
  145.     object         *p,
  146.                    *CSG;
  147.     int             encl_shapes,/* shapes we're inside of. */
  148.                     total;
  149.     bool            inside_this,
  150.                     gotcha,
  151.                     chkall,
  152.                     loc_ins;    /* found an intersection? */
  153.     dqueue         *CSGq,
  154.                    *q;
  155.  
  156.     CSGinter_methods.test++;
  157.     CSG = o->data.CSG;
  158.     gotcha = FALSE;
  159.     chkall = flags & CHKALL;
  160.  
  161.     /* count the shapes, and intersect them. */
  162.     encl_shapes = 0;
  163.     total = 0;
  164.     CSGq = get_new_queue();    /* set up a new queue for results of this
  165.                  * CSG union. */
  166.     for (p = CSG; p != NULL; p = p->next) {
  167.     total++;
  168.     p->methods->all_intersections_method(CSGq, p, r, CHKINSIDE | CHKALL, &inside_this);
  169.     if (inside_this)
  170.         encl_shapes++;
  171.     }
  172.  
  173.     if (encl_shapes < total)
  174.     *isinside = loc_ins = FALSE ^ o->inverted;
  175.     else
  176.     *isinside = loc_ins = TRUE ^ o->inverted;
  177.  
  178.     /*
  179.      * encl_shapes now holds the number of shapes we're in
  180.      * 
  181.      * during the following loop, it holds the number of shapes we're in,
  182.      * after we've passed intersection q->i
  183.      * 
  184.      * During the loop, isinside is wether we are inside or outside a shape.
  185.      * Note that for every intersection of the CSG we're looking in to,
  186.      * isinside is flipped.
  187.      */
  188.  
  189.     for (q = CSGq;
  190.      q != NULL && (chkall || !gotcha);
  191.      q = q->next) {
  192.     if (q->obj == NULL)    /* some kind of void intersection.. Hmmm,
  193.                  * not very elegant. */
  194.         continue;
  195.  
  196.     if (q->entering) {    /* going into a shape */
  197.         ++encl_shapes;
  198.         assert(encl_shapes <= total);    /* we can't be in more
  199.                          * shapes than there are
  200.                          * shapes to be in (huh
  201.                          * :-) */
  202.  
  203.         if (encl_shapes == total) {    /* from outside CSG -> inside CSG,
  204.                      * this is an intersection */
  205.         loc_ins = !loc_ins;
  206.         q->entering = loc_ins;
  207.         add_to_queue(dq, *q);
  208.         gotcha = TRUE;
  209.         }
  210.     } else {
  211.         if (encl_shapes == total) {    /* just left the CSG structure */
  212.         loc_ins = !loc_ins;
  213.         q->entering = loc_ins;
  214.         add_to_queue(dq, *q);
  215.         gotcha = TRUE;
  216.         }
  217.         /* exiting a shape */
  218.         --encl_shapes;
  219.         assert(encl_shapes >= 0);
  220.     }
  221.     }
  222.  
  223.     /* throw away the queue. It's needed anymore. */
  224.     free_queue(CSGq);
  225.     if (gotcha)
  226.     CSGinter_methods.hit++;
  227.  
  228.     return gotcha;
  229. }
  230.  
  231. /* inside?  True if we're at least inside one of the components */
  232. PRIVATE bool
  233. inside_CSGunion(object *c, vector x)
  234. {
  235.     object         *p;
  236.  
  237.     for (p = c->data.CSG; p != NULL; p = p->next)
  238.     if (p->methods->inside_method(p, x))
  239.         return !c->inverted;
  240.     return c->inverted;
  241. }
  242.  
  243.  
  244. /* inside of  CSGinter if we're inside all parts of CSG */
  245. PRIVATE bool
  246. inside_CSGinter(object *c, vector x)
  247. {
  248.     object         *p;
  249.  
  250.     for (p = c->data.CSG; p != NULL; p = p->next)
  251.     if (!p->methods->inside_method(p, x))
  252.         return c->inverted;
  253.     return !c->inverted;
  254. }
  255.  
  256. PRIVATE void
  257. print_CSG(object *p)
  258. {
  259. #ifdef DEBUG
  260.     printf(" {\n");
  261.     print_object_list(p->data.CSG);
  262.     printf("} \n");
  263. #endif
  264. }
  265.  
  266.  
  267. /*
  268.  * QUESTION: from what file were the routines below copied? (u gaat door
  269.  * voor de koelkast!)
  270.  */
  271.  
  272. /* add an object to the CSG c */
  273. PUBLIC void
  274. add_to_CSG(object *c, object *o)
  275. {
  276.     object         *tmp;
  277.  
  278.     tmp = c->data.CSG;
  279.     c->data.CSG = o;
  280.     o->next = tmp;
  281.     o->daddy = c;
  282. }
  283.  
  284. /* this is getting boring... */
  285. PRIVATE void
  286. copy_CSG(object *dst, object *src)
  287. {
  288.     object         *p,
  289.                    *new;
  290.  
  291.     dst->type = src->type;
  292.     dst->data.CSG = NULL;
  293.     for (p = src->data.CSG; p != NULL; p = p->next) {
  294.     new = get_new_object();
  295.     copy_object(new, p);
  296.     add_to_CSG(dst, new);
  297.     }
  298. }
  299.  
  300. /* standard */
  301. PRIVATE void
  302. translate_CSG(object *c, vector t)
  303. {
  304.     translate_object_list(c->data.CSG, t);
  305. }
  306.  
  307. /* hooooeeewaahhh, Geez, why do I write these comments? */
  308. PRIVATE void
  309. rotate_CSG(object *c, matrix rotmat)
  310. {
  311.  
  312.     rotate_object_list(c->data.CSG, rotmat);
  313. }
  314.  
  315. /*
  316.  * I guess .. because somebody will read them, some day (Hello, is there
  317.  * somebody out there?
  318.  * 
  319.  * and another free_XXX() (en wat hebben ze gewonnen, Pierre, als ze goed
  320.  * raden waar dit voor is ?
  321.  */
  322. PRIVATE void
  323. free_CSG(object *c)
  324. {
  325.     free_object_list(c->data.CSG);
  326.     c->type = NOSHAPE;
  327. }
  328.  
  329. /* 3X raden (Yes, you folks out there, I'm now commenting in Dutch! */
  330. PRIVATE void
  331. scale_CSG(object *c, vector s)
  332. {
  333.     scale_object_list(c->data.CSG, s);
  334. }
  335.  
  336. PRIVATE vector
  337. CSG_normal(struct intersect i, vector loc)
  338. {
  339.     assert(FALSE);
  340. }
  341.  
  342. PRIVATE void
  343. precompute_CSG(object *o)
  344. {
  345.     precompute_object_list(o->data.CSG);
  346.  
  347.     global_stats.nonprims++;
  348.     if (o->type == CSGINTER)
  349.     CSGinter_methods.howmuch++;
  350.     else
  351.     CSGunion_methods.howmuch++;
  352. }
  353.  
  354.  
  355. PRIVATE struct methods CSGinter_methods =
  356. {
  357.     all_CSGinter_intersections,
  358.     CSG_normal,
  359.     copy_CSG,
  360.     inside_CSGinter,
  361.     rotate_CSG,
  362.     translate_CSG,
  363.     scale_CSG,
  364.     free_CSG,
  365.     print_CSG,
  366.     precompute_CSG,
  367.     "intersection"
  368. };
  369.  
  370. PRIVATE struct methods CSGunion_methods =
  371. {
  372.     all_CSGunion_intersections,
  373.     CSG_normal,
  374.     copy_CSG,
  375.     inside_CSGunion,
  376.     rotate_CSG,
  377.     translate_CSG,
  378.     scale_CSG,
  379.     free_CSG,
  380.     print_CSG,
  381.     precompute_CSG,
  382.     "union",
  383. };
  384.  
  385. PUBLIC object  *
  386. get_new_CSGinter_object(void)
  387. {
  388.     object         *o;
  389.  
  390.     o = get_new_object();
  391.     o->methods = &CSGinter_methods;
  392.     o->type = CSGINTER;
  393.     o->data.CSG = NULL;
  394.  
  395.  
  396.     return o;
  397. }
  398.  
  399. PUBLIC object  *
  400. get_new_CSGunion_object(void)
  401. {
  402.     object         *o;
  403.  
  404.     o = get_new_object();
  405.     o->methods = &CSGunion_methods;
  406.     o->data.CSG = NULL;
  407.     o->type = CSGUNION;
  408.  
  409.  
  410.     return o;
  411. }
  412.