diff --git a/src/game/g_grid.pas b/src/game/g_grid.pas
index 81f19c12af6fbfc64072bbd7dbb35510ef8cf6b2..b1b157f8d3c685b3b65d457ed5620051d2bbb4dc 100644 (file)
--- a/src/game/g_grid.pas
+++ b/src/game/g_grid.pas
*)
// universal spatial grid
{$INCLUDE ../shared/a_modes.inc}
+{$IF DEFINED(D2F_DEBUG)}
+ {.$DEFINE D2F_DEBUG_RAYTRACE}
+{$ENDIF}
unit g_grid;
interface
public
dbgShowTraceLog: Boolean;
+ {$IF DEFINED(D2F_DEBUG)}
+ dbgRayTraceTileHitCB: TCellQueryCB;
+ {$ENDIF}
private
function allocCell (): Integer;
// 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
- function traceRay (x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP; overload;
- function traceRay (out ex, ey: Integer; ax0, ay0, ax1, ay1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP;
+ 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
- function forEachAlongLine (x0, y0, x1, y1: Integer; cb: TGridAlongQueryCB; tagmask: Integer=-1; log: Boolean=false): ITP;
+ function forEachAlongLine (const x0, y0, x1, y1: Integer; cb: TGridAlongQueryCB; tagmask: Integer=-1; log: Boolean=false): ITP;
// debug
procedure forEachBodyCell (body: TBodyProxyId; cb: TCellQueryCB);
idx: Integer;
begin
dbgShowTraceLog := false;
+ {$IF DEFINED(D2F_DEBUG)}
+ dbgRayTraceTileHitCB := nil;
+ {$ENDIF}
{
if aTileSize < 1 then aTileSize := 1;
if aTileSize > 8192 then aTileSize := 8192; // arbitrary limit
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;
if (pc <> -1) then
begin
pi := @mCells[pc];
- if (pi.bodies[High(TGridCell.bodies)] = -1) then
+ // check "has room" flag
+ if (pi.bodies[GridCellBucketSize-1] = -1) then
begin
// can add here
- for f := 0 to High(TGridCell.bodies) do
+ for f := 0 to GridCellBucketSize-1 do
begin
if (pi.bodies[f] = -1) then
begin
pi.bodies[f] := bodyId;
- if (f+1 < Length(TGridCell.bodies)) then pi.bodies[f+1] := -1;
+ if (f+1 < GridCellBucketSize) then pi.bodies[f+1] := -1;
exit;
end;
end;
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;
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]];
// ////////////////////////////////////////////////////////////////////////// //
// no callback: return `true` on the nearest hit
-function TBodyGridBase.traceRay (x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP;
+function TBodyGridBase.traceRay (const x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP;
var
ex, ey: Integer;
begin
// no callback: return `true` on the nearest hit
// you are not supposed to understand this
-function TBodyGridBase.traceRay (out ex, ey: Integer; ax0, ay0, ax1, ay1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP;
+function TBodyGridBase.traceRay (out ex, ey: Integer; const ax0, ay0, ax1, ay1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP;
const
tsize = mTileSize;
var
maxx := gw*tsize-1;
maxy := gh*tsize-1;
+ {$IF DEFINED(D2F_DEBUG_RAYTRACE)}
+ 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);
+ {$ENDIF}
+
x0 := ax0;
y0 := ay0;
x1 := ax1;
if (xd = term) then exit;
{$IF DEFINED(D2F_DEBUG)}
- if (xptr^ < 0) or (yptr^ < 0) or (xptr^ >= gw*tsize) and (yptr^ > mHeight*tsize) then raise Exception.Create('raycaster internal error (0)');
+ if (xptr^ < 0) or (yptr^ < 0) or (xptr^ >= gw*tsize) and (yptr^ >= gh*tsize) then raise Exception.Create('raycaster internal error (0)');
{$ENDIF}
+ lastGA := (yptr^ div tsize)*gw+(xptr^ div tsize);
+ ccidx := mGrid[lastGA];
- //if (dbgShowTraceLog) then e_WriteLog(Format('raycast start: (%d,%d)-(%d,%d); xptr^=%d; yptr^=%d', [ax0, ay0, ax1, ay1, xptr^, yptr^]), MSG_NOTIFY);
+ {$IF DEFINED(D2F_DEBUG_RAYTRACE)}
+ //if assigned(dbgRayTraceTileHitCB) then e_WriteLog('1:TRACING!', MSG_NOTIFY);
+ {$ENDIF}
- // restore query coords
- Inc(ax0, minx);
- Inc(ay0, miny);
- //Inc(ax1, minx);
- //Inc(ay1, miny);
+ {$IF DEFINED(D2F_DEBUG_RAYTRACE)}
+ if assigned(dbgRayTraceTileHitCB) then dbgRayTraceTileHitCB((xptr^ div tsize*tsize)+minx, (yptr^ div tsize*tsize)+miny);
+ {$ENDIF}
+
+ //if (dbgShowTraceLog) then e_WriteLog(Format('raycast start: (%d,%d)-(%d,%d); xptr^=%d; yptr^=%d', [ax0, ay0, ax1, ay1, xptr^, yptr^]), MSG_NOTIFY);
// increase query counter
Inc(mLastQuery);
begin
// check cell(s)
{$IF DEFINED(D2F_DEBUG)}
- if (xptr^ < 0) or (yptr^ < 0) or (xptr^ >= gw*tsize) and (yptr^ > mHeight*tsize) then raise Exception.Create('raycaster internal error (0)');
+ if (xptr^ < 0) or (yptr^ < 0) or (xptr^ >= gw*tsize) and (yptr^ >= gh*tsize) then raise Exception.Create('raycaster internal error (0)');
{$ENDIF}
// new tile?
ga := (yptr^ div tsize)*gw+(xptr^ div tsize);
if (ga <> lastGA) then
begin
// yes
+ {$IF DEFINED(D2F_DEBUG)}
+ if assigned(dbgRayTraceTileHitCB) then dbgRayTraceTileHitCB((xptr^ div tsize*tsize)+minx, (yptr^ div tsize*tsize)+miny);
+ {$ENDIF}
if (ccidx <> -1) then
begin
// signal cell completion
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]];
ey := prevy;
exit;
end;
+ (*
+ {$IF DEFINED(D2F_DEBUG_RAYTRACE)}
+ distSq := distanceSq(ax0, ay0, prevx, prevy);
+ 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);
+ if (distSq < lastDistSq) then
+ begin
+ wasHit := true;
+ lastDistSq := distSq;
+ ex := prevx;
+ ey := prevy;
+ lastObj := px.mObj;
+ end;
+ {$ENDIF}
+ *)
end
else
begin
// remember this hitpoint if it is nearer than an old one
distSq := distanceSq(ax0, ay0, prevx, prevy);
+ {$IF DEFINED(D2F_DEBUG_RAYTRACE)}
+ 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);
+ {$ENDIF}
if (distSq < lastDistSq) then
begin
wasHit := true;
// ////////////////////////////////////////////////////////////////////////// //
//FIXME! optimize this with real tile walking
-function TBodyGridBase.forEachAlongLine (x0, y0, x1, y1: Integer; cb: TGridAlongQueryCB; tagmask: Integer=-1; log: Boolean=false): ITP;
+function TBodyGridBase.forEachAlongLine (const x0, y0, x1, y1: Integer; cb: TGridAlongQueryCB; tagmask: Integer=-1; log: Boolean=false): ITP;
const
tsize = mTileSize;
var
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]];