diff --git a/src/p_maputl.c b/src/p_maputl.c index 4df9de76c..a7ee27ce1 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -1736,10 +1736,6 @@ static boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac) boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2, INT32 flags, traverser_t trav) { - fixed_t xt1, yt1, xt2, yt2; - fixed_t xstep, ystep, partialx, partialy, xintercept, yintercept; - INT32 mapx, mapy, mapxstep, mapystep, count; - validcount++; intercept_p = intercepts; @@ -1756,170 +1752,94 @@ boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2, px1 -= bmaporgx; py1 -= bmaporgy; - xt1 = (unsigned)px1>>MAPBLOCKSHIFT; - yt1 = (unsigned)py1>>MAPBLOCKSHIFT; - px2 -= bmaporgx; py2 -= bmaporgy; - xt2 = (unsigned)px2>>MAPBLOCKSHIFT; - yt2 = (unsigned)py2>>MAPBLOCKSHIFT; - if (xt2 > xt1) + // blockmap traversal algorithm ported from antimony + int gridpos_x = px1 >> MAPBLOCKSHIFT; + int gridpos_y = py1 >> MAPBLOCKSHIFT; + if (flags & PT_ADDLINES) + if (!P_BlockLinesIterator(gridpos_x, gridpos_y, PIT_AddLineIntercepts)) + return false; // early out + if (flags & PT_ADDTHINGS) + if (!P_BlockThingsIterator(gridpos_x, gridpos_y, PIT_AddThingIntercepts)) + return false; // early out + + int endpos_x = px2 >> MAPBLOCKSHIFT; + int endpos_y = py2 >> MAPBLOCKSHIFT; + if (gridpos_x == endpos_x && gridpos_y == endpos_y) + return P_TraverseIntercepts(trav, FRACUNIT); + + fixed_t pos_x = px1; + fixed_t pos_y = py1; + fixed_t dist_x = px2 - px1; + fixed_t dist_y = py2 - py1; + int dir_x = dist_x < 0 ? -1 : 1; + int dir_y = dist_y < 0 ? -1 : 1; + fixed_t delta_x; + fixed_t delta_y; + // special cases for 0 to avoid crashes + if (dist_y == 0) { - mapxstep = 1; - partialx = FRACUNIT - ((px1>>MAPBTOFRAC) & FRACMASK); - ystep = FixedDiv(py2 - py1, abs(px2 - px1)); + delta_x = INT32_MAX; + delta_y = 0; } - else if (xt2 < xt1) + else if (dist_x == 0) { - mapxstep = -1; - partialx = (px1>>MAPBTOFRAC) & FRACMASK; - ystep = FixedDiv(py2 - py1, abs(px2 - px1)); + delta_x = 0; + delta_y = INT32_MAX; } else { - mapxstep = 0; - partialx = FRACUNIT; - ystep = 256*FRACUNIT; + delta_x = FixedDiv2(dist_x, abs(dist_y)); + delta_y = FixedDiv2(dist_y, abs(dist_x)); } - yintercept = (py1>>MAPBTOFRAC) + FixedMul(partialx, ystep); + while (gridpos_x >= 0 && gridpos_y >= 0 && gridpos_x < bmapwidth && gridpos_y < bmapheight) + { + fixed_t hitx_x; + if (dir_x > 0) + hitx_x = (gridpos_x+1) << MAPBLOCKSHIFT; + else + hitx_x = gridpos_x << MAPBLOCKSHIFT; - if (yt2 > yt1) - { - mapystep = 1; - partialy = FRACUNIT - ((py1>>MAPBTOFRAC) & FRACMASK); - xstep = FixedDiv(px2 - px1, abs(py2 - py1)); - } - else if (yt2 < yt1) - { - mapystep = -1; - partialy = (py1>>MAPBTOFRAC) & FRACMASK; - xstep = FixedDiv(px2 - px1, abs(py2 - py1)); - } - else - { - mapystep = 0; - partialy = FRACUNIT; - xstep = 256*FRACUNIT; - } - xintercept = (px1>>MAPBTOFRAC) + FixedMul(partialy, xstep); + fixed_t hity_y; + if (dir_y > 0) + hity_y = (gridpos_y+1) << MAPBLOCKSHIFT; + else + hity_y = gridpos_y << MAPBLOCKSHIFT; - // [RH] Fix for traces that pass only through blockmap corners. In that case, - // xintercept and yintercept can both be set ahead of mapx and mapy, so the - // for loop would never advance anywhere. - - if (abs(xstep) == FRACUNIT && abs(ystep) == FRACUNIT) - { - if (ystep < 0) + hitx_x -= pos_x; + hity_y -= pos_y; + fixed_t hitx_y = FixedMul(delta_y, abs(hitx_x)); + fixed_t hity_x = FixedMul(delta_x, abs(hity_y)); + if (FixedMul(hitx_x, hitx_x) + FixedMul(hitx_y, hitx_y) > FixedMul(hity_x, hity_x) + FixedMul(hity_y, hity_y)) { - partialx = FRACUNIT - partialx; + gridpos_y += dir_y; + pos_x += hity_x; + pos_y += hity_y; } - if (xstep < 0) + else { - partialy = FRACUNIT - partialy; + gridpos_x += dir_x; + pos_x += hitx_x; + pos_y += hitx_y; } - if (partialx == partialy) - { - xintercept = xt1 << FRACBITS; - yintercept = yt1 << FRACBITS; - } - } - // Step through map blocks. - // Count is present to prevent a round off error - // from skipping the break. - mapx = xt1; - mapy = yt1; - - for (count = 0; count < 100; count++) - { if (flags & PT_ADDLINES) - { - P_BlockLinesIterator(mapx, mapy, PIT_AddLineIntercepts); - } - + if (!P_BlockLinesIterator(gridpos_x, gridpos_y, PIT_AddLineIntercepts)) + return false; // early out if (flags & PT_ADDTHINGS) - { - P_BlockThingsIterator(mapx, mapy, PIT_AddThingIntercepts); - } - - // both coordinates reached the end, so end the traversing. - if ((mapxstep | mapystep) == 0) - { + if (!P_BlockThingsIterator(gridpos_x, gridpos_y, PIT_AddThingIntercepts)) + return false; // early out + if (gridpos_x == endpos_x && gridpos_y == endpos_y) break; - } - - // [RH] Handle corner cases properly instead of pretending they don't exist. - switch ( (((yintercept >> FRACBITS) == mapy) << 1) | ((xintercept >> FRACBITS) == mapx) ) - { - case 0: // neither xintercept nor yintercept match! - { - count = 100; // Stop traversing, because somebody screwed up. - break; - } - case 1: // xintercept matches - { - xintercept += xstep; - mapy += mapystep; - if (mapy == yt2) - { - mapystep = 0; - } - break; - } - case 2: // yintercept matches - { - yintercept += ystep; - mapx += mapxstep; - if (mapx == xt2) - { - mapxstep = 0; - } - break; - } - case 3: // xintercept and yintercept both match - { - // The trace is exiting a block through its corner. Not only does the block - // being entered need to be checked (which will happen when this loop - // continues), but the other two blocks adjacent to the corner also need to - // be checked. - if (flags & PT_ADDLINES) - { - P_BlockLinesIterator(mapx + mapxstep, mapy, PIT_AddLineIntercepts); - P_BlockLinesIterator(mapx, mapy + mapystep, PIT_AddLineIntercepts); - } - - if (flags & PT_ADDTHINGS) - { - P_BlockThingsIterator(mapx + mapxstep, mapy, PIT_AddThingIntercepts); - P_BlockThingsIterator(mapx, mapy + mapystep, PIT_AddThingIntercepts); - } - - xintercept += xstep; - yintercept += ystep; - - mapx += mapxstep; - mapy += mapystep; - - if (mapx == xt2) - { - mapxstep = 0; - } - if (mapy == yt2) - { - mapystep = 0; - } - break; - } - } } // Go through the sorted list return P_TraverseIntercepts(trav, FRACUNIT); } - // ========================================================================= // BLOCKMAP ITERATORS // =========================================================================