| 433 | } |
| 434 | |
| 435 | void intersectgeometry(const vec &from, vec &to) // check line for contact with map geometry, shorten if necessary |
| 436 | { |
| 437 | int x = from.x, y = from.y, hfnb[4] = { 0, 1, ssize, ssize +1 }; |
| 438 | if(OUTBORD(x, y) || from.z < -127.0f || from.z > 127.0f) return; |
| 439 | vec d = to; // d: direction |
| 440 | d.sub(from); |
| 441 | |
| 442 | float distmin = 1.0f, vdelta[4]; |
| 443 | sqr *r[2], *s, *nb[4]; |
| 444 | loop(xy, 2) // first check x == const planes and then y == const planes |
| 445 | { |
| 446 | float dxy = xy ? d.y : d.x, fromxy = xy ? from.y : from.x; |
| 447 | bool dxynz = fabs(dxy) < NEARZERO; |
| 448 | if(dxy == 0.0f) dxy = 1e-20; // hack |
| 449 | |
| 450 | int ixy = fromxy, step = dxy < 0 ? -1 : 1, steps = fabs(dxy) + 1, sqrdir = xy ? -ssize : -1; |
| 451 | while(steps-- > 0) |
| 452 | { |
| 453 | // intersect d with plane |
| 454 | float t = dxynz ? distmin : (ixy - fromxy) / dxy; |
| 455 | vec p = d; |
| 456 | p.mul(t).add(from); |
| 457 | |
| 458 | // check position |
| 459 | if(xy) x = p.x, y = ixy; |
| 460 | else x = ixy, y = p.y; |
| 461 | if(t > distmin || OUTBORD(x, y)) break; |
| 462 | |
| 463 | // always check cubes on both sides of the plane |
| 464 | r[0] = S(x, y); |
| 465 | r[1] = r[0] + sqrdir; |
| 466 | if(t > 0) loopk(2) |
| 467 | { |
| 468 | s = r[k]; |
| 469 | if(SOLID(s) || s->floor > p.z || s->ceil < p.z || s->type == CORNER) |
| 470 | { // cube s is a probable hit, examine further |
| 471 | if(k) |
| 472 | { // match x|y back to s |
| 473 | if(xy) y--; |
| 474 | else x--; |
| 475 | } |
| 476 | |
| 477 | if(s->type == CORNER) |
| 478 | { |
| 479 | sqr *ns, *h = NULL, *n; |
| 480 | int bx, by, bs; |
| 481 | int q = cornertest(x, y, bx, by, bs, ns, h); |
| 482 | vec newto; float newdist; |
| 483 | if(intersectcorner(from, d, bx, by, bs, !(q & 1), &newto, &newdist) && newdist < distmin && (!h || newto.z < ns->floor || newto.z > ns->ceil)) to = newto, distmin = newdist; |
| 484 | if(d.z) |
| 485 | { // intersect with z == const plane where the corner ends |
| 486 | bool downwards = d.z < 0.0f; |
| 487 | n = h ? h : ns; |
| 488 | float endplate = downwards ? n->floor : n->ceil; |
| 489 | float tz = (endplate - from.z) / d.z; |
| 490 | vec pz = d; |
| 491 | pz.mul(tz).add(from); |
| 492 | if(pz.x >= bx && pz.x <= bx + bs && pz.y >= by && pz.y <= by + bs && tz < distmin) to = pz, distmin = tz; |
no test coverage detected