summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 58b15f7)
raw | patch | inline | side by side (parent: 58b15f7)
author | Ketmar Dark <ketmar@ketmar.no-ip.org> | |
Mon, 21 Aug 2017 04:25:23 +0000 (07:25 +0300) | ||
committer | Ketmar Dark <ketmar@ketmar.no-ip.org> | |
Mon, 21 Aug 2017 04:39:57 +0000 (07:39 +0300) |
src/game/z_aabbtree.pas | patch | blob | history |
index 298fa34f4775b23f2875ceb0789d261721bc37c4..79d9d8a62eeb8d58855e7e9e123c020e87fb093e 100644 (file)
--- a/src/game/z_aabbtree.pas
+++ b/src/game/z_aabbtree.pas
dist: Single; // <0: nothing was hit
flesh: TTreeFlesh;
+ constructor Create (fuckyoufpc: Boolean);
procedure reset (); inline;
function valid (): Boolean; inline;
end;
curbx, curby: Single;
dirx, diry: Single;
sqcb: TSegQueryCallback;
+ vstack: array of Integer; // for `visit()`
+ vstused: Integer; // to support recursive queries
function checkerAABB (node: PTreeNode): Boolean;
function checkerPoint (node: PTreeNode): Boolean;
// ////////////////////////////////////////////////////////////////////////// //
+constructor TDynAABBTreeBase.TSegmentQueryResult.Create (fuckyoufpc: Boolean); begin dist := -1; flesh := Default(ITP); end;
procedure TDynAABBTreeBase.TSegmentQueryResult.reset (); inline; begin dist := -1; flesh := Default(ITP); end;
function TDynAABBTreeBase.TSegmentQueryResult.valid (): Boolean; inline; begin result := (dist >= 0) and (flesh <> Default(ITP)); end;
mRootNodeId := TTreeNode.NullTreeNode;
mNodeCount := 0;
mAllocCount := 8192;
+ vstused := 0;
SetLength(mNodes, mAllocCount);
//memset(mNodes, 0, mAllocCount*TTreeNode.sizeof);
// checker should check if this node should be considered to further checking
// returns tree node if visitor says stop or -1
function TDynAABBTreeBase.visit (constref caabb: AABB2D; mode: Integer; checker: TVisitCheckerCB; visitor: TQueryOverlapCB; visdg: TQueryOverlapDg; tagmask: Integer): Integer;
+const
+ StackGran = 1024;
var
- stack: array [0..2048] of Integer; // stack with the nodes to visit
- bigstack: array of Integer = nil;
- sp: Integer = 0;
-
- (*
- procedure spush (id: Integer); inline;
- var
- xsp: Integer;
- begin
- if (sp < length(stack)) then
- begin
- // use "small stack"
- stack[sp] := id;
- Inc(sp);
- end
- else
- begin
- // use "big stack"
- xsp := sp-length(stack);
- if (xsp < length(bigstack)) then
- begin
- // reuse
- bigstack[xsp] := id;
- end
- else
- begin
- // grow
- SetLength(bigstack, length(bigstack)+1);
- bigstack[high(bigstack)] := id;
- end;
- Inc(sp);
- end;
- end;
-
- function spop (): Integer; inline;
- begin
- //{$IFDEF aabbtree_many_asserts}assert(sp > 0);{$ENDIF}
- if (sp <= length(stack)) then
- begin
- // use "small stack"
- Dec(sp);
- result := stack[sp];
- end
- else
- begin
- // use "big stack"
- Dec(sp);
- result := bigstack[sp-length(stack)];
- end;
- end;
- *)
-
-var
+ oldvstused: Integer;
nodeId: Integer;
node: PTreeNode;
doNode: Boolean = false;
- xsp: Integer;
begin
if not assigned(checker) then begin result := -1; exit; end;
//if not assigned(visitor) and not assigned(visdg) then raise Exception.Create('dyntree: empty visitors aren''t supported');
+ oldvstused := vstused;
+ if (vstused+StackGran > Length(vstack)) then SetLength(vstack, vstused+StackGran);
//try
{$IFDEF aabbtree_query_count}
mNodesVisited := 0;
{$ENDIF}
// start from root node
+ // we can't have nested functions in generics, sorry
{$IF FALSE}
spush(mRootNodeId);
{$ELSE}
- if (sp < length(stack)) then begin stack[sp] := mRootNodeId; Inc(sp); end
- else begin xsp := sp-length(stack); if (xsp < length(bigstack)) then bigstack[xsp] := mRootNodeId
- else begin SetLength(bigstack, length(bigstack)+1); bigstack[high(bigstack)] := mRootNodeId; end;
- end;
- Inc(sp);
+ if (vstused >= Length(vstack)) then SetLength(vstack, vstused+StackGran);
+ vstack[vstused] := mRootNodeId;
+ Inc(vstused);
{$ENDIF}
// while there are still nodes to visit
- while (sp > 0) do
+ while (vstused > oldvstused) do
begin
// get the next node id to visit
+ // we can't have nested functions in generics, sorry
{$IF FALSE}
nodeId := spop();
{$ELSE}
- if (sp <= length(stack)) then begin Dec(sp); nodeId := stack[sp]; end
- else begin Dec(sp); nodeId := bigstack[sp-length(stack)]; end;
+ Dec(vstused);
+ nodeId := vstack[vstused];
{$ENDIF}
// skip it if it is a nil node
if (nodeId = TTreeNode.NullTreeNode) then continue;
begin
if assigned(visitor) then
begin
- if (visitor(node.flesh, node.tag)) then begin result := nodeId; bigstack := nil; exit; end;
+ if (visitor(node.flesh, node.tag)) then begin result := nodeId; vstused := oldvstused; exit; end;
end;
if assigned(visdg) then
begin
- if (visdg(node.flesh, node.tag)) then begin result := nodeId; bigstack := nil; exit; end;
+ if (visdg(node.flesh, node.tag)) then begin result := nodeId; vstused := oldvstused; exit; end;
end;
end;
end
else
begin
// if the node is not a leaf, we need to visit its children
+ // we can't have nested functions in generics, sorry
{$IF FALSE}
spush(node.children[TTreeNode.Left]);
spush(node.children[TTreeNode.Right]);
{$ELSE}
- if (sp < length(stack)) then begin stack[sp] := node.children[TTreeNode.Left]; Inc(sp); end
- else begin xsp := sp-length(stack); if (xsp < length(bigstack)) then bigstack[xsp] := node.children[TTreeNode.Left]
- else begin SetLength(bigstack, length(bigstack)+1); bigstack[high(bigstack)] := node.children[TTreeNode.Left]; end;
- end;
- Inc(sp);
-
- if (sp < length(stack)) then begin stack[sp] := node.children[TTreeNode.Right]; Inc(sp); end
- else begin xsp := sp-length(stack); if (xsp < length(bigstack)) then bigstack[xsp] := node.children[TTreeNode.Right]
- else begin SetLength(bigstack, length(bigstack)+1); bigstack[high(bigstack)] := node.children[TTreeNode.Right]; end;
- end;
- Inc(sp);
-
+ if (vstused+2 > Length(vstack)) then SetLength(vstack, vstused+StackGran);
+ vstack[vstused] := node.children[TTreeNode.Left];
+ Inc(vstused);
+ vstack[vstused] := node.children[TTreeNode.Right];
+ Inc(vstused);
{$ENDIF}
end;
end;
end;
result := -1; // oops
- bigstack := nil;
+ vstused := oldvstused;
//finally
// bigstack := nil;
//end;
constructor TDynAABBTreeBase.Create (extraAABBGap: TreeNumber=0);
begin
mExtraGap := extraAABBGap;
+ mNodes := nil;
+ SetLength(vstack, 2048);
+ vstused := 0;
setup();
end;
destructor TDynAABBTreeBase.Destroy ();
begin
mNodes := nil;
+ vstack := nil;
inherited;
end;
// get fat object AABB by nodeid; returns random shit for invalid ids
procedure TDynAABBTreeBase.getNodeFatAABB (out aabb: AABB2D; nodeid: Integer);
begin
- if (nodeid >= 0) and (nodeid < mAllocCount) and (not mNodes[nodeid].isfree) then aabb.copyFrom(mNodes[nodeid].aabb) else aabb.setDims(0, 0, 0, 0);
+ if (nodeid >= 0) and (nodeid < mAllocCount) and (not mNodes[nodeid].isfree) then aabb := AABB2D.Create(mNodes[nodeid].aabb) else aabb := AABB2D.Create(0, 0, 0, 0);
end;
function TDynAABBTreeBase.getNodeXY (nodeid: Integer; out x, y: Integer): Boolean; inline;
osres: PSegmentQueryResult;
osqcb: TSegQueryCallback;
begin
- qr.reset();
+ qr := TSegmentQueryResult.Create(false);
if (ax >= bx) or (ay >= by) then begin result := false; exit; end;