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 {$DEFINE grid_use_buckets}
21 interface
24 type
28 public
29 type TGridQueryCB = function (obj: ITP; tag: Integer): Boolean is nested; // return `true` to stop
30 type TGridRayQueryCB = function (obj: ITP; tag: Integer; x, y, prevx, prevy: Integer): Boolean is nested; // return `true` to stop
32 private
33 const
37 private
38 type
41 private
48 private
54 {$IFDEF grid_use_buckets}
56 {$ELSE}
58 {$ENDIF}
64 private
83 private
99 public
100 constructor Create (aMinPixX, aMinPixY, aPixWidth, aPixHeight: Integer; aTileSize: Integer=GridDefaultTileSize);
103 function insertBody (aObj: ITP; ax, ay, aWidth, aHeight: Integer; aTag: Integer=0): TBodyProxyId;
110 //WARNING: can't do recursive queries
113 //WARNING: can't do recursive queries
114 // cb with `(nil)` will be called before processing new tile
115 function traceRay (x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): Boolean; overload;
121 implementation
123 uses
127 // ////////////////////////////////////////////////////////////////////////// //
128 procedure TBodyGridBase.TBodyProxyRec.setup (aX, aY, aWidth, aHeight: Integer; aObj: ITP; aTag: Integer);
129 begin
141 // ////////////////////////////////////////////////////////////////////////// //
142 constructor TBodyGridBase.Create (aMinPixX, aMinPixY, aPixWidth, aPixHeight: Integer; aTileSize: Integer=GridDefaultTileSize);
143 var
145 begin
159 // init free list
161 begin
162 {$IFDEF grid_use_buckets}
164 {$ELSE}
166 {$ENDIF}
170 // init grid
172 // init proxies
184 e_WriteLog(Format('created grid with size: %dx%d (tile size: %d); pix: %dx%d', [mWidth, mHeight, mTileSize, mWidth*mTileSize, mHeight*mTileSize]), MSG_NOTIFY);
189 begin
198 var
200 begin
203 begin
207 begin
213 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);
218 var
220 begin
222 begin
223 // no free cells, want more
227 begin
228 {$IFDEF grid_use_buckets}
230 {$ELSE}
232 {$ENDIF}
241 //e_WriteLog(Format('grid: allocated new cell #%d (total: %d)', [result, mUsedCells]), MSG_NOTIFY);
246 begin
248 begin
249 //if mCells[idx].body = -1 then exit; // the thing that should not be
250 //mCells[idx].body := -1;
258 function TBodyGridBase.allocProxy (aX, aY, aWidth, aHeight: Integer; aObj: ITP; aTag: Integer): TBodyProxyId;
259 var
262 begin
264 begin
265 // no free proxies, resize list
272 // get one from list
277 // add to used list
279 // statistics
285 begin
287 if (mProxyCount = 0) then raise Exception.Create('wutafuuuuu in grid (no allocated proxies, what i should free now?)');
288 // add to free list
297 var
299 begin
302 // fix coords
305 // go on
309 begin
313 begin
322 // ////////////////////////////////////////////////////////////////////////// //
323 function TBodyGridBase.traceRay (x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): Boolean;
324 var
344 begin
349 // make coords (0,0)-based
373 // increase query counter
376 begin
377 // just in case of overflow
390 begin
397 begin
400 begin
401 // new cell
405 begin
410 end
411 else
412 begin
417 begin
421 begin
424 begin
428 begin
429 if (x+minx >= px.mX) and (y+miny >= px.mY) and (x+minx < px.mX+px.mWidth) and (y+miny < px.mY+px.mHeight) then
430 begin
434 end
435 else
436 begin
450 var
453 {$IFDEF grid_use_buckets}
456 {$ENDIF}
457 begin
459 // add body to the given grid cell
461 {$IFDEF grid_use_buckets}
463 begin
467 begin
469 begin
470 // can add here
473 exit;
477 // either no room, or no cell at all
483 {$ELSE}
485 //e_WriteLog(Format(' 01: allocated cell for grid coords (%d,%d), body coords:(%d,%d): #%d', [gx, gy, dx, dy, cidx]), MSG_NOTIFY);
489 {$ENDIF}
494 var
496 begin
505 var
508 begin
510 // find and remove cell
514 begin
516 {$IFDEF grid_use_buckets}
520 begin
522 begin
523 // i found her!
525 begin
526 // this cell contains no elements, remove it
530 end
531 else
532 begin
533 // remove element from bucket
536 begin
547 {$ELSE}
549 begin
554 {$ENDIF}
561 // absolutely not tested
563 var
565 begin
573 function TBodyGridBase.insertBody (aObj: ITP; aX, aY, aWidth, aHeight: Integer; aTag: Integer=0): TBodyProxyId;
574 begin
584 begin
595 var
597 begin
613 begin
618 begin
624 var
627 {$IFDEF grid_use_buckets}
630 {$ENDIF}
631 begin
635 begin
636 {$IFDEF grid_use_buckets}
639 begin
643 begin
644 //e_WriteLog(Format(' query #%d body hit: (%d,%d)-(%dx%d) tag:%d', [mLastQuery, mCells[idx].body.mX, mCells[idx].body.mY, mCells[idx].body.mWidth, mCells[idx].body.mHeight, mCells[idx].body.mTag]), MSG_NOTIFY);
650 {$ELSE}
652 begin
655 begin
656 //e_WriteLog(Format(' query #%d body hit: (%d,%d)-(%dx%d) tag:%d', [mLastQuery, mCells[idx].body.mX, mCells[idx].body.mY, mCells[idx].body.mWidth, mCells[idx].body.mHeight, mCells[idx].body.mTag]), MSG_NOTIFY);
662 {$ENDIF}
666 function TBodyGridBase.forEachInAABB (x, y, w, h: Integer; cb: TGridQueryCB; tagmask: Integer=-1): Boolean;
667 var
669 begin
676 // increase query counter
679 begin
680 // just in case of overflow
684 //e_WriteLog(Format('grid: query #%d: (%d,%d)-(%dx%d)', [mLastQuery, minx, miny, maxx, maxy]), MSG_NOTIFY);