summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 983a370)
raw | patch | inline | side by side (parent: 983a370)
author | Ketmar Dark <ketmar@ketmar.no-ip.org> | |
Fri, 18 Aug 2017 17:36:17 +0000 (20:36 +0300) | ||
committer | Ketmar Dark <ketmar@ketmar.no-ip.org> | |
Fri, 18 Aug 2017 18:29:51 +0000 (21:29 +0300) |
src/game/g_map.pas | patch | blob | history | |
src/game/z_aabbtree.pas | patch | blob | history |
diff --git a/src/game/g_map.pas b/src/game/g_map.pas
index b448103ab23601f6630d783d284ddf516f54675a..3a97ef4586b2b6572e1a68dff275d0d00f34114d 100644 (file)
--- a/src/game/g_map.pas
+++ b/src/game/g_map.pas
MUSIC_SIGNATURE = $4953554D; // 'MUSI'
FLAG_SIGNATURE = $47414C46; // 'FLAG'
- GridTagInvalid = -1;
- GridTagWallDoor = 0;
- GridTagBack = 1;
- GridTagFore = 2;
- GridTagWater = 3;
- GridTagAcid1 = 4;
- GridTagAcid2 = 5;
- GridTagStep = 6;
- GridTagLift = 7;
- GridTagBlockMon = 8;
+ GridTagInvalid = 0;
+ GridTagWallDoor = $0001;
+ GridTagBack = $0002;
+ GridTagFore = $0004;
+ GridTagWater = $0008;
+ GridTagAcid1 = $0010;
+ GridTagAcid2 = $0020;
+ GridTagStep = $0040;
+ GridTagLift = $0080;
+ GridTagBlockMon = $0100;
function panelTypeToTag (panelType: Word): Integer;
begin
panels[idx].tag := tag;
gMapGrid.insertBody(panels[idx], panels[idx].X, panels[idx].Y, panels[idx].Width, panels[idx].Height, tag);
- mapTree.insertObject(panels[idx], true); // as static object
+ mapTree.insertObject(panels[idx], tag, true); // as static object
end;
end;
pan: TPanel;
begin
result := false; // don't stop, ever
+ //e_WriteLog(Format(' *body: tag:%d; ptag:%d; pantype=%d', [tag, ptag, PanelType]), MSG_NOTIFY);
if (tag <> ptag) then exit;
- //e_WriteLog(Format(' *body: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY);
if obj = nil then begin e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); exit; end;
if not (obj is TPanel) then begin e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); exit; end;
dplAddPanel(pan);
end;
- function checkerTree (obj: TObject): Boolean;
- var
- pan: TPanel;
- begin
- result := false; // don't stop, ever
- pan := (obj as TPanel);
- if (pan.tag <> ptag) then exit;
- if (PanelType = PANEL_CLOSEDOOR) then begin if not pan.Door then exit; end else begin if pan.Door then exit; end;
- //e_WriteLog(Format(' body hit: (%d,%d)-(%dx%d) tag: %d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY);
- dplAddPanel(pan);
- end;
-
procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False);
var
idx: Integer;
begin
if gdbg_map_use_tree_draw then
begin
- mapTree.aabbQuery(x0, y0, wdt, hgt, checkerTree);
+ mapTree.aabbQuery(x0, y0, wdt, hgt, checker, ptag);
end
else
begin
@@ -2003,20 +1991,10 @@ procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius:
pan.DrawShadowVolume(lightX, lightY, radius);
end;
- function checkerTree (obj: TObject): Boolean;
- var
- pan: TPanel;
- begin
- result := false; // don't stop, ever
- pan := (obj as TPanel);
- if (pan.tag <> GridTagWallDoor) then exit; // only walls
- pan.DrawShadowVolume(lightX, lightY, radius);
- end;
-
begin
if gdbg_map_use_tree_draw then
begin
- mapTree.aabbQuery(lightX-radius, lightY-radius, radius*2, radius*2, checkerTree);
+ mapTree.aabbQuery(lightX-radius, lightY-radius, radius*2, radius*2, checker, GridTagWallDoor);
end
else
begin
@@ -2277,14 +2255,6 @@ function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word;
end;
end;
- function checkerTree (obj: TObject): Boolean;
- var
- pan: TPanel;
- begin
- pan := (obj as TPanel);
- result := checker(obj, pan.tag);
- end;
-
begin
//TODO: detailed profile
if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('wall coldet');
begin
if gdbg_map_use_tree_coldet then
begin
- result := mapTree.aabbQuery(X, Y, Width, Height, checkerTree);
+ result := (mapTree.aabbQuery(X, Y, Width, Height, checker, (GridTagWallDoor or GridTagWater or GridTagAcid1 or GridTagAcid2 or GridTagStep or GridTagLift or GridTagBlockMon)) <> nil);
{
if (mapTree.nodesVisited <> 0) then
begin
a: Integer;
begin
result := false; // don't stop, ever
+ if (tag <> GridTagWater) and (tag <> GridTagAcid1) and (tag <> GridTagAcid2) then exit;
pan := (obj as TPanel);
a := pan.ArrIdx;
// water
end;
end;
- function checkerTree (obj: TObject): Boolean;
- var
- pan: TPanel;
- begin
- result := false;
- pan := (obj as TPanel);
- if (pan.tag = GridTagWater) or (pan.tag = GridTagAcid1) or (pan.tag = GridTagAcid2) then result := checker(obj, pan.tag);
- end;
-
{var
cctype1: Integer = 3; // priority: 0: water, 1: acid1, 2: acid2; 3: others (nothing)
texid1: DWORD;}
texid := TEXTURE_NONE;
if gdbg_map_use_tree_coldet then
begin
- mapTree.aabbQuery(X, Y, Width, Height, checkerTree);
+ mapTree.aabbQuery(X, Y, Width, Height, checker);
{
cctype1 := cctype;
texid1 := texid;
index 4f3e9938c0fe9c5f5acb617621a6242e890a5983..19a5c7474f29ac4e319d7b524aef51dffd99a094 100644 (file)
--- a/src/game/z_aabbtree.pas
+++ b/src/game/z_aabbtree.pas
height: SmallInt;
// fat axis aligned bounding box (AABB) corresponding to the node
aabb: AABB2D;
+ tag: Integer; // just a user-defined tag
public
// return true if the node is a leaf of the tree
procedure clear (); inline;
end;
TVisitCheckerCB = function (node: PTreeNode): Boolean is nested;
- TVisitVisitorCB = function (abody: TTreeFlesh): Boolean is nested;
+ //TVisitVisitorCB = function (abody: TTreeFlesh; atag: Integer): Boolean is nested;
public
// return `true` to stop
// without triggering a large modification of the tree which can be costly
mExtraGap: Float;
+ public
+ // called when a overlapping node has been found during the call to forEachAABBOverlap()
+ // return `true` to stop
+ type TQueryOverlapCB = function (abody: TTreeFlesh; atag: Integer): Boolean is nested;
+ type TSegQueryCallback = function (abody: TTreeFlesh; ax, ay, bx, by: Float): Float is nested; // return dist from (ax,ay) to abody
+
+ TSegmentQueryResult = record
+ dist: Float; // <0: nothing was hit
+ flesh: TTreeFlesh;
+
+ procedure reset (); inline;
+ function valid (): Boolean; inline;
+ end;
+
private
function allocateNode (): Integer;
procedure releaseNode (nodeId: Integer);
function computeHeight (nodeId: Integer): Integer;
function insertObjectInternal (var aabb: AABB2D; staticObject: Boolean): Integer;
procedure setup ();
- function visit (checker: TVisitCheckerCB; visitor: TVisitVisitorCB): Integer;
+ function visit (checker: TVisitCheckerCB; visitor: TQueryOverlapCB; tagmask: Integer=-1): Integer;
public
{$IFDEF aabbtree_query_count}
mNodesVisited, mNodesDeepVisited: Integer;
{$ENDIF}
- public
- // called when a overlapping node has been found during the call to forEachAABBOverlap()
- // return `true` to stop
- type TQueryOverlapCB = function (abody: TTreeFlesh): Boolean is nested;
- type TSegQueryCallback = function (abody: TTreeFlesh; ax, ay, bx, by: Float): Float is nested; // return dist from (ax,ay) to abody
-
- TSegmentQueryResult = record
- dist: Float; // <0: nothing was hit
- flesh: TTreeFlesh;
-
- procedure reset (); inline;
- function valid (): Boolean; inline;
- end;
-
public
constructor Create (extraAABBGap: Float=0.0);
destructor Destroy (); override;
// this method creates a new leaf node in the tree and returns the id of the corresponding node or -1 on error
// AABB for static object will not be "fat" (simple optimization)
// WARNING! inserting the same object several times *WILL* break everything!
- function insertObject (flesh: TTreeFlesh; staticObject: Boolean=false): Integer;
+ function insertObject (flesh: TTreeFlesh; tag: Integer; staticObject: Boolean=false): Integer;
// remove an object from the tree
// WARNING: ids of removed objects can be reused on later insertions!
*)
function updateObject (nodeId: Integer; dispX, dispY: Float; forceReinsert: Boolean=false): Boolean;
- function aabbQuery (ax, ay, aw, ah: Float; cb: TQueryOverlapCB): Boolean;
+ function aabbQuery (ax, ay, aw, ah: Float; cb: TQueryOverlapCB; tagmask: Integer=-1): TTreeFlesh;
function pointQuery (ax, ay: Float; cb: TQueryOverlapCB): TTreeFlesh;
function segmentQuery (var qr: TSegmentQueryResult; ax, ay, bx, by: Float; cb: TSegQueryCallback): Boolean;
children[0] := 0;
children[1] := 0;
flesh := nil;
+ tag := 0;
height := 0;
aabb.minX := 0;
aabb.minY := 0;
// return `true` from visitor to stop immediately
// checker should check if this node should be considered to further checking
// returns tree node if visitor says stop or -1
-function TDynAABBTree.visit (checker: TVisitCheckerCB; visitor: TVisitVisitorCB): Integer;
+function TDynAABBTree.visit (checker: TVisitCheckerCB; visitor: TQueryOverlapCB; tagmask: Integer=-1): Integer;
var
stack: array [0..255] of Integer; // stack with the nodes to visit
bigstack: array of Integer = nil;
begin
// call visitor on it
{$IFDEF aabbtree_query_count}Inc(mNodesDeepVisited);{$ENDIF}
- if assigned(visitor) then
+ if ((node.tag and tagmask) <> 0) and assigned(visitor) then
begin
- if (visitor(node.flesh)) then begin result := nodeId; exit; end;
+ if (visitor(node.flesh, node.tag)) then begin result := nodeId; exit; end;
end;
end
else
// this method creates a new leaf node in the tree and returns the id of the corresponding node or -1 on error
// AABB for static object will not be "fat" (simple optimization)
// WARNING! inserting the same object several times *WILL* break everything!
-function TDynAABBTree.insertObject (flesh: TTreeFlesh; staticObject: Boolean=false): Integer;
+function TDynAABBTree.insertObject (flesh: TTreeFlesh; tag: Integer; staticObject: Boolean=false): Integer;
var
aabb: AABB2D;
nodeId: Integer;
nodeId := insertObjectInternal(aabb, staticObject);
{$IFDEF aabbtree_many_asserts}assert(mNodes[nodeId].leaf);{$ENDIF}
mNodes[nodeId].flesh := flesh;
+ mNodes[nodeId].tag := tag;
result := nodeId;
end;
// report all shapes overlapping with the AABB given in parameter
-function TDynAABBTree.aabbQuery (ax, ay, aw, ah: Float; cb: TQueryOverlapCB): Boolean;
+function TDynAABBTree.aabbQuery (ax, ay, aw, ah: Float; cb: TQueryOverlapCB; tagmask: Integer=-1): TTreeFlesh;
var
caabb: AABB2D;
function checker (node: PTreeNode): Boolean;
begin
result := caabb.overlaps(node.aabb);
end;
+var
+ nid: Integer;
begin
+ result := nil;
if not assigned(cb) then exit;
if (aw < 1) or (ah < 1) then exit;
caabb := AABB2D.Create(ax, ay, ax+aw, ay+ah);
- result := (visit(checker, cb) <> -1);
+ nid := visit(checker, cb, tagmask);
+ if (nid >= 0) then result := mNodes[nid].flesh else result := nil;
end;
// report body that contains the given point, or nil
function TDynAABBTree.pointQuery (ax, ay: Float; cb: TQueryOverlapCB): TTreeFlesh;
-var
- nid: Integer;
function checker (node: PTreeNode): Boolean;
begin
result := node.aabb.contains(ax, ay);
end;
+var
+ nid: Integer;
begin
nid := visit(checker, cb);
{$IFDEF aabbtree_many_asserts}assert((nid < 0) or ((nid >= 0) and (nid < mNodeCount) and (mNodes[nid].leaf)));{$ENDIF}
result := node.aabb.intersects(curax, curay, curbx, curby);
end;
- function visitor (flesh: TTreeFlesh): Boolean;
+ function visitor (flesh: TTreeFlesh; tag: Integer): Boolean;
var
hitFraction: Float;
begin