in layer1/Basis.cpp [1530:2022]
int BasisHitPerspective(BasisCallRec * BC)
{
CBasis *BI = BC->Basis;
MapType *map = BI->Map;
int iMin0 = map->iMin[0];
int iMin1 = map->iMin[1];
int iMin2 = map->iMin[2];
int iMax0 = map->iMax[0];
int iMax1 = map->iMax[1];
int iMax2 = map->iMax[2];
int a, b, c;
float iDiv = map->recipDiv;
float base0, base1, base2;
float min0 = map->Min[0] * iDiv;
float min1 = map->Min[1] * iDiv;
float min2 = map->Min[2] * iDiv;
int new_ray = !BC->pass;
RayInfo *r = BC->rr;
MapCache *cache = &BC->cache;
int *cache_cache = cache->Cache;
int *cache_CacheLink = cache->CacheLink;
CPrimitive *r_prim = NULL;
if(new_ray) { /* see if we can eliminate this ray right away using the mask */
base0 = (r->base[0] * iDiv) - min0;
base1 = (r->base[1] * iDiv) - min1;
a = (int) base0;
b = (int) base1;
a += MapBorder;
b += MapBorder;
if(a < iMin0)
a = iMin0;
else if(a > iMax0)
a = iMax0;
if(b < iMin1)
b = iMin1;
else if(b > iMax1)
b = iMax1;
if(!*(map->EMask + a * map->Dim[1] + b))
return -1;
}
{
int last_a = -1, last_b = -1, last_c = -1;
int allow_break;
int minIndex = -1;
float step0, step1, step2;
float back_dist = BC->back_dist;
const float _0 = 0.0F, _1 = 1.0F;
float r_tri1 = _0, r_tri2 = _0, r_dist, dist; /* zero inits to suppress compiler warnings */
float r_sphere0 = _0, r_sphere1 = _0, r_sphere2 = _0;
int h, *ip;
int excl_trans_flag;
int *elist, local_iflag = false;
int terminal = -1;
int *ehead = map->EHead;
int d1d2 = map->D1D2;
int d2 = map->Dim[2];
const int *vert2prim = BC->vert2prim;
const float excl_trans = BC->excl_trans;
const float BasisFudge0 = BC->fudge0;
const float BasisFudge1 = BC->fudge1;
int v2p;
int i, ii;
int n_vert = BI->NVertex, n_eElem = map->NEElem;
int except1 = BC->except1;
int except2 = BC->except2;
int check_interior_flag = BC->check_interior && !BC->pass;
float sph[3], vt[3], tri1 = _0, tri2;
CPrimitive *BC_prim = BC->prim;
int *BI_Vert2Normal = BI->Vert2Normal;
float *BI_Vertex = BI->Vertex;
float *BI_Precomp = BI->Precomp;
float *BI_Normal = BI->Normal;
float *BI_Radius = BI->Radius;
float *BI_Radius2 = BI->Radius2;
copy3f(r->base, vt);
elist = map->EList;
r_dist = MAXFLOAT;
excl_trans_flag = (excl_trans != _0);
if(except1 >= 0)
except1 = vert2prim[except1];
if(except2 >= 0)
except2 = vert2prim[except2];
MapCacheReset(cache);
{ /* take steps with a Z-size equil to the grid spacing */
float div = iDiv * (-MapGetDiv(BI->Map) / r->dir[2]);
step0 = r->dir[0] * div;
step1 = r->dir[1] * div;
step2 = r->dir[2] * div;
}
base0 = (r->skip[0] * iDiv) - min0;
base1 = (r->skip[1] * iDiv) - min1;
base2 = (r->skip[2] * iDiv) - min2;
allow_break = false;
while(1) {
int inside_code;
int clamped;
a = ((int) base0);
b = ((int) base1);
c = ((int) base2);
inside_code = 1;
clamped = false;
a += MapBorder;
b += MapBorder;
c += MapBorder;
#define EDGE_ALLOWANCE 1
if(a < iMin0) {
if(((iMin0 - a) > EDGE_ALLOWANCE) && allow_break)
break;
else {
a = iMin0;
clamped = true;
}
} else if(a > iMax0) {
if(((a - iMax0) > EDGE_ALLOWANCE) && allow_break)
break;
else {
a = iMax0;
clamped = true;
}
}
if(b < iMin1) {
if(((iMin1 - b) > EDGE_ALLOWANCE) && allow_break)
break;
else {
b = iMin1;
clamped = true;
}
} else if(b > iMax1) {
if(((b - iMax1) > EDGE_ALLOWANCE) && allow_break)
break;
else {
b = iMax1;
clamped = true;
}
}
if(c < iMin2) {
if((iMin2 - c) > EDGE_ALLOWANCE)
break;
else {
c = iMin2;
clamped = true;
}
} else if(c > iMax2) {
if((c - iMax2) > EDGE_ALLOWANCE)
inside_code = 0;
else {
c = iMax2;
clamped = true;
}
}
if(inside_code && (((a != last_a) || (b != last_b) || (c != last_c)))) {
int new_min_index;
h = *(ehead + (d1d2 * a) + (d2 * b) + c);
new_min_index = -1;
if(!clamped) /* don't discard a ray until it has hit the objective at least once */
allow_break = true;
if((terminal > 0) && (last_c != c)) {
if(!terminal--)
break;
}
if((h > 0) && (h < n_eElem)) {
int do_loop;
ip = elist + h;
last_a = a;
i = *(ip++);
last_b = b;
do_loop = ((i >= 0) && (i < n_vert));
last_c = c;
while(do_loop) { /* n_vert checking is a bug workaround */
CPrimitive *prm;
v2p = vert2prim[i];
ii = *(ip++);
prm = BC_prim + v2p;
do_loop = ((ii >= 0) && (ii < n_vert));
/* if((v2p != except1) && (v2p != except2) && (!MapCached(cache, v2p))) { */
if((v2p != except1) && (v2p != except2) && (!cache_cache[v2p])) {
int prm_type = prm->type;
/*MapCache(cache,v2p); */
cache_cache[v2p] = 1;
cache_CacheLink[v2p] = cache->CacheStart;
cache->CacheStart = v2p;
switch (prm_type) {
case cPrimTriangle:
case cPrimCharacter:
{
float *dir = r->dir;
float *d10 = BI_Precomp + BI_Vert2Normal[i] * 3;
float *d20 = d10 + 3;
float *v0;
float det, inv_det;
float pvec0, pvec1, pvec2;
float dir0 = dir[0], dir1 = dir[1], dir2 = dir[2];
float d20_0 = d20[0], d20_1 = d20[1], d20_2 = d20[2];
float d10_0 = d10[0], d10_1 = d10[1], d10_2 = d10[2];
/* cross_product3f(dir, d20, pvec); */
pvec0 = dir1 * d20_2 - dir2 * d20_1;
pvec1 = dir2 * d20_0 - dir0 * d20_2;
pvec2 = dir0 * d20_1 - dir1 * d20_0;
/* det = dot_product3f(pvec, d10); */
det = pvec0 * d10_0 + pvec1 * d10_1 + pvec2 * d10_2;
v0 = BI_Vertex + prm->vert * 3;
if((det >= EPSILON) || (det <= -EPSILON)) {
float tvec0, tvec1, tvec2;
float qvec0, qvec1, qvec2;
inv_det = _1 / det;
/* subtract3f(vt,v0,tvec); */
tvec0 = vt[0] - v0[0];
tvec1 = vt[1] - v0[1];
tvec2 = vt[2] - v0[2];
/* dot_product3f(tvec,pvec) * inv_det; */
tri1 = (tvec0 * pvec0 + tvec1 * pvec1 + tvec2 * pvec2) * inv_det;
/* cross_product3f(tvec,d10,qvec); */
qvec0 = tvec1 * d10_2 - tvec2 * d10_1;
qvec1 = tvec2 * d10_0 - tvec0 * d10_2;
if((tri1 >= BasisFudge0) && (tri1 <= BasisFudge1)) {
qvec2 = tvec0 * d10_1 - tvec1 * d10_0;
/* dot_product3f(dir, qvec) * inv_det; */
tri2 = (dir0 * qvec0 + dir1 * qvec1 + dir2 * qvec2) * inv_det;
/* dot_product3f(d20, qvec) * inv_det; */
dist = (d20_0 * qvec0 + d20_1 * qvec1 + d20_2 * qvec2) * inv_det;
if((tri2 >= BasisFudge0) && (tri2 <= BasisFudge1)
&& ((tri1 + tri2) <= BasisFudge1)) {
if((dist < r_dist) && (dist >= _0) && (dist <= back_dist)
&& (prm->trans != _1)) {
new_min_index = prm->vert;
r_tri1 = tri1;
r_tri2 = tri2;
r_dist = dist;
}
}
}
}
}
break;
case cPrimSphere:
{
if(LineClipPoint(r->base, r->dir,
BI_Vertex + i * 3, &dist,
BI_Radius[i], BI_Radius2[i])) {
if((dist < r_dist) && (prm->trans != _1)) {
if((dist >= _0) && (dist <= back_dist)) {
new_min_index = prm->vert;
r_dist = dist;
} else if(check_interior_flag && (dist <= back_dist)) {
if(diffsq3f(vt, BI_Vertex + i * 3) < BI_Radius2[i]) {
local_iflag = true;
r_prim = prm;
r_dist = _0;
new_min_index = prm->vert;
}
}
}
}
}
break;
case cPrimEllipsoid:
{
if(LineClipPoint(r->base, r->dir,
BI_Vertex + i * 3, &dist,
BI_Radius[i], BI_Radius2[i])) {
if((dist < r_dist) && (prm->trans != _1)) {
float *n1 = BI_Normal + BI_Vert2Normal[i] * 3;
if(LineClipEllipsoidPoint(r->base, r->dir,
BI_Vertex + i * 3, &dist,
BI_Radius[i], BI_Radius2[i],
prm->n0, n1, n1 + 3, n1 + 6)) {
if(dist < r_dist) {
if((dist >= _0) && (dist <= back_dist)) {
new_min_index = prm->vert;
r_dist = dist;
}
}
}
}
}
}
break;
case cPrimCylinder:
if(LineToSphereCapped(r->base, r->dir, BI_Vertex + i * 3,
BI_Normal + BI_Vert2Normal[i] * 3,
BI_Radius[i], prm->l1, sph, &tri1,
prm->cap1, prm->cap2)) {
if(LineClipPoint
(r->base, r->dir, sph, &dist, BI_Radius[i], BI_Radius2[i])) {
if((dist < r_dist) && (prm->trans != _1)) {
if((dist >= _0) && (dist <= back_dist)) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
new_min_index = prm->vert;
r_dist = dist;
} else if(check_interior_flag && (dist <= back_dist)) {
if(FrontToInteriorSphereCapped(vt,
BI_Vertex + i * 3,
BI_Normal + BI_Vert2Normal[i] * 3,
BI_Radius[i],
BI_Radius2[i],
prm->l1, prm->cap1, prm->cap2)) {
local_iflag = true;
r_prim = prm;
r_dist = _0;
new_min_index = prm->vert;
}
}
}
}
}
break;
case cPrimCone:
{
float sph_rad, sph_rad_sq;
if(ConeLineToSphereCapped(r->base, r->dir, BI_Vertex + i * 3,
BI_Normal + BI_Vert2Normal[i] * 3,
BI_Radius[i], prm->r2, prm->l1, sph, &tri1,
&sph_rad, &sph_rad_sq,
prm->cap1, prm->cap2)) {
if(LineClipPoint(r->base, r->dir, sph, &dist, sph_rad, sph_rad_sq)) {
if((dist < r_dist) && (prm->trans != _1)) {
if((dist >= _0) && (dist <= back_dist)) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1; /* color blending */
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
new_min_index = prm->vert;
r_dist = dist;
} else if(check_interior_flag && (dist <= back_dist)) {
if(FrontToInteriorSphereCapped(vt,
BI_Vertex + i * 3,
BI_Normal +
BI_Vert2Normal[i] * 3,
BI_Radius[i], BI_Radius2[i],
prm->l1, prm->cap1, prm->cap2)) {
local_iflag = true;
r_prim = prm;
r_dist = _0;
new_min_index = prm->vert;
}
}
}
}
}
}
break;
case cPrimSausage:
if(LineToSphere(r->base, r->dir,
BI_Vertex + i * 3, BI_Normal + BI_Vert2Normal[i] * 3,
BI_Radius[i], prm->l1, sph, &tri1)) {
if(LineClipPoint
(r->base, r->dir, sph, &dist, BI_Radius[i], BI_Radius2[i])) {
int tmp_flag = false;
if((dist < r_dist) && (prm->trans != _1)) {
if((dist >= _0) && (dist <= back_dist)) {
tmp_flag = true;
if(excl_trans_flag) {
if((prm->trans > _0) && (dist < excl_trans))
tmp_flag = false;
}
if(tmp_flag) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
new_min_index = prm->vert;
r_dist = dist;
}
} else if(check_interior_flag && (dist <= back_dist)) {
if(FrontToInteriorSphere(vt, BI_Vertex + i * 3,
BI_Normal + BI_Vert2Normal[i] * 3,
BI_Radius[i], BI_Radius2[i], prm->l1)) {
local_iflag = true;
r_prim = prm;
r_dist = _0;
new_min_index = prm->vert;
}
}
}
}
}
break;
} /* end of switch */
}
/* end of if */
i = ii;
} /* end of while */
if(local_iflag) {
r->prim = r_prim;
r->dist = r_dist;
break;
}
if(new_min_index > -1) {
minIndex = new_min_index;
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->sphere[0] = r_sphere0;
r->sphere[1] = r_sphere1;
r->sphere[2] = r_sphere2;
}
} /* if -- h valid */
}
/* end of if */
if(minIndex > -1) {
if(terminal < 0)
terminal = EDGE_ALLOWANCE + 1;
}
base0 += step0;
base1 += step1;
base2 += step2;
/* advance through the map one block at a time -- note that this is a crappy way to walk through the map... */
}
BC->interior_flag = local_iflag;
return (minIndex);
}
}