X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_grid.pas;h=2d5d6323f00f2f0ae41d6728d073ea66d3f865cc;hb=a4f25c41dfd783a925aa2dab4b9b84753d5c3f18;hp=b4b0e32795cddfaa38864fa8154c2f260e903328;hpb=6dd20e00616144332edbc3da83d2df181486150b;p=d2df-sdl.git diff --git a/src/game/g_grid.pas b/src/game/g_grid.pas index b4b0e32..2d5d632 100644 --- a/src/game/g_grid.pas +++ b/src/game/g_grid.pas @@ -20,7 +20,7 @@ {.$DEFINE D2F_DEBUG_XXQ} {.$DEFINE D2F_DEBUG_MOVER} {$ENDIF} -{$DEFINE GRID_USE_ORTHO_ACCEL} +{.$DEFINE GRID_USE_ORTHO_ACCEL} unit g_grid; interface @@ -71,6 +71,7 @@ type property height: Integer read mHeight; property tag: Integer read getTag write setTag; property enabled: Boolean read getEnabled write setEnabled; + property obj: ITP read mObj; end; private @@ -81,20 +82,36 @@ type next: Integer; // in this cell; index in mCells end; + TCellArray = array of TGridCell; + TGridInternalCB = function (grida: Integer; bodyId: TBodyProxyId): Boolean of object; // return `true` to stop private //mTileSize: Integer; const mTileSize = GridDefaultTileSize; + type TGetProxyFn = function (pxidx: Integer): PBodyProxyRec of object; public const tileSize = mTileSize; + type + TAtPointEnumerator = record + private + mCells: TCellArray; + curidx, curbki: Integer; + getpx: TGetProxyFn; + public + constructor Create (acells: TCellArray; aidx: Integer; agetpx: TGetProxyFn); + function MoveNext (): Boolean; inline; + function getCurrent (): PBodyProxyRec; inline; + property Current: PBodyProxyRec read getCurrent; + end; + private mMinX, mMinY: Integer; // so grids can start at any origin mWidth, mHeight: Integer; // in tiles mGrid: array of Integer; // mWidth*mHeight, index in mCells - mCells: array of TGridCell; // cell pool + mCells: TCellArray; // cell pool mFreeCell: Integer; // first free cell index or -1 mLastQuery: LongWord; mUsedCells: Integer; @@ -102,6 +119,7 @@ type mProxyFree: TBodyProxyId; // free mProxyCount: Integer; // currently used mProxyMaxCount: Integer; + mInQuery: Boolean; public dbgShowTraceLog: Boolean; @@ -160,6 +178,8 @@ type // no callback: return object on the first hit or nil function forEachAtPoint (x, y: Integer; cb: TGridQueryCB; tagmask: Integer=-1; exittag: PInteger=nil): ITP; + function atCellInPoint (x, y: Integer): TAtPointEnumerator; + //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) // cb with `(nil)` will be called before processing new tile @@ -419,6 +439,40 @@ begin end; +// ////////////////////////////////////////////////////////////////////////// // +constructor TBodyGridBase.TAtPointEnumerator.Create (acells: TCellArray; aidx: Integer; agetpx: TGetProxyFn); +begin + mCells := acells; + curidx := aidx; + curbki := -1; + getpx := agetpx; +end; + + +function TBodyGridBase.TAtPointEnumerator.MoveNext (): Boolean; inline; +begin + while (curidx <> -1) do + begin + while (curbki < GridCellBucketSize) do + begin + Inc(curbki); + if (mCells[curidx].bodies[curbki] = -1) then break; + result := true; + exit; + end; + curidx := mCells[curidx].next; + curbki := -1; + end; + result := false; +end; + + +function TBodyGridBase.TAtPointEnumerator.getCurrent (): PBodyProxyRec; inline; +begin + result := getpx(mCells[curidx].bodies[curbki]); +end; + + // ////////////////////////////////////////////////////////////////////////// // constructor TBodyGridBase.Create (aMinPixX, aMinPixY, aPixWidth, aPixHeight: Integer{; aTileSize: Integer=GridDefaultTileSize}); var @@ -1107,6 +1161,18 @@ begin end; +// ////////////////////////////////////////////////////////////////////////// // +function TBodyGridBase.atCellInPoint (x, y: Integer): TAtPointEnumerator; +var + cidx: Integer = -1; +begin + Dec(x, mMinX); + Dec(y, mMinY); + if (x >= 0) and (y >= 0) and (x < mWidth*mTileSize) and (y < mHeight*mTileSize) then cidx := mGrid[(y div mTileSize)*mWidth+(x div mTileSize)]; + result := TAtPointEnumerator.Create(mCells, cidx, getProxyById); +end; + + // ////////////////////////////////////////////////////////////////////////// // // no callback: return `true` on the first hit function TBodyGridBase.forEachAtPoint (x, y: Integer; cb: TGridQueryCB; tagmask: Integer=-1; exittag: PInteger=nil): ITP; @@ -1235,6 +1301,9 @@ begin if (x+w <= 0) or (y+h <= 0) then exit; if (x >= gw*tsize) or (y >= mHeight*tsize) then exit; + if mInQuery then raise Exception.Create('recursive queries aren''t supported'); + mInQuery := true; + // increase query counter Inc(mLastQuery); if (mLastQuery = 0) then @@ -1274,11 +1343,12 @@ begin if (x0+w <= px.mX) or (y0+h <= px.mY) then continue; if assigned(cb) then begin - if cb(px.mObj, ptag) then begin result := px.mObj; exit; end; + if cb(px.mObj, ptag) then begin result := px.mObj; mInQuery := false; exit; end; end else begin result := px.mObj; + mInQuery := false; exit; end; end; @@ -1286,6 +1356,8 @@ begin end; end; end; + + mInQuery := false; end; @@ -1552,6 +1624,9 @@ begin //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 mInQuery then raise Exception.Create('recursive queries aren''t supported'); + mInQuery := true; + // increase query counter Inc(mLastQuery); if (mLastQuery = 0) then @@ -1581,16 +1656,6 @@ begin y := yptr^+miny; //prevx := x; //prevy := y; - {$IF DEFINED(D2F_DEBUG)} - if hopt then - begin - if (y <> ay0) then raise Exception.Create('htrace fatal internal error'); - end - else - begin - if (x <> ax0) then raise Exception.Create('vtrace fatal internal error'); - end; - {$ENDIF} while (wklen > 0) do begin {$IF DEFINED(D2F_DEBUG)} @@ -1629,6 +1694,7 @@ begin result := px.mObj; ex := x; ey := y; + mInQuery := false; exit; end; end @@ -1643,6 +1709,7 @@ begin ex := x; ey := y; result := px.mObj; + mInQuery := false; exit; end; end; @@ -1697,6 +1764,7 @@ begin result := px.mObj; ex := prevx; ey := prevy; + mInQuery := false; exit; end; end @@ -1720,8 +1788,8 @@ begin // next cell ccidx := cc.next; end; - if wasHit and not assigned(cb) then begin result := lastObj; exit; end; - if assigned(cb) and cb(nil, 0, x, y, x, y) then begin result := lastObj; exit; end; + if wasHit and not assigned(cb) then begin result := lastObj; mInQuery := false; exit; end; + if assigned(cb) and cb(nil, 0, x, y, x, y) then begin result := lastObj; mInQuery := false; exit; end; end; // skip to next tile if hopt then @@ -1778,6 +1846,7 @@ begin end; // we can travel less than one cell if wasHit and not assigned(cb) then result := lastObj else begin ex := ax1; ey := ay1; end; + mInQuery := false; exit; end; {$ENDIF} @@ -1811,11 +1880,12 @@ begin // signal cell completion if assigned(cb) then begin - if cb(nil, 0, xptr^+minx, yptr^+miny, prevx, prevy) then begin result := lastObj; exit; end; + if cb(nil, 0, xptr^+minx, yptr^+miny, prevx, prevy) then begin result := lastObj; mInQuery := false; exit; end; end else if wasHit then begin result := lastObj; + mInQuery := false; exit; end; end; @@ -1853,6 +1923,7 @@ begin result := px.mObj; ex := prevx; ey := prevy; + mInQuery := false; exit; end; end @@ -1890,11 +1961,12 @@ begin ccidx := -1; if assigned(cb) then begin - if cb(nil, 0, x, y, prevx, prevy) then begin result := lastObj; exit; end; + if cb(nil, 0, x, y, prevx, prevy) then begin result := lastObj; mInQuery := false; exit; end; end else if wasHit then begin result := lastObj; + mInQuery := false; exit; end; end; @@ -1933,6 +2005,8 @@ begin ex := ax1; // why not? ey := ay1; // why not? end; + + mInQuery := false; end; @@ -1955,7 +2029,7 @@ var temp: Integer; ccidx, curci: Integer; lastGA: Integer = -1; - ga, x, y: Integer; + ga: Integer; gw, gh, minx, miny, maxx, maxy: Integer; cc: PGridCell; px: PBodyProxyRec; @@ -2143,6 +2217,9 @@ begin //lastGA := (yptr^ div tsize)*gw+(xptr^ div tsize); //ccidx := mGrid[lastGA]; + if mInQuery then raise Exception.Create('recursive queries aren''t supported'); + mInQuery := true; + // increase query counter Inc(mLastQuery); if (mLastQuery = 0) then @@ -2167,23 +2244,10 @@ begin if dbgShowTraceLog then e_LogWritefln('optimized htrace; wklen=%d', [wklen]); {$ENDIF} ga := (yptr^ div tsize)*gw+(xptr^ div tsize); - // one of those will never change - x := xptr^+minx; - y := yptr^+miny; - {$IF DEFINED(D2F_DEBUG)} - if hopt then - begin - if (y <> ay0) then raise Exception.Create('htrace fatal internal error'); - end - else - begin - if (x <> ax0) then raise Exception.Create('vtrace fatal internal error'); - end; - {$ENDIF} while (wklen > 0) do begin {$IF DEFINED(D2F_DEBUG)} - if dbgShowTraceLog then e_LogWritefln(' htrace; ga=%d; x=%d, y=%d; y=%d; y=%d', [ga, xptr^+minx, yptr^+miny, y, ay0]); + if dbgShowTraceLog then e_LogWritefln(' htrace; ga=%d; x=%d, y=%d; ay0=%d', [ga, xptr^+minx, yptr^+miny, ay0]); {$ENDIF} // new tile? if (ga <> lastGA) then @@ -2191,7 +2255,6 @@ begin lastGA := ga; ccidx := mGrid[lastGA]; // convert coords to map (to avoid ajdusting coords inside the loop) - if hopt then x := xptr^+minx else y := yptr^+miny; while (ccidx <> -1) do begin cc := @mCells[ccidx]; @@ -2205,11 +2268,12 @@ begin px.mQueryMark := lq; // mark as processed if assigned(cb) then begin - if cb(px.mObj, ptag) then begin result := px.mObj; exit; end; + if cb(px.mObj, ptag) then begin result := px.mObj; mInQuery := false; exit; end; end else begin result := px.mObj; + mInQuery := false; exit; end; end; @@ -2271,6 +2335,7 @@ begin end; Dec(wklen, wkstep); end; + mInQuery := false; exit; end; {$ENDIF} @@ -2306,9 +2371,6 @@ begin begin // process cell curci := ccidx; - // convert coords to map (to avoid ajdusting coords inside the loop) - x := xptr^+minx; - y := yptr^+miny; // process cell list while (curci <> -1) do begin @@ -2323,11 +2385,12 @@ begin px.mQueryMark := lq; // mark as processed if assigned(cb) then begin - if cb(px.mObj, ptag) then begin result := px.mObj; exit; end; + if cb(px.mObj, ptag) then begin result := px.mObj; mInQuery := false; exit; end; end else begin result := px.mObj; + mInQuery := false; exit; end; end; @@ -2357,6 +2420,8 @@ begin if (e >= 0) then begin yd += sty; e -= dx2; end else e += dy2; xd += stx; end; + + mInQuery := false; end;