summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: faef8ad)
raw | patch | inline | side by side (parent: faef8ad)
author | Ketmar Dark <ketmar@ketmar.no-ip.org> | |
Tue, 22 Aug 2017 15:23:11 +0000 (18:23 +0300) | ||
committer | Ketmar Dark <ketmar@ketmar.no-ip.org> | |
Wed, 23 Aug 2017 18:23:55 +0000 (21:23 +0300) |
src/game/g_grid.pas | patch | blob | history |
diff --git a/src/game/g_grid.pas b/src/game/g_grid.pas
index 70703afd363162b5438af2d84a0a432cacb8db6c..b4dca5eecf483d5255bbee3591398cd584e9fa7c 100644 (file)
--- a/src/game/g_grid.pas
+++ b/src/game/g_grid.pas
function TBodyGridBase.traceRay (out ex, ey: Integer; x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP;
var
i: Integer;
- dx, dy: Integer;
- xerr: Integer = 0;
- yerr: Integer = 0;
- d: Integer;
+ dx, dy, d: Integer;
+ xerr, yerr: Integer;
incx, incy: Integer;
+ stepx, stepy: Integer;
x, y: Integer;
maxx, maxy: Integer;
tsize: Integer; // tile size
gw, gh: Integer;
- lastGA: Integer = -1;
- ga: Integer = -1; // last used grid address
- ccidx: Integer = -1;
- curci: Integer = -1;
- cc: PGridCell = nil;
+ ccidx: Integer;
+ curci: Integer;
+ cc: PGridCell;
hasUntried: Boolean;
- f: Integer;
px: PBodyProxyRec;
lq: LongWord;
prevX, prevY: Integer;
lastDistSq, distSq: Integer;
wasHit: Boolean = false;
lastObj: ITP;
- lastWasInGrid: Boolean = false;
+ lastWasInGrid: Boolean;
+ tbcross: Boolean;
+ f: Integer;
begin
result := Default(ITP);
lastObj := Default(ITP);
tagmask := tagmask and TagFullMask;
if (tagmask = 0) then begin ex := x0; ey := y0; exit; end;
- // make coords (0,0)-based
minx := mMinX;
miny := mMinY;
- //Dec(x0, minx);
- //Dec(y0, miny);
- //Dec(x1, minx);
- //Dec(y1, miny);
dx := x1-x0;
dy := y1-y0;
end;
lq := mLastQuery;
+ // cache various things
tsize := mTileSize;
gw := mWidth;
gh := mHeight;
maxx := gw*tsize-1;
maxy := gh*tsize-1;
+
+ // setup distance and flags
lastDistSq := (x1-x0)*(x1-x0)+(y1-y0)*(y1-y0)+1;
lastWasInGrid := (x >= 0) and (y >= 0) and (x <= maxx) and (y <= maxy);
+ // setup starting tile ('cause we'll adjust tile vars only on tile edge crossing)
+ if lastWasInGrid then ccidx := mGrid[(y div tsize)*gw+(x div tsize)] else ccidx := -1;
+
+ // it is slightly faster this way
+ xerr := -d;
+ yerr := -d;
+
+ // now trace
for i := 1 to d do
begin
// prevs are always in map coords
prevX := x+minx;
prevY := y+miny;
// do one step
- xerr += dx; if (xerr >= d) then begin xerr -= d; x += incx; end;
- yerr += dy; if (yerr >= d) then begin yerr -= d; y += incy; end;
-
- // check for new tile
- if (x >= 0) and (y >= 0) and (x <= maxx) and (y <= maxy) then
+ xerr += dx;
+ yerr += dy;
+ // invariant: one of those always changed
+ if (xerr < 0) and (yerr < 0) then raise Exception.Create('internal bug in grid raycaster (0)');
+ if (xerr >= 0) then begin xerr -= d; x += incx; stepx := incx; end else stepx := 0;
+ if (yerr >= 0) then begin yerr -= d; y += incy; stepy := incy; end else stepy := 0;
+ // invariant: we always doing a step
+ if ((stepx or stepy) = 0) then raise Exception.Create('internal bug in grid raycaster (1)');
begin
- ga := (y div tsize)*gw+(x div tsize);
- if (lastGA <> ga) then
+ // check for crossing tile/grid boundary
+ if (x >= 0) and (y >= 0) and (x <= maxx) and (y <= maxy) then
+ begin
+ // we're still in grid
+ lastWasInGrid := true;
+ // check for tile edge crossing
+ if (stepx < 0) and ((x mod tsize) = tsize-1) then tbcross := true
+ else if (stepx > 0) and ((x mod tsize) = 0) then tbcross := true
+ else if (stepy < 0) and ((y mod tsize) = tsize-1) then tbcross := true
+ else if (stepy > 0) and ((y mod tsize) = 0) then tbcross := true
+ else tbcross := false;
+ // crossed tile edge?
+ if tbcross then
+ begin
+ // had something in the cell we're leaving?
+ if (ccidx <> -1) then
+ begin
+ // yes, signal cell completion
+ if assigned(cb) then
+ begin
+ if cb(nil, 0, x+minx, y+miny, prevX, prevY) then begin result := lastObj; exit; end;
+ end
+ else if wasHit then
+ begin
+ result := lastObj;
+ exit;
+ end;
+ end;
+ // setup new cell index
+ ccidx := mGrid[(y div tsize)*gw+(x div tsize)];
+ end;
+ end
+ else
begin
- // new cell
- lastWasInGrid := true; // do it here, yeah
- lastGA := ga;
- // had something in the cell we're leaving?
+ // out of grid, had something in the last processed cell?
if (ccidx <> -1) then
begin
// yes, signal cell completion
+ ccidx := -1;
if assigned(cb) then
begin
if cb(nil, 0, x+minx, y+miny, prevX, prevY) then begin result := lastObj; exit; end;
exit;
end;
end;
- // have something in this cell?
- ccidx := mGrid[lastGA];
- end;
- end
- else
- begin
- // out of grid, had something in the cell we're last processed?
- if (ccidx <> -1) then
- begin
- // yes, signal cell completion
- ccidx := -1;
- if assigned(cb) then
- begin
- if cb(nil, 0, x+minx, y+miny, prevX, prevY) then begin result := lastObj; exit; end;
- end
- else if wasHit then
- begin
- result := lastObj;
- exit;
- end;
+ if lastWasInGrid then exit; // oops, stepped out of the grid -- there is no way to return
end;
- if lastWasInGrid then exit; // oops, stepped out of the grid -- there is no way to return
- //lastWasInGrid := false;
end;
// has something to process in the current cell?
begin
// process cell
curci := ccidx;
- hasUntried := false; // this will be set to `true` if we have some panels we still want to process at the next step
- // convert coords to map
+ hasUntried := false; // this will be set to `true` if we have some proxies we still want to process at the next step
+ // convert coords to map (to avoid ajdusting coords inside the loop)
Inc(x, minx);
Inc(y, miny);
+ // process cell list
while (curci <> -1) do
begin
cc := @mCells[curci];
ptag := px.mTag;
if ((ptag and TagDisabled) = 0) and ((ptag and tagmask) <> 0) and (px.mQueryMark <> lq) then
begin
- // can we process this wall?
+ // can we process this proxy?
if (x >= px.mX) and (y >= px.mY) and (x < px.mX+px.mWidth) and (y < px.mY+px.mHeight) then
begin
px.mQueryMark := lq; // mark as processed
end
else
begin
- // this is possibly interesting wall, set "has more to check" flag
+ // this is possibly interesting proxy, set "has more to check" flag
hasUntried := true;
end;
end;