diff --git a/src/game/g_grid.pas b/src/game/g_grid.pas
index 2e7105e7729190fbe6e1062c834034beaa43de47..19c4d0d2ca8f31fc39170217693375c3d8cc5de2 100644 (file)
--- a/src/game/g_grid.pas
+++ b/src/game/g_grid.pas
{$INCLUDE ../shared/a_modes.inc}
{$IF DEFINED(D2F_DEBUG)}
{.$DEFINE D2F_DEBUG_RAYTRACE}
+ {.$DEFINE D2F_DEBUG_XXQ}
{$ENDIF}
unit g_grid;
// you can set enabled/disabled flag, tho (but iterator can still return objects disabled inside it)
// cb with `(nil)` will be called before processing new tile
// no callback: return `true` on the nearest hit
+ //WARNING: don't change tags in callbacks here!
function traceRay (const x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP; overload;
function traceRay (out ex, ey: Integer; const ax0, ay0, ax1, ay1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP;
//WARNING: don't modify grid while any query is in progress (no checks are made!)
// you can set enabled/disabled flag, tho (but iterator can still return objects disabled inside it)
// trace line along the grid, calling `cb` for all objects in passed cells, in no particular order
+ //WARNING: don't change tags in callbacks here!
function forEachAlongLine (const x0, y0, x1, y1: Integer; cb: TGridAlongQueryCB; tagmask: Integer=-1; log: Boolean=false): ITP;
// debug
for idx := 0 to High(mCells) do
begin
mCells[idx].bodies[0] := -1;
+ mCells[idx].bodies[GridCellBucketSize-1] := -1; // "has free room" flag
mCells[idx].next := idx+1;
end;
mCells[High(mCells)].next := -1; // last cell
var
g, f, cidx: Integer;
cc: PGridCell;
- //px: PBodyProxyRec;
begin
if (body < 0) or (body > High(mProxies)) or not assigned(cb) then exit;
for g := 0 to High(mGrid) do
while (cidx <> -1) do
begin
cc := @mCells[cidx];
- for f := 0 to High(TGridCell.bodies) do
+ for f := 0 to GridCellBucketSize-1 do
begin
if (cc.bodies[f] = -1) then break;
if (cc.bodies[f] = body) then cb((g mod mWidth)*mTileSize+mMinX, (g div mWidth)*mTileSize+mMinY);
- //px := @mProxies[cc.bodies[f]];
end;
// next cell
cidx := cc.next;
while (cidx <> -1) do
begin
cc := @mCells[cidx];
- for f := 0 to High(TGridCell.bodies) do
+ for f := 0 to GridCellBucketSize-1 do
begin
if (cc.bodies[f] = -1) then break;
if cb(mProxies[cc.bodies[f]].mObj, mProxies[cc.bodies[f]].mTag) then begin result := mProxies[cc.bodies[f]].mObj; exit; end;
for idx := mFreeCell to High(mCells) do
begin
mCells[idx].bodies[0] := -1;
- mCells[idx].bodies[High(TGridCell.bodies)] := -1; // 'has free room' flag
+ mCells[idx].bodies[GridCellBucketSize-1] := -1; // 'has free room' flag
mCells[idx].next := idx+1;
end;
mCells[High(mCells)].next := -1; // last cell
pc := @mCells[result];
mFreeCell := pc.next;
pc.next := -1;
- //pc.bodies[0] := -1;
Inc(mUsedCells);
//e_WriteLog(Format('grid: allocated new cell #%d (total: %d)', [result, mUsedCells]), MSG_NOTIFY);
end;
with mCells[idx] do
begin
bodies[0] := -1;
- bodies[High(TGridCell.bodies)] := -1; // 'has free room' flag
+ bodies[GridCellBucketSize-1] := -1; // 'has free room' flag
next := mFreeCell;
end;
mFreeCell := idx;
pc := mGrid[grida];
if (pc <> -1) then
begin
- pi := @mCells[pc];
- if (pi.bodies[High(TGridCell.bodies)] = -1) then
+ {$IF DEFINED(D2F_DEBUG)}
+ cidx := pc;
+ while (cidx <> -1) do
begin
- // can add here
- for f := 0 to High(TGridCell.bodies) do
+ pi := @mCells[cidx];
+ for f := 0 to GridCellBucketSize-1 do
begin
- if (pi.bodies[f] = -1) then
+ if (pi.bodies[f] = -1) then break;
+ if (pi.bodies[f] = bodyId) then raise Exception.Create('trying to insert already inserted proxy');
+ end;
+ cidx := pi.next;
+ end;
+ {$ENDIF}
+ cidx := pc;
+ while (cidx <> -1) do
+ begin
+ pi := @mCells[cidx];
+ // check "has room" flag
+ if (pi.bodies[GridCellBucketSize-1] = -1) then
+ begin
+ // can add here
+ for f := 0 to GridCellBucketSize-1 do
begin
- pi.bodies[f] := bodyId;
- if (f+1 < Length(TGridCell.bodies)) then pi.bodies[f+1] := -1;
- exit;
+ if (pi.bodies[f] = -1) then
+ begin
+ pi.bodies[f] := bodyId;
+ if (f+1 < GridCellBucketSize) then pi.bodies[f+1] := -1;
+ exit;
+ end;
end;
+ raise Exception.Create('internal error in grid inserter');
end;
- raise Exception.Create('internal error in grid inserter');
+ // no room, go to next cell in list (if there is any)
+ cidx := pi.next;
end;
+ // no room in cells, add new cell to list
end;
// either no room, or no cell at all
cidx := allocCell();
while (cidx <> -1) do
begin
pc := @mCells[cidx];
- for f := 0 to High(TGridCell.bodies) do
+ for f := 0 to GridCellBucketSize-1 do
begin
if (pc.bodies[f] = bodyId) then
begin
exit;
end;
// remove element from bucket
- for c := f to High(TGridCell.bodies)-1 do
+ for c := f to GridCellBucketSize-2 do
begin
pc.bodies[c] := pc.bodies[c+1];
if (pc.bodies[c] = -1) then break;
end;
- pc.bodies[High(TGridCell.bodies)] := -1; // "has free room" flag
+ pc.bodies[GridCellBucketSize-1] := -1; // "has free room" flag
exit;
end;
end;
end;
end;
-// absolutely not tested
procedure TBodyGridBase.removeInternal (body: TBodyProxyId);
var
px: PBodyProxyRec;
tagmask := tagmask and TagFullMask;
if (tagmask = 0) then exit;
+ {$IF DEFINED(D2F_DEBUG_XXQ)}
+ if (assigned(cb)) then e_WriteLog(Format('0: grid pointquery: (%d,%d)', [x, y]), MSG_NOTIFY);
+ {$ENDIF}
+
// make coords (0,0)-based
Dec(x, mMinX);
Dec(y, mMinY);
if (x < 0) or (y < 0) or (x >= mWidth*mTileSize) or (y >= mHeight*mTileSize) then exit;
curci := mGrid[(y div mTileSize)*mWidth+(x div mTileSize)];
+
+ {$IF DEFINED(D2F_DEBUG_XXQ)}
+ 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);
+ {$ENDIF}
+
// restore coords
Inc(x, mMinX);
Inc(y, mMinY);
end;
lq := mLastQuery;
+ {$IF DEFINED(D2F_DEBUG_XXQ)}
+ if (assigned(cb)) then e_WriteLog(Format('2: grid pointquery: (%d,%d); lq=%u', [x, y, lq]), MSG_NOTIFY);
+ {$ENDIF}
+
while (curci <> -1) do
begin
+ {$IF DEFINED(D2F_DEBUG_XXQ)}
+ if (assigned(cb)) then e_WriteLog(Format(' cell #%d', [curci]), MSG_NOTIFY);
+ {$ENDIF}
cc := @mCells[curci];
- for f := 0 to High(TGridCell.bodies) do
+ for f := 0 to GridCellBucketSize-1 do
begin
if (cc.bodies[f] = -1) then break;
px := @mProxies[cc.bodies[f]];
- ptag := px.mTag;
- if ((ptag and TagDisabled) = 0) and ((ptag and tagmask) <> 0) and (px.mQueryMark <> lq) then
+ {$IF DEFINED(D2F_DEBUG_XXQ)}
+ 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);
+ {$ENDIF}
+ // shit. has to do it this way, so i can change tag in callback
+ if (px.mQueryMark <> lq) then
begin
- if (x >= px.mX) and (y >= px.mY) and (x < px.mX+px.mWidth) and (y < px.mY+px.mHeight) then
+ px.mQueryMark := lq;
+ ptag := px.mTag;
+ if ((ptag and TagDisabled) = 0) and ((ptag and tagmask) <> 0) and
+ (x >= px.mX) and (y >= px.mY) and (x < px.mX+px.mWidth) and (y < px.mY+px.mHeight) then
begin
- px.mQueryMark := lq;
if assigned(cb) then
begin
if cb(px.mObj, ptag) then begin result := px.mObj; exit; end;
while (curci <> -1) do
begin
cc := @mCells[curci];
- for f := 0 to High(TGridCell.bodies) do
+ for f := 0 to GridCellBucketSize-1 do
begin
if (cc.bodies[f] = -1) then break;
px := @mProxies[cc.bodies[f]];
+ // shit. has to do it this way, so i can change tag in callback
+ if (px.mQueryMark = lq) then continue;
+ px.mQueryMark := lq;
ptag := px.mTag;
if (not allowDisabled) and ((ptag and TagDisabled) <> 0) then continue;
- if ((ptag and tagmask) <> 0) and (px.mQueryMark <> lq) then
- //if ((ptag and TagDisabled) = 0) and ((ptag and tagmask) <> 0) and (px.mQueryMark <> lq) then
- //if ( ((ptag and TagDisabled) = 0) = ignoreDisabled) and ((ptag and tagmask) <> 0) and (px.mQueryMark <> lq) then
+ if ((ptag and tagmask) = 0) then continue;
+ if (x0 >= px.mX+px.mWidth) or (y0 >= px.mY+px.mHeight) then continue;
+ if (x0+w <= px.mX) or (y0+h <= px.mY) then continue;
+ if assigned(cb) then
begin
- if (x0 >= px.mX+px.mWidth) or (y0 >= px.mY+px.mHeight) then continue;
- if (x0+w <= px.mX) or (y0+h <= px.mY) then continue;
- px.mQueryMark := lq;
- if assigned(cb) then
- begin
- if cb(px.mObj, ptag) then begin result := px.mObj; exit; end;
- end
- else
- begin
- result := px.mObj;
- exit;
- end;
+ if cb(px.mObj, ptag) then begin result := px.mObj; exit; end;
+ end
+ else
+ begin
+ result := px.mObj;
+ exit;
end;
end;
curci := cc.next;
while (curci <> -1) do
begin
cc := @mCells[curci];
- for f := 0 to High(TGridCell.bodies) do
+ for f := 0 to GridCellBucketSize-1 do
begin
if (cc.bodies[f] = -1) then break;
px := @mProxies[cc.bodies[f]];
while (curci <> -1) do
begin
cc := @mCells[curci];
- for f := 0 to High(TGridCell.bodies) do
+ for f := 0 to GridCellBucketSize-1 do
begin
if (cc.bodies[f] = -1) then break;
px := @mProxies[cc.bodies[f]];