| 1 | #ifndef lint | 
| 2 | static const char       RCSid[] = "$Id: m_clip.c,v 2.13 2019/05/04 03:14:04 greg Exp $"; | 
| 3 | #endif | 
| 4 | /* | 
| 5 | *  m_clip.c - routine for clipped (cut) objects. | 
| 6 | */ | 
| 7 |  | 
| 8 | #include "copyright.h" | 
| 9 |  | 
| 10 | #include  "ray.h" | 
| 11 | #include  "rtotypes.h" | 
| 12 |  | 
| 13 | /* | 
| 14 | *  Clipping objects permit holes and sections to be taken out | 
| 15 | *  of other objects. | 
| 16 | * | 
| 17 | *  The argument is the clipped materials; | 
| 18 | *  the first is used to shade upon exit. | 
| 19 | * | 
| 20 | *  In the simple case of the first argument being "void", we | 
| 21 | *  just add or subtract (depending on whether we're coming or going) | 
| 22 | *  the list of modifiers to the ray's "newcset", which will then | 
| 23 | *  take over for "clipset" on penetration.  Any surface modifier | 
| 24 | *  names found in "clipset" will be treated as invisible in raycont(). | 
| 25 | * | 
| 26 | *  In the more complicated case of a non-void material as the | 
| 27 | *  first argument, we have to backtrack up the ray tree to count | 
| 28 | *  the number of times we've penetrated the front side of one of | 
| 29 | *  the surfaces we care about.  This relies on outward-facing | 
| 30 | *  surface normals and closed objects, so is somewhat error-prone. | 
| 31 | */ | 
| 32 |  | 
| 33 |  | 
| 34 | int | 
| 35 | m_clip(                 /* clip objects from ray */ | 
| 36 | OBJREC  *m, | 
| 37 | RAY  *r | 
| 38 | ) | 
| 39 | { | 
| 40 | OBJECT  cset[MAXSET+1], *modset; | 
| 41 | OBJECT  obj, mod; | 
| 42 | int  entering; | 
| 43 | int  i; | 
| 44 |  | 
| 45 | obj = objndx(m); | 
| 46 | if ((modset = (OBJECT *)m->os) == NULL) { | 
| 47 | if (m->oargs.nsargs < 1 || m->oargs.nsargs > MAXSET) | 
| 48 | objerror(m, USER, "bad # arguments"); | 
| 49 | modset = (OBJECT *)malloc((m->oargs.nsargs+1)*sizeof(OBJECT)); | 
| 50 | if (modset == NULL) | 
| 51 | error(SYSTEM, "out of memory in m_clip"); | 
| 52 | modset[0] = 0; | 
| 53 | for (i = 0; i < m->oargs.nsargs; i++) { | 
| 54 | if (!strcmp(m->oargs.sarg[i], VOIDID)) | 
| 55 | continue; | 
| 56 | if ((mod = lastmod(obj, m->oargs.sarg[i])) == OVOID) { | 
| 57 | sprintf(errmsg, "unknown modifier \"%s\"", | 
| 58 | m->oargs.sarg[i]); | 
| 59 | objerror(m, WARNING, errmsg); | 
| 60 | continue; | 
| 61 | } | 
| 62 | if (inset(modset, mod)) { | 
| 63 | objerror(m, WARNING, "duplicate modifier"); | 
| 64 | continue; | 
| 65 | } | 
| 66 | insertelem(modset, mod); | 
| 67 | } | 
| 68 | m->os = (char *)modset; | 
| 69 | } | 
| 70 | if (r == NULL) | 
| 71 | return(0);                      /* just initializing */ | 
| 72 | if (r->clipset != NULL) | 
| 73 | setcopy(cset, r->clipset); | 
| 74 | else | 
| 75 | cset[0] = 0; | 
| 76 |  | 
| 77 | entering = (r->rod > 0.0);              /* entering clipped region? */ | 
| 78 |  | 
| 79 | for (i = modset[0]; i > 0; i--) | 
| 80 | if (entering) { | 
| 81 | if (!inset(cset, modset[i])) { | 
| 82 | if (cset[0] >= MAXSET) | 
| 83 | error(INTERNAL, "set overflow in m_clip"); | 
| 84 | insertelem(cset, modset[i]); | 
| 85 | } | 
| 86 | } else if (inset(cset, modset[i])) | 
| 87 | deletelem(cset, modset[i]); | 
| 88 |  | 
| 89 | /* compute ray value */ | 
| 90 | r->newcset = cset; | 
| 91 | if (strcmp(m->oargs.sarg[0], VOIDID)) { | 
| 92 | int  inside = 0; | 
| 93 | const RAY  *rp; | 
| 94 | /* check for penetration */ | 
| 95 | for (rp = r; rp->parent != NULL; rp = rp->parent) | 
| 96 | if (!(rp->rtype & RAYREFL) & (rp->parent->ro != NULL) | 
| 97 | && inset(modset, rp->parent->ro->omod)) { | 
| 98 | if (rp->parent->rod > 0.0) | 
| 99 | inside++; | 
| 100 | else | 
| 101 | inside--; | 
| 102 | } | 
| 103 | if (inside > 0) {       /* we just hit the object */ | 
| 104 | flipsurface(r); | 
| 105 | return(rayshade(r, lastmod(obj, m->oargs.sarg[0]))); | 
| 106 | } | 
| 107 | } | 
| 108 | raytrans(r);                    /* else transfer ray */ | 
| 109 | return(1); | 
| 110 | } |