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 sweep-and-prune broad phase
17 {$INCLUDE ../shared/a_modes.inc}
18 {$DEFINE SAP_CHECKS}
19 {$DEFINE SAP_ALWAYS_SORT}
20 {$DEFINE SAP_WALK_DEBUG}
21 {$DEFINE SAP_INSERT_DEBUG}
24 interface
26 type
29 type
34 private
41 private
53 public
70 private
71 type
74 public
78 public
93 public
94 type
95 TWalkCB = function (pidx: Integer; px: PSAPProxyRec): Boolean is nested; // return `true` to stop
97 public
103 public
115 private
124 private
125 function allocProxy (aX, aY, aWidth, aHeight: Integer; aObj: TObject; aTag: Integer): TSAPProxy;
131 //procedure remove (body: TSAPProxy);
133 public
137 function insertBody (aObj: TObject; ax, ay, aWidth, aHeight: Integer; aTag: Integer=0): TSAPProxy;
138 //procedure removeBody (aObj: TSAPProxy); // WARNING! this WILL destroy proxy!
140 //procedure moveBody (body: TSAPProxy; dx, dy: Integer);
141 //procedure resizeBody (body: TSAPProxy; sx, sy: Integer);
142 //procedure moveResizeBody (body: TSAPProxy; dx, dy, sx, sy: Integer);
146 //function getProxyForBody (aObj: TObject; x, y, w, h: Integer): TSAPProxy;
148 // call these functions before massive update (it may, or may be not faster)
156 implementation
158 uses
162 // ////////////////////////////////////////////////////////////////////////// //
164 begin
181 function TSAPProxyRec.getidx (ismin: Boolean; iidx: Integer): Integer; begin result := mIdx[ismin, iidx]; end;
182 procedure TSAPProxyRec.setidx (ismin: Boolean; iidx: Integer; v: Integer); begin mIdx[ismin, iidx] := v; end;
188 // ////////////////////////////////////////////////////////////////////////// //
189 function TSweepAndPrune.TIntervalRec.getismin (): Boolean; begin result := ((mpidx and $80000000) <> 0); end;
190 procedure TSweepAndPrune.TIntervalRec.setismin (v: Boolean); begin if (v) then mpidx := mpidx or $80000000 else mpidx := mpidx and $7fffffff; end;
192 function TSweepAndPrune.TIntervalRec.getpidx (): Integer; begin result := Integer(mpidx and $7fffffff); end;
193 procedure TSweepAndPrune.TIntervalRec.setpidx (v: Integer); begin mpidx := (v and $7fffffff) or (mpidx and $80000000); end;
197 var
199 begin
205 // v0 MUST be <= v1!
207 begin
212 // ////////////////////////////////////////////////////////////////////////// //
214 begin
223 begin
230 var
236 begin
242 {$IFDEF SAP_CHECKS}
244 begin
246 begin
247 e_WriteLog(Format('FUCKUP: interval %d; i=%d; val=%d; ismin=%d; got=%d', [iidx, i, arr[i].val, Integer(arr[i].ismin), pxa[arr[i].pidx].idx[arr[i].ismin, iidx]]), MSG_NOTIFY);
252 {$ENDIF}
254 begin
257 begin
259 begin
263 begin
274 // check
275 {$IFDEF SAP_CHECKS}
277 begin
279 begin
281 if (arr[i-1].val > arr[i].val) then begin dump(); raise Exception.Create('sorting fuckup (3)'); end;
283 if (pxa[arr[i].pidx].idx[arr[i].ismin, iidx] <> i) then begin dump(); raise Exception.Create('sorting fuckup (4)'); end;
285 {$ENDIF}
290 var
294 begin
296 // get min/max
298 begin
301 end
302 else
303 begin
307 // append min
310 {$IFDEF SAP_INSERT_DEBUG}
311 e_WriteLog(Format('inserting proxy %d into interval %d; v0=%d; i=%d', [apidx, myidx, v0, i]), MSG_NOTIFY);
312 {$ENDIF}
318 // append max
320 {$IFDEF SAP_INSERT_DEBUG}
321 e_WriteLog(Format('inserting proxy %d into interval %d; v1=%d; i=%d', [apidx, myidx, v1, i]), MSG_NOTIFY);
322 {$ENDIF}
328 // done
330 {$IFDEF SAP_CHECKS}
332 {$ENDIF}
337 var
343 begin
351 {$IFDEF SAP_WALK_DEBUG}
352 e_WriteLog(Format('walking interval #%d; v0=%d; v1=%d; len=%d', [myidx, v0, v1, len]), MSG_NOTIFY);
353 {$ENDIF}
356 begin
357 // one element
359 end
360 else
361 begin
362 // do search
366 begin
372 //return (cmpfn(lines+i) == 0 ? i : -1);
373 {$IFDEF SAP_WALK_DEBUG}
374 e_WriteLog(Format(' binsearch interval #%d; i=%d; len=%d; isect=%d', [myidx, i, len, Integer(arr[i].inside(v0, v1))]), MSG_NOTIFY);
375 {$ENDIF}
377 begin
379 if (i > 0) and arr[i-1].inside(v0, v1) then begin Dec(i); {$IFDEF SAP_WALK_DEBUG}e_WriteLog(' bin: up', MSG_NOTIFY);{$ENDIF} end
380 else if (i+1 < len) and arr[i+1].inside(v0, v1) then begin Inc(i); {$IFDEF SAP_WALK_DEBUG}e_WriteLog(' bin: down', MSG_NOTIFY);{$ENDIF} end
383 // find first interval
387 {$IFDEF SAP_WALK_DEBUG}
389 e_WriteLog(Format(' start interval #%d; i=%d; v0=%d; v1=%d; len=%d; val=%d; ismin=%d', [myidx, i, v0, v1, len, arr[i].val, Integer(arr[i].ismin)]), MSG_NOTIFY);
390 {$ENDIF}
392 // walk
394 begin
401 {$IFDEF SAP_WALK_DEBUG}
404 e_WriteLog(Format(' end interval #%d; i=%d; v0=%d; v1=%d; len=%d; val=%d; ismin=%d', [myidx, i, v0, v1, len, arr[i].val, Integer(arr[i].ismin)]), MSG_NOTIFY);
405 {$ENDIF}
410 var
413 begin
416 begin
418 e_WriteLog(Format(' pi #%d; val=%d; ismin=%d; pidx=%d; px0=%d; py0=%d; px1=%d; py1=%d', [idx, pi.val, Integer(pi.ismin), pi.pidx, mProxies[pi.pidx].x0, mProxies[pi.pidx].y0, mProxies[pi.pidx].x1, mProxies[pi.pidx].y1]), MSG_NOTIFY);
423 // ////////////////////////////////////////////////////////////////////////// //
425 var
427 begin
430 // init proxies
433 begin
441 // init intervals
443 begin
457 var
459 begin
467 begin
468 e_WriteLog(Format('used intervals: [%d;%d]; max proxies allocated: %d; proxies used: %d', [mIntrs[0].used, mIntrs[1].used, mProxyMaxCount, mProxyCount]), MSG_NOTIFY);
475 begin
481 begin
483 begin
490 function TSweepAndPrune.allocProxy (aX, aY, aWidth, aHeight: Integer; aObj: TObject; aTag: Integer): TSAPProxy;
491 var
494 begin
496 begin
497 // no free proxies, resize list
503 // fix intervals cache
506 // get one from list
511 // add to used list
516 // statistics
523 var
525 begin
527 if (mProxyCount = 0) then raise Exception.Create('wutafuuuuu in grid (no allocated proxies, what i should free now?)');
528 // add to free list
541 begin
548 begin
552 {$IFDEF SAP_ALWAYS_SORT}
554 {$ELSE}
556 {$ENDIF}
560 function TSweepAndPrune.insertBody (aObj: TObject; aX, aY, aWidth, aHeight: Integer; aTag: Integer=0): TSAPProxy;
561 begin
569 var
573 begin
575 {$IFDEF SAP_WALK_DEBUG}
576 e_WriteLog(Format(' walker0: pidx=%d; x0=%d; y0=%d; x1=%d; y1=%d; lq=%d', [pidx, px.x0, px.y0, px.x1, px.y1, lq]), MSG_NOTIFY);
577 {$ENDIF}
582 begin
583 {$IFDEF SAP_WALK_DEBUG}
584 e_WriteLog(Format(' walker1: pidx=%d; x0=%d; y0=%d; x1=%d; y1=%d; lq=%d', [pidx, px.x0, px.y0, px.x1, px.y1, px.mQueryMark]), MSG_NOTIFY);
585 {$ENDIF}
587 begin
589 {$IFDEF SAP_WALK_DEBUG}
590 e_WriteLog(Format(' CB walker1: pidx=%d; x0=%d; y0=%d; x1=%d; y1=%d; lq=%d; res=%d', [pidx, px.x0, px.y0, px.x1, px.y1, px.mQueryMark, Integer(result)]), MSG_NOTIFY);
591 {$ENDIF}
592 end
593 else
594 begin
599 var
601 begin
606 // increase query counter
609 begin
610 // just in case of overflow
615 (*
616 * the algorithm is simple:
617 * find start for first interval (binary search will do)
618 * walk the interval, marking proxies with mLastQuery
619 * find start for second interval (binary search will do)
620 * walk the interval, returning proxies marked with mLastQuery
621 *)