int BasisHitShadow()

in layer1/Basis.cpp [2351:2851]


int BasisHitShadow(BasisCallRec * BC)
{
  const float _0 = 0.0F;
  const float _1 = 1.0F;
  float oppSq, dist = _0, tri1, tri2;
  float sph[3], vt[3];
  int h, *ip;
  int a, b, c;
  int *elist, local_iflag = false;
  float minusZ[3] = { 0.0F, 0.0F, -1.0F };
  /* local copies (eliminate these extra copies later on) */

  CBasis *BI = BC->Basis;
  RayInfo *r = BC->rr;

  if(MapInsideXY(BI->Map, r->base, &a, &b, &c)) {
    int minIndex = -1;
    int v2p;
    int i, ii;
    int *xxtmp;

    int n_vert = BI->NVertex, n_eElem = BI->Map->NEElem;
    int except1 = BC->except1;
    int except2 = BC->except2;
    const int *vert2prim = BC->vert2prim;
    const int trans_shadows = BC->trans_shadows;
    const int nearest_shadow = BC->nearest_shadow;
    const float BasisFudge0 = BC->fudge0;
    const float BasisFudge1 = BC->fudge1;
    const int label_shadow_mode = BC->label_shadow_mode;
    MapCache *cache = &BC->cache;
    int *cache_cache = cache->Cache;
    int *cache_CacheLink = cache->CacheLink;
    CPrimitive *BC_prim = BC->prim;

    float r_tri1 = _0, r_tri2 = _0, r_dist;    /* zero inits to suppress compiler warnings */
    float r_sphere0 = _0, r_sphere1 = _0, r_sphere2 = _0;
    float r_trans = _0;
    CPrimitive *r_prim = NULL;

    /* assumption: always heading in the negative Z direction with our vector... */
    vt[0] = r->base[0];
    vt[1] = r->base[1];

    if(except1 >= 0)
      except1 = vert2prim[except1];
    if(except2 >= 0)
      except2 = vert2prim[except2];

    r_trans = _1;
    r_dist = MAXFLOAT;

    xxtmp = BI->Map->EHead + (a * BI->Map->D1D2) + (b * BI->Map->Dim[2]) + c;

    MapCacheReset(cache);

    elist = BI->Map->EList;

    while(c >= MapBorder) {
      h = *xxtmp;
      if((h > 0) && (h < n_eElem)) {
        int do_loop;
        ip = elist + h;
        i = *(ip++);
        do_loop = ((i >= 0) && (i < n_vert));
        while(do_loop) {
          ii = *(ip++);
          v2p = vert2prim[i];
          do_loop = ((ii >= 0) && (ii < n_vert));
          if((v2p != except1) && (v2p != except2) && !MapCached(cache, v2p)) {
            CPrimitive *prm = BC_prim + v2p;
            int prm_type;

            /*MapCache(cache,v2p); */
            cache_cache[v2p] = 1;
            prm_type = prm->type;
            cache_CacheLink[v2p] = cache->CacheStart;
            cache->CacheStart = v2p;

            switch (prm_type) {
            case cPrimCharacter:       /* will need special handling for character shadows */
              if(label_shadow_mode & 0x2) {     /* if labels case shadows... */
                float *pre = BI->Precomp + BI->Vert2Normal[i] * 3;

                if(pre[6]) {
                  float *vert0 = BI->Vertex + prm->vert * 3;

                  float tvec0 = vt[0] - vert0[0];
                  float tvec1 = vt[1] - vert0[1];

                  tri1 = (tvec0 * pre[4] - tvec1 * pre[3]) * pre[7];
                  tri2 = -(tvec0 * pre[1] - tvec1 * pre[0]) * pre[7];

                  if(!((tri1 < BasisFudge0) ||
                       (tri2 < BasisFudge0) ||
                       (tri1 > BasisFudge1) || ((tri1 + tri2) > BasisFudge1))) {
                    dist = (r->base[2] - (tri1 * pre[2]) - (tri2 * pre[5]) - vert0[2]);

                    {
                      float fc[3];
                      float trans;

                      r->tri1 = tri1;
                      r->tri2 = tri2;
                      r->dist = dist;
                      r->prim = prm;

                      {
                        float w2;
                        w2 = _1 - (r->tri1 + r->tri2);

                        fc[0] =
                          (prm->c2[0] * r->tri1) + (prm->c3[0] * r->tri2) +
                          (prm->c1[0] * w2);
                        fc[1] =
                          (prm->c2[1] * r->tri1) + (prm->c3[1] * r->tri2) +
                          (prm->c1[1] * w2);
                        fc[2] =
                          (prm->c2[2] * r->tri1) + (prm->c3[2] * r->tri2) +
                          (prm->c1[2] * w2);
                      }

                      trans = CharacterInterpolate(BI->G, prm->char_id, fc);

                      if(trans == _0) { /* opaque? return immed. */
                        if(dist > -kR_SMALL4) {
                          if(nearest_shadow) {
                            if(dist < r_dist) {
                              minIndex = prm->vert;
                              r_tri1 = tri1;
                              r_tri2 = tri2;
                              r_dist = dist;
                              r_trans = (r->trans = trans);
                            }
                          } else {
                            r->prim = prm;
                            r->trans = _0;
                            r->dist = dist;
                            return (1);
                          }
                        }
                      } else if(trans_shadows) {
                        if((dist > -kR_SMALL4) &&
                           ((r_trans > trans) ||
                            (nearest_shadow && (dist < r_dist) && (r_trans >= trans)))) {
                          minIndex = prm->vert;
                          r_tri1 = tri1;
                          r_tri2 = tri2;
                          r_dist = dist;
                          r_trans = (r->trans = trans);
                        }
                      }
                    }
                  }
                }
              }
              break;

            case cPrimTriangle:
              {
                float *pre = BI->Precomp + BI->Vert2Normal[i] * 3;

                if(pre[6]) {
                  float *vert0 = BI->Vertex + prm->vert * 3;

                  float tvec0 = vt[0] - vert0[0];
                  float tvec1 = vt[1] - vert0[1];

                  tri1 = (tvec0 * pre[4] - tvec1 * pre[3]) * pre[7];
                  tri2 = -(tvec0 * pre[1] - tvec1 * pre[0]) * pre[7];
                  if(!((tri1 < BasisFudge0) ||
                       (tri2 < BasisFudge0) ||
                       (tri1 > BasisFudge1) || ((tri1 + tri2) > BasisFudge1))) {
                    float *tr = prm->tr;
                    float trans = _0;

                    dist = (r->base[2] - (tri1 * pre[2]) - (tri2 * pre[5]) - vert0[2]);

                    if(prm->trans != _0) {
                      trans =
                        (tr[1] * tri1) + (tr[2] * tri2) + (tr[0] * (_1 - (tri1 + tri2)));
                    }

                    if(trans == _0) {
                      if(dist > -kR_SMALL4) {
                        if(nearest_shadow) {    /* do we need the nearest shadow? */
                          if(dist < r_dist) {
                            minIndex = prm->vert;
                            r_tri1 = tri1;
                            r_tri2 = tri2;
                            r_dist = dist;
                            r_trans = (r->trans = trans);
                          }
                        } else {
                          r->prim = prm;
                          r->trans = _0;
                          r->dist = dist;
                          return (1);
                        }
                      }
                    } else if(trans_shadows) {
                      if((dist > -kR_SMALL4) &&
                         ((r_trans > trans) ||
                          (nearest_shadow && (dist < r_dist) && (r_trans >= trans)))) {
                        minIndex = prm->vert;
                        r_tri1 = tri1;
                        r_tri2 = tri2;
                        r_dist = dist;
                        r_trans = (r->trans = trans);
                      }
                    }
                  }
                }
              }
              break;

            case cPrimSphere:

              oppSq = ZLineClipPoint(r->base, BI->Vertex + i * 3, &dist, BI->Radius[i]);
              if(oppSq <= BI->Radius2[i]) {
                dist = (float) (sqrt1f(dist) - sqrt1f((BI->Radius2[i] - oppSq)));

                if(prm->trans == _0) {
                  if(dist > -kR_SMALL4) {
                    if(nearest_shadow) {
                      if(dist < r_dist) {
                        minIndex = prm->vert;
                        r_dist = dist;
                        r_trans = (r->trans = prm->trans);
                      }
                    } else {
                      r->prim = prm;
                      r->trans = prm->trans;
                      r->dist = dist;
                      return (1);
                    }
                  }
                } else if(trans_shadows) {
                  if((dist > -kR_SMALL4) &&
                     ((r_trans > prm->trans) ||
                      (nearest_shadow && (dist < r_dist) && (r_trans >= prm->trans)))) {
                    minIndex = prm->vert;
                    r_dist = dist;
                    r_trans = (r->trans = prm->trans);
                  }
                }
              }
              break;

            case cPrimEllipsoid:

              oppSq =
                ZLineClipPointNoZCheck(r->base, BI->Vertex + i * 3, &dist, BI->Radius[i]);
              if(oppSq <= BI->Radius2[i]) {
                dist = (float) (sqrt1f(dist) - sqrt1f((BI->Radius2[i] - oppSq)));

                if((dist < r_dist) || (trans_shadows && (r_trans != _0))) {
                  float *n1 = BI->Normal + BI->Vert2Normal[i] * 3;
                  if(LineClipEllipsoidPoint(r->base, minusZ,
                                            BI->Vertex + i * 3, &dist,
                                            BI->Radius[i], BI->Radius2[i],
                                            prm->n0, n1, n1 + 3, n1 + 6)) {

                    if(prm->trans == _0) {
                      if(dist > -kR_SMALL4) {
                        if(nearest_shadow) {
                          if(dist < r_dist) {
                            minIndex = prm->vert;
                            r_dist = dist;
                            r_trans = (r->trans = prm->trans);
                          }
                        } else {
                          r->prim = prm;
                          r->trans = prm->trans;
                          r->dist = dist;
                          return (1);
                        }
                      }
                    } else if(trans_shadows) {
                      if((dist > -kR_SMALL4) &&
                         ((r_trans > prm->trans) ||
                          (nearest_shadow && (dist < r_dist)
                           && (r_trans >= prm->trans)))) {
                        minIndex = prm->vert;
                        r_dist = dist;
                        r_trans = (r->trans = prm->trans);
                      }
                    }
                  }
                }
              }
              break;
            case cPrimCone:
              {
                float sph_rad, sph_rad_sq;
                if(ConeLineToSphereCapped(r->base, minusZ, BI->Vertex + i * 3,
                                          BI->Normal + BI->Vert2Normal[i] * 3,
                                          BI->Radius[i], prm->r2, prm->l1, sph, &tri1,
                                          &sph_rad, &sph_rad_sq, 1, 1)) {

                  oppSq = ZLineClipPoint(r->base, sph, &dist, sph_rad);
                  if(oppSq <= sph_rad_sq) {
                    dist = (float) (sqrt1f(dist) - sqrt1f((sph_rad_sq - oppSq)));

                    if(prm->trans == _0) {
                      if(dist > -kR_SMALL4) {
                        if(nearest_shadow) {
                          if(dist < r_dist) {
                            if(prm->l1 > kR_SMALL4)
                              r_tri1 = tri1 / prm->l1;
                            r_sphere0 = sph[0];
                            r_sphere1 = sph[1];
                            r_sphere2 = sph[2];
                            minIndex = prm->vert;
                            r->trans = prm->trans;
                            r_dist = dist;
                            r_trans = (r->trans = prm->trans);
                          }
                        } else {
                          r->prim = prm;
                          r->trans = prm->trans;
                          r->dist = dist;
                          return (1);
                        }
                      }
                    } else if(trans_shadows) {
                      if((dist > -kR_SMALL4) &&
                         ((r_trans > prm->trans) ||
                          (nearest_shadow && (dist < r_dist)
                           && (r_trans >= prm->trans)))) {
                        if(prm->l1 > kR_SMALL4)
                          r_tri1 = tri1 / prm->l1;
                        r_sphere0 = sph[0];
                        r_sphere1 = sph[1];
                        r_sphere2 = sph[2];
                        minIndex = prm->vert;
                        r->trans = prm->trans;
                        r_dist = dist;
                        r_trans = (r->trans = prm->trans);
                      }
                    }
                  }
                }
              }
              break;
            case cPrimCylinder:
              if(ZLineToSphereCapped(r->base, BI->Vertex + i * 3,
                                     BI->Normal + BI->Vert2Normal[i] * 3,
                                     BI->Radius[i], prm->l1, sph, &tri1, prm->cap1,
                                     prm->cap2, BI->Precomp + BI->Vert2Normal[i] * 3)) {

                oppSq = ZLineClipPoint(r->base, sph, &dist, BI->Radius[i]);
                if(oppSq <= BI->Radius2[i]) {
                  dist = (float) (sqrt1f(dist) - sqrt1f((BI->Radius2[i] - oppSq)));

                  if(prm->trans == _0) {
                    if(dist > -kR_SMALL4) {
                      if(nearest_shadow) {
                        if(dist < r_dist) {
                          if(prm->l1 > kR_SMALL4)
                            r_tri1 = tri1 / prm->l1;
                          r_sphere0 = sph[0];
                          r_sphere1 = sph[1];
                          r_sphere2 = sph[2];
                          minIndex = prm->vert;
                          r->trans = prm->trans;
                          r_dist = dist;
                          r_trans = (r->trans = prm->trans);
                        }
                      } else {
                        r->prim = prm;
                        r->trans = prm->trans;
                        r->dist = dist;
                        return (1);
                      }
                    }
                  } else if(trans_shadows) {
                    if((dist > -kR_SMALL4) &&
                       ((r_trans > prm->trans) ||
                        (nearest_shadow && (dist < r_dist) && (r_trans >= prm->trans)))) {
                      if(prm->l1 > kR_SMALL4)
                        r_tri1 = tri1 / prm->l1;
                      r_sphere0 = sph[0];
                      r_sphere1 = sph[1];
                      r_sphere2 = sph[2];
                      minIndex = prm->vert;
                      r->trans = prm->trans;
                      r_dist = dist;
                      r_trans = (r->trans = prm->trans);
                    }
                  }
                }
              }
              break;

            case cPrimSausage:
              if(ZLineToSphere
                 (r->base, BI->Vertex + i * 3, BI->Normal + BI->Vert2Normal[i] * 3,
                  BI->Radius[i], prm->l1, sph, &tri1,
                  BI->Precomp + BI->Vert2Normal[i] * 3)) {
                oppSq = ZLineClipPoint(r->base, sph, &dist, BI->Radius[i]);
                if(oppSq <= BI->Radius2[i]) {
                  dist = (float) (sqrt1f(dist) - sqrt1f((BI->Radius2[i] - oppSq)));

                  if(prm->trans == _0) {
                    if(dist > -kR_SMALL4) {
                      if(nearest_shadow) {
                        if(dist < r_dist) {
                          if(prm->l1 > kR_SMALL4)
                            r_tri1 = tri1 / prm->l1;
                          r_sphere0 = sph[0];
                          r_sphere1 = sph[1];
                          r_sphere2 = sph[2];
                          minIndex = prm->vert;
                          r_dist = dist;
                          r_trans = (r->trans = prm->trans);
                        }
                      } else {
                        r->prim = prm;
                        r->trans = prm->trans;
                        r->dist = dist;
                        return (1);
                      }
                    }
                  } else if(trans_shadows) {
                    if((dist > -kR_SMALL4) &&
                       ((r_trans > prm->trans) ||
                        (nearest_shadow && (dist < r_dist) && (r_trans >= prm->trans)))) {
                      if(prm->l1 > kR_SMALL4)
                        r_tri1 = tri1 / prm->l1;

                      r_sphere0 = sph[0];
                      r_sphere1 = sph[1];
                      r_sphere2 = sph[2];
                      minIndex = prm->vert;
                      r_dist = dist;
                      r_trans = (r->trans = prm->trans);
                    }
                  }
                }
              }
              break;
            }                   /* end of switch */
          }
          /* end of if */
          i = ii;
        }                       /* end of while */
      }

      /* and of course stop when we hit the edge of the map */

      if(local_iflag)
        break;

      /* we've processed all primitives associated with this voxel, 
         so if an intersection has been found which occurs in front of
         the next voxel, then we can stop */

      /* this optimization invalid for transparent surfaces 

         if( minIndex > -1 ) 
         {
         int   aa,bb,cc;

         vt[2]   = r->base[2] - r_dist;
         MapLocus(BI->Map,vt,&aa,&bb,&cc);
         if(cc > c) 
         break;
         }
       */

      c--;
      xxtmp--;

    }                           /* end of while */

    if(minIndex > -1) {
      r_prim = BC->prim + vert2prim[minIndex];

      if((r_prim->type == cPrimSphere) || (r_prim->type == cPrimEllipsoid)) {
        const float *vv = BI->Vertex + minIndex * 3;
        r_sphere0 = vv[0];
        r_sphere1 = vv[1];
        r_sphere2 = vv[2];
      }
    }

    BC->interior_flag = local_iflag;
    r->tri1 = r_tri1;
    r->tri2 = r_tri2;
    r->prim = r_prim;
    r->dist = r_dist;
    r->trans = r_trans;
    r->sphere[0] = r_sphere0;
    r->sphere[1] = r_sphere1;
    r->sphere[2] = r_sphere2;
    return (minIndex);
  }                             /* end of if */
  BC->interior_flag = local_iflag;
  return (-1);
}