647a45d8329519461cb257e423a8176de017d077
1 (* Copyright (C) DooM 2D:Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 // universal spatial grid
17 {$INCLUDE ../shared/a_modes.inc}
18 {$IF DEFINED(D2F_DEBUG)}
19 {.$DEFINE D2F_DEBUG_RAYTRACE}
20 {.$DEFINE D2F_DEBUG_XXQ}
21 {$ENDIF}
24 interface
27 type
31 public
32 type TGridQueryCB = function (obj: ITP; tag: Integer): Boolean is nested; // return `true` to stop
33 type TGridRayQueryCB = function (obj: ITP; tag: Integer; x, y, prevx, prevy: Integer): Boolean is nested; // return `true` to stop
34 type TGridAlongQueryCB = function (obj: ITP; tag: Integer): Boolean is nested; // return `true` to stop
41 private
42 const
46 private
47 type
50 private
57 private
67 TGridInternalCB = function (grida: Integer; bodyId: TBodyProxyId): Boolean of object; // return `true` to stop
69 private
70 //mTileSize: Integer;
73 public
76 private
89 public
91 {$IF DEFINED(D2F_DEBUG)}
93 {$ENDIF}
95 private
116 public
117 constructor Create (aMinPixX, aMinPixY, aPixWidth, aPixHeight: Integer{; aTileSize: Integer=GridDefaultTileSize});
120 function insertBody (aObj: ITP; ax, ay, aWidth, aHeight: Integer; aTag: Integer=-1): TBodyProxyId;
129 // `false` if `body` is surely invalid
132 //WARNING: don't modify grid while any query is in progress (no checks are made!)
133 // you can set enabled/disabled flag, tho (but iterator can still return objects disabled inside it)
134 // no callback: return `true` on the first hit
135 function forEachInAABB (x, y, w, h: Integer; cb: TGridQueryCB; tagmask: Integer=-1; allowDisabled: Boolean=false): ITP;
137 //WARNING: don't modify grid while any query is in progress (no checks are made!)
138 // you can set enabled/disabled flag, tho (but iterator can still return objects disabled inside it)
139 // no callback: return `true` on the first hit
142 //WARNING: don't modify grid while any query is in progress (no checks are made!)
143 // you can set enabled/disabled flag, tho (but iterator can still return objects disabled inside it)
144 // cb with `(nil)` will be called before processing new tile
145 // no callback: return `true` on the nearest hit
146 //WARNING: don't change tags in callbacks here!
147 function traceRay (const x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP; overload;
148 function traceRay (out ex, ey: Integer; const ax0, ay0, ax1, ay1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP;
150 //WARNING: don't modify grid while any query is in progress (no checks are made!)
151 // you can set enabled/disabled flag, tho (but iterator can still return objects disabled inside it)
152 // trace line along the grid, calling `cb` for all objects in passed cells, in no particular order
153 //WARNING: don't change tags in callbacks here!
154 function forEachAlongLine (const x0, y0, x1, y1: Integer; cb: TGridAlongQueryCB; tagmask: Integer=-1; log: Boolean=false): ITP;
156 // debug
161 //WARNING! no sanity checks!
171 // you are not supposed to understand this
172 // returns `true` if there is an intersection, and enter coords
173 // enter coords will be equal to (x0, y0) if starting point is inside the box
174 // if result is `false`, `inx` and `iny` are undefined
175 function lineAABBIntersects (x0, y0, x1, y1: Integer; bx, by, bw, bh: Integer; out inx, iny: Integer): Boolean;
184 implementation
186 uses
190 // ////////////////////////////////////////////////////////////////////////// //
191 procedure swapInt (var a: Integer; var b: Integer); inline; var t: Integer; begin t := a; a := b; b := t; end;
192 function minInt (a, b: Integer): Integer; inline; begin if (a < b) then result := a else result := b; end;
193 function maxInt (a, b: Integer): Integer; inline; begin if (a > b) then result := a else result := b; end;
195 function distanceSq (x0, y0, x1, y1: Integer): Integer; inline; begin result := (x1-x0)*(x1-x0)+(y1-y0)*(y1-y0); end;
198 // ////////////////////////////////////////////////////////////////////////// //
199 // you are not supposed to understand this
200 // returns `true` if there is an intersection, and enter coords
201 // enter coords will be equal to (x0, y0) if starting point is inside the box
202 // if result is `false`, `inx` and `iny` are undefined
203 function lineAABBIntersects (x0, y0, x1, y1: Integer; bx, by, bw, bh: Integer; out inx, iny: Integer): Boolean;
204 var
212 //!term: Integer;
216 begin
218 // why not
224 begin
225 // check this point
227 exit;
230 // check if staring point is inside the box
231 if (x0 >= bx) and (y0 >= by) and (x0 < bx+bw) and (y0 < by+bh) then begin result := true; exit; end;
233 // clip rectange
239 // horizontal setup
241 begin
242 // from left to right
245 end
246 else
247 begin
248 // from right to left
258 // vertical setup
260 begin
261 // from top to bottom
264 end
265 else
266 begin
267 // from bottom to top
281 begin
290 end
291 else
292 begin
302 //!term := x1;
306 begin
307 // clip at top
313 begin
322 begin
323 // clip at left
333 (*
334 if (y1 > wy1) then
335 begin
336 // clip at bottom
337 temp := dx2*(wy1-y0)+dsx;
338 term := x0+temp div dy2;
339 rem := temp mod dy2;
340 if (rem = 0) then Dec(term);
341 end;
343 if (term > wx1) then term := wx1; // clip at right
345 Inc(term); // draw last point
346 //if (term = xd) then exit; // this is the only point, get out of here
347 *)
351 //!dx2 -= dy2;
359 // ////////////////////////////////////////////////////////////////////////// //
360 procedure TBodyGridBase.TBodyProxyRec.setup (aX, aY, aWidth, aHeight: Integer; aObj: ITP; aTag: Integer);
361 begin
373 // ////////////////////////////////////////////////////////////////////////// //
374 constructor TBodyGridBase.Create (aMinPixX, aMinPixY, aPixWidth, aPixHeight: Integer{; aTileSize: Integer=GridDefaultTileSize});
375 var
377 begin
379 {$IF DEFINED(D2F_DEBUG)}
381 {$ENDIF}
382 {
383 if aTileSize < 1 then aTileSize := 1;
384 if aTileSize > 8192 then aTileSize := 8192; // arbitrary limit
385 mTileSize := aTileSize;
386 }
397 // init free list
399 begin
405 // init grid
407 // init proxies
415 e_WriteLog(Format('created grid with size: %dx%d (tile size: %d); pix: %dx%d', [mWidth, mHeight, mTileSize, mWidth*mTileSize, mHeight*mTileSize]), MSG_NOTIFY);
420 begin
428 // ////////////////////////////////////////////////////////////////////////// //
430 var
432 begin
435 begin
439 begin
445 e_WriteLog(Format('grid size: %dx%d (tile size: %d); pix: %dx%d; used cells: %d; max bodies in cell: %d; max proxies allocated: %d; proxies used: %d', [mWidth, mHeight, mTileSize, mWidth*mTileSize, mHeight*mTileSize, mUsedCells, mcb, mProxyMaxCount, mProxyCount]), MSG_NOTIFY);
450 var
453 begin
456 begin
459 begin
462 begin
464 if (cc.bodies[f] = body) then cb((g mod mWidth)*mTileSize+mMinX, (g div mWidth)*mTileSize+mMinY);
466 // next cell
474 var
477 begin
485 begin
488 begin
490 if cb(mProxies[cc.bodies[f]].mObj, mProxies[cc.bodies[f]].mTag) then begin result := mProxies[cc.bodies[f]].mObj; exit; end;
492 // next cell
498 // ////////////////////////////////////////////////////////////////////////// //
499 function TBodyGridBase.getGridWidthPx (): Integer; inline; begin result := mWidth*mTileSize; end;
500 function TBodyGridBase.getGridHeightPx (): Integer; inline; begin result := mHeight*mTileSize; end;
504 begin
505 // fix coords
513 begin
515 begin
518 end
519 else
520 begin
528 // ////////////////////////////////////////////////////////////////////////// //
530 begin
536 begin
538 begin
540 begin
542 end
543 else
544 begin
551 // ////////////////////////////////////////////////////////////////////////// //
553 var
556 begin
558 begin
559 // no free cells, want more
563 begin
575 //e_WriteLog(Format('grid: allocated new cell #%d (total: %d)', [result, mUsedCells]), MSG_NOTIFY);
580 begin
582 begin
584 begin
595 // ////////////////////////////////////////////////////////////////////////// //
596 function TBodyGridBase.allocProxy (aX, aY, aWidth, aHeight: Integer; aObj: ITP; aTag: Integer): TBodyProxyId;
597 var
600 begin
602 begin
603 // no free proxies, resize list
610 // get one from list
615 // add to used list
617 // statistics
623 begin
625 if (mProxyCount = 0) then raise Exception.Create('wutafuuuuu in grid (no allocated proxies, what i should free now?)');
626 // add to free list
634 // ////////////////////////////////////////////////////////////////////////// //
635 function TBodyGridBase.forGridRect (x, y, w, h: Integer; cb: TGridInternalCB; bodyId: TBodyProxyId): Boolean;
636 const
638 var
641 begin
644 // fix coords
647 // go on
651 //tsize := mTileSize;
654 begin
658 begin
668 // ////////////////////////////////////////////////////////////////////////// //
670 var
675 begin
677 // add body to the given grid cell
680 begin
681 {$IF DEFINED(D2F_DEBUG)}
684 begin
687 begin
689 if (pi.bodies[f] = bodyId) then raise Exception.Create('trying to insert already inserted proxy');
693 {$ENDIF}
696 begin
698 // check "has room" flag
700 begin
701 // can add here
703 begin
705 begin
708 exit;
713 // no room, go to next cell in list (if there is any)
716 // no room in cells, add new cell to list
718 // either no room, or no cell at all
728 var
730 begin
737 // assume that we cannot have one object added to bucket twice
739 var
743 begin
745 // find and remove cell
749 begin
752 begin
754 begin
755 // i found her!
757 begin
758 // this cell contains no elements, remove it
761 exit;
763 // remove element from bucket
765 begin
770 exit;
779 var
781 begin
788 // ////////////////////////////////////////////////////////////////////////// //
789 function TBodyGridBase.insertBody (aObj: ITP; aX, aY, aWidth, aHeight: Integer; aTag: Integer=-1): TBodyProxyId;
790 begin
798 begin
805 // ////////////////////////////////////////////////////////////////////////// //
807 var
810 begin
818 // did any corner crossed tile boundary?
823 begin
830 end
831 else
832 begin
840 //TODO: optimize for horizontal/vertical moves
842 var
850 begin
852 // check if tile coords was changed
857 // map -> grid
862 // check for heavy work
874 begin
875 // crossed tile boundary, do heavy work
878 // cycle with old rect, remove body where it is necessary
879 // optimized for horizontal moves
880 //e_WriteLog(Format('og:(%d,%d)-(%d,%d); ng:(%d,%d)-(%d,%d)', [ogx0, ogy0, ogx1, ogy1, ngx0, ngy0, ngx1, ngy1]), MSG_NOTIFY);
881 // remove stale marks
884 begin
889 //e_WriteLog(Format(' norm og:(%d,%d)-(%d,%d)', [ogx0, ogy0, ogx1, ogy1]), MSG_NOTIFY);
891 begin
893 begin
894 // this column is completely outside of new rect
896 begin
897 //e_WriteLog(Format(' remove:(%d,%d)', [gx, gy]), MSG_NOTIFY);
900 end
901 else
902 begin
903 // heavy checks
905 begin
907 begin
908 //e_WriteLog(Format(' remove:(%d,%d)', [gx, gy]), MSG_NOTIFY);
915 // cycle with new rect, add body where it is necessary
918 begin
923 //e_WriteLog(Format(' norm ng:(%d,%d)-(%d,%d)', [ngx0, ngy0, ngx1, ngy1]), MSG_NOTIFY);
925 begin
927 begin
928 // this column is completely outside of old rect
930 begin
931 //e_WriteLog(Format(' insert:(%d,%d)', [gx, gy]), MSG_NOTIFY);
934 end
935 else
936 begin
937 // heavy checks
939 begin
941 begin
942 //e_WriteLog(Format(' insert:(%d,%d)', [gx, gy]), MSG_NOTIFY);
949 // done
951 // update coordinates
957 var
960 begin
962 // check if tile coords was changed
970 begin
971 // crossed tile boundary, do heavy work
976 end
977 else
978 begin
979 // nothing to do with the grid, just fix size
986 // ////////////////////////////////////////////////////////////////////////// //
987 // no callback: return `true` on the first hit
988 function TBodyGridBase.forEachAtPoint (x, y: Integer; cb: TGridQueryCB; tagmask: Integer=-1): ITP;
989 var
996 begin
1001 {$IF DEFINED(D2F_DEBUG_XXQ)}
1003 {$ENDIF}
1005 // make coords (0,0)-based
1012 {$IF DEFINED(D2F_DEBUG_XXQ)}
1013 if (assigned(cb)) then e_WriteLog(Format('1: grid pointquery: (%d,%d) (%d,%d) %d', [x, y, (x div mTileSize), (y div mTileSize), curci]), MSG_NOTIFY);
1014 {$ENDIF}
1016 // restore coords
1020 // increase query counter
1023 begin
1024 // just in case of overflow
1030 {$IF DEFINED(D2F_DEBUG_XXQ)}
1031 if (assigned(cb)) then e_WriteLog(Format('2: grid pointquery: (%d,%d); lq=%u', [x, y, lq]), MSG_NOTIFY);
1032 {$ENDIF}
1035 begin
1036 {$IF DEFINED(D2F_DEBUG_XXQ)}
1038 {$ENDIF}
1041 begin
1044 {$IF DEFINED(D2F_DEBUG_XXQ)}
1045 if (assigned(cb)) then e_WriteLog(Format(' proxy #%d; qm:%u; tag:%08x; tagflag:%d %u', [cc.bodies[f], px.mQueryMark, px.mTag, (px.mTag and tagmask), LongWord(px.mObj)]), MSG_NOTIFY);
1046 {$ENDIF}
1047 // shit. has to do it this way, so i can change tag in callback
1049 begin
1054 begin
1056 begin
1058 end
1059 else
1060 begin
1062 exit;
1072 // ////////////////////////////////////////////////////////////////////////// //
1073 // no callback: return `true` on the first hit
1074 function TBodyGridBase.forEachInAABB (x, y, w, h: Integer; cb: TGridQueryCB; tagmask: Integer=-1; allowDisabled: Boolean=false): ITP;
1075 const
1077 var
1088 begin
1097 // fix coords
1102 //tsize := mTileSize;
1107 // increase query counter
1110 begin
1111 // just in case of overflow
1115 //e_WriteLog(Format('grid: query #%d: (%d,%d)-(%dx%d)', [mLastQuery, minx, miny, maxx, maxy]), MSG_NOTIFY);
1118 // go on
1120 begin
1124 begin
1127 // process cells
1130 begin
1133 begin
1136 // shit. has to do it this way, so i can change tag in callback
1145 begin
1147 end
1148 else
1149 begin
1151 exit;
1161 // ////////////////////////////////////////////////////////////////////////// //
1162 // no callback: return `true` on the nearest hit
1163 function TBodyGridBase.traceRay (const x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP;
1164 var
1166 begin
1171 // no callback: return `true` on the nearest hit
1172 // you are not supposed to understand this
1173 function TBodyGridBase.traceRay (out ex, ey: Integer; const ax0, ay0, ax1, ay1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP;
1174 const
1176 var
1202 begin
1210 if (ax0 = ax1) and (ay0 = ay1) then exit; // as the first point is ignored, just get outta here
1221 {$IF DEFINED(D2F_DEBUG_RAYTRACE)}
1222 if assigned(dbgRayTraceTileHitCB) then e_WriteLog(Format('TRACING: (%d,%d)-(%d,%d) [(%d,%d)-(%d,%d)]; maxdistsq=%d', [ax0, ay0, ax1, ay1, minx, miny, maxx, maxy, lastDistSq]), MSG_NOTIFY);
1223 {$ENDIF}
1230 // offset query coords to (0,0)-based
1236 // clip rectange
1242 // horizontal setup
1244 begin
1245 // from left to right
1248 end
1249 else
1250 begin
1251 // from right to left
1261 // vertical setup
1263 begin
1264 // from top to bottom
1267 end
1268 else
1269 begin
1270 // from bottom to top
1284 begin
1293 end
1294 else
1295 begin
1309 begin
1310 // clip at top
1316 begin
1325 begin
1326 // clip at left
1337 begin
1338 // clip at bottom
1348 //if (term = xd) then exit; // this is the only point, get out of here
1354 // first move, to skip starting point
1355 // DON'T DO THIS! loop will take care of that
1359 (*
1360 // move coords
1361 if (e >= 0) then begin yd += sty; e -= dx2; end else e += dy2;
1362 xd += stx;
1363 // done?
1364 if (xd = term) then exit;
1365 *)
1367 {$IF DEFINED(D2F_DEBUG)}
1368 if (xptr^ < 0) or (yptr^ < 0) or (xptr^ >= gw*tsize) and (yptr^ >= gh*tsize) then raise Exception.Create('raycaster internal error (0)');
1369 {$ENDIF}
1370 // DON'T DO THIS! loop will take care of that
1371 //lastGA := (yptr^ div tsize)*gw+(xptr^ div tsize);
1372 //ccidx := mGrid[lastGA];
1374 {$IF DEFINED(D2F_DEBUG_RAYTRACE)}
1375 //if assigned(dbgRayTraceTileHitCB) then e_WriteLog('1:TRACING!', MSG_NOTIFY);
1376 {$ENDIF}
1378 {$IF DEFINED(D2F_DEBUG_RAYTRACE)}
1379 if assigned(dbgRayTraceTileHitCB) then dbgRayTraceTileHitCB((xptr^ div tsize*tsize)+minx, (yptr^ div tsize*tsize)+miny);
1380 {$ENDIF}
1382 //if (dbgShowTraceLog) then e_WriteLog(Format('raycast start: (%d,%d)-(%d,%d); xptr^=%d; yptr^=%d', [ax0, ay0, ax1, ay1, xptr^, yptr^]), MSG_NOTIFY);
1384 // increase query counter
1387 begin
1388 // just in case of overflow
1395 // draw it; can omit checks
1397 begin
1398 // check cell(s)
1399 {$IF DEFINED(D2F_DEBUG)}
1400 if (xptr^ < 0) or (yptr^ < 0) or (xptr^ >= gw*tsize) and (yptr^ >= gh*tsize) then raise Exception.Create('raycaster internal error (0)');
1401 {$ENDIF}
1402 // new tile?
1405 begin
1406 // yes
1407 {$IF DEFINED(D2F_DEBUG)}
1408 if assigned(dbgRayTraceTileHitCB) then dbgRayTraceTileHitCB((xptr^ div tsize*tsize)+minx, (yptr^ div tsize*tsize)+miny);
1409 {$ENDIF}
1411 begin
1412 // signal cell completion
1414 begin
1416 end
1418 begin
1420 exit;
1426 // has something to process in this tile?
1428 begin
1429 // process cell
1431 hasUntried := false; // this will be set to `true` if we have some proxies we still want to process at the next step
1432 // convert coords to map (to avoid ajdusting coords inside the loop)
1435 // process cell list
1437 begin
1440 begin
1445 begin
1446 // can we process this proxy?
1448 begin
1451 begin
1453 begin
1457 exit;
1459 (*
1460 {$IF DEFINED(D2F_DEBUG_RAYTRACE)}
1461 distSq := distanceSq(ax0, ay0, prevx, prevy);
1462 if assigned(dbgRayTraceTileHitCB) then e_WriteLog(Format(' hit(%d): a=(%d,%d), h=(%d,%d), p=(%d,%d); distsq=%d; lastsq=%d', [cc.bodies[f], ax0, ay0, x, y, prevx, prevy, distSq, lastDistSq]), MSG_NOTIFY);
1463 if (distSq < lastDistSq) then
1464 begin
1465 wasHit := true;
1466 lastDistSq := distSq;
1467 ex := prevx;
1468 ey := prevy;
1469 lastObj := px.mObj;
1470 end;
1471 {$ENDIF}
1472 *)
1473 end
1474 else
1475 begin
1476 // remember this hitpoint if it is nearer than an old one
1478 {$IF DEFINED(D2F_DEBUG_RAYTRACE)}
1479 if assigned(dbgRayTraceTileHitCB) then e_WriteLog(Format(' hit(%d): a=(%d,%d), h=(%d,%d), p=(%d,%d); distsq=%d; lastsq=%d', [cc.bodies[f], ax0, ay0, x, y, prevx, prevy, distSq, lastDistSq]), MSG_NOTIFY);
1480 {$ENDIF}
1482 begin
1490 end
1491 else
1492 begin
1493 // this is possibly interesting proxy, set "has more to check" flag
1498 // next cell
1501 // still has something interesting in this cell?
1503 begin
1504 // nope, don't process this cell anymore; signal cell completion
1507 begin
1509 end
1511 begin
1513 exit;
1517 //putPixel(xptr^, yptr^);
1518 // move coords
1527 // ////////////////////////////////////////////////////////////////////////// //
1528 //FIXME! optimize this with real tile walking
1529 function TBodyGridBase.forEachAlongLine (const x0, y0, x1, y1: Integer; cb: TGridAlongQueryCB; tagmask: Integer=-1; log: Boolean=false): ITP;
1530 const
1532 var
1551 //tedist: Integer;
1552 begin
1574 // `x` and `y` will be in grid coords
1578 // increase query counter
1581 begin
1582 // just in case of overflow
1588 // cache various things
1589 //tsize := mTileSize;
1595 // setup distance and flags
1598 // setup starting tile ('cause we'll adjust tile vars only on tile edge crossing)
1601 // it is slightly faster this way
1605 if (log) then e_WriteLog(Format('tracing: (%d,%d)-(%d,%d)', [x, y, x1-minx, y1-miny]), MSG_NOTIFY);
1607 // now trace
1610 begin
1612 // do one step
1615 // invariant: one of those always changed
1616 {$IF DEFINED(D2F_DEBUG)}
1617 if (xerr < 0) and (yerr < 0) then raise Exception.Create('internal bug in grid raycaster (0)');
1618 {$ENDIF}
1621 // invariant: we always doing a step
1622 {$IF DEFINED(D2F_DEBUG)}
1624 {$ENDIF}
1625 begin
1626 // check for crossing tile/grid boundary
1628 begin
1629 // we're still in grid
1631 // check for tile edge crossing
1637 // crossed tile edge?
1639 begin
1640 // setup new cell index
1642 if (log) then e_WriteLog(Format(' stepped to new tile (%d,%d) -- (%d,%d)', [(x div tsize), (y div tsize), x, y]), MSG_NOTIFY);
1643 end
1644 else
1646 begin
1647 // we have nothing interesting here anymore, jump directly to tile edge
1648 (*
1649 if (incx = 0) then
1650 begin
1651 // vertical line
1652 if (incy < 0) then tedist := y-(y and (not tsize)) else tedist := (y or (tsize-1))-y;
1653 if (tedist > 1) then
1654 begin
1655 if (log) then e_WriteLog(Format(' doing vertical jump from tile (%d,%d) - (%d,%d) by %d steps', [(x div tsize), (y div tsize), x, y, tedist]), MSG_NOTIFY);
1656 y += incy*tedist;
1657 Inc(i, tedist);
1658 if (log) then e_WriteLog(Format(' jumped to tile (%d,%d) - (%d,%d) by %d steps', [(x div tsize), (y div tsize), x, y, tedist]), MSG_NOTIFY);
1659 end;
1660 end
1661 else if (incy = 0) then
1662 begin
1663 // horizontal line
1664 if (incx < 0) then tedist := x-(x and (not tsize)) else tedist := (x or (tsize-1))-x;
1665 if (tedist > 1) then
1666 begin
1667 if (log) then e_WriteLog(Format(' doing horizontal jump from tile (%d,%d) - (%d,%d) by %d steps', [(x div tsize), (y div tsize), x, y, tedist]), MSG_NOTIFY);
1668 x += incx*tedist;
1669 Inc(i, tedist);
1670 if (log) then e_WriteLog(Format(' jumped to tile (%d,%d) - (%d,%d) by %d steps', [(x div tsize), (y div tsize), x, y, tedist]), MSG_NOTIFY);
1671 end;
1672 end;
1673 *)
1674 (*
1675 else if (
1676 // get minimal distance to tile edges
1677 if (incx < 0) then tedist := x-(x and (not tsize)) else if (incx > 0) then tedist := (x or (tsize+1))-x else tedist := 0;
1678 {$IF DEFINED(D2F_DEBUG)}
1679 if (tedist < 0) then raise Exception.Create('internal bug in grid raycaster (2.x)');
1680 {$ENDIF}
1681 if (incy < 0) then f := y-(y and (not tsize)) else if (incy > 0) then f := (y or (tsize+1))-y else f := 0;
1682 {$IF DEFINED(D2F_DEBUG)}
1683 if (f < 0) then raise Exception.Create('internal bug in grid raycaster (2.y)');
1684 {$ENDIF}
1685 if (tedist = 0) then tedist := f else if (f <> 0) then tedist := minInt(tedist, f);
1686 // do jump
1687 if (tedist > 1) then
1688 begin
1689 if (log) then e_WriteLog(Format(' doing jump from tile (%d,%d) - (%d,%d) by %d steps', [(x div tsize), (y div tsize), x, y, tedist]), MSG_NOTIFY);
1690 xerr += dx*tedist;
1691 yerr += dy*tedist;
1692 if (xerr >= 0) then begin x += incx*((xerr div d)+1); xerr := (xerr mod d)-d; end;
1693 if (yerr >= 0) then begin y += incy*((yerr div d)+1); yerr := (yerr mod d)-d; end;
1694 Inc(i, tedist);
1695 if (log) then e_WriteLog(Format(' jumped to tile (%d,%d) - (%d,%d) by %d steps', [(x div tsize), (y div tsize), x, y, tedist]), MSG_NOTIFY);
1696 end;
1697 *)
1699 end
1700 else
1701 begin
1702 // out of grid
1707 // has something to process in the current cell?
1709 begin
1710 // process cell
1712 // convert coords to map (to avoid ajdusting coords inside the loop)
1713 //Inc(x, minx);
1714 //Inc(y, miny);
1715 // process cell list
1717 begin
1720 begin
1725 begin
1730 // next cell
1734 // convert coords to grid
1735 //Dec(x, minx);
1736 //Dec(y, miny);