DEADSOFTWARE

cosmetix
authorKetmar Dark <ketmar@ketmar.no-ip.org>
Fri, 18 Aug 2017 17:36:17 +0000 (20:36 +0300)
committerKetmar Dark <ketmar@ketmar.no-ip.org>
Fri, 18 Aug 2017 18:29:51 +0000 (21:29 +0300)
src/game/g_map.pas
src/game/z_aabbtree.pas

index b448103ab23601f6630d783d284ddf516f54675a..3a97ef4586b2b6572e1a68dff275d0d00f34114d 100644 (file)
@@ -156,16 +156,16 @@ const
   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;
@@ -1005,7 +1005,7 @@ var
     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;
 
@@ -1898,8 +1898,8 @@ var
     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;
@@ -1912,18 +1912,6 @@ var
     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;
@@ -1960,7 +1948,7 @@ begin
   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');
@@ -2293,7 +2263,7 @@ begin
     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
@@ -2328,6 +2298,7 @@ var
     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
@@ -2362,15 +2333,6 @@ var
     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;}
@@ -2383,7 +2345,7 @@ begin
       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)
@@ -153,6 +153,7 @@ type
         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;
@@ -163,7 +164,7 @@ type
       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
@@ -186,6 +187,20 @@ type
     // 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);
@@ -195,27 +210,13 @@ type
     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;
@@ -237,7 +238,7 @@ type
     // 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!
@@ -260,7 +261,7 @@ type
      *)
     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;
 
@@ -524,6 +525,7 @@ begin
   children[0] := 0;
   children[1] := 0;
   flesh := nil;
+  tag := 0;
   height := 0;
   aabb.minX := 0;
   aabb.minY := 0;
@@ -1105,7 +1107,7 @@ end;
 // 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;
@@ -1206,9 +1208,9 @@ begin
         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
@@ -1287,7 +1289,7 @@ end;
 // 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;
@@ -1310,6 +1312,7 @@ begin
   nodeId := insertObjectInternal(aabb, staticObject);
   {$IFDEF aabbtree_many_asserts}assert(mNodes[nodeId].leaf);{$ENDIF}
   mNodes[nodeId].flesh := flesh;
+  mNodes[nodeId].tag := tag;
   result := nodeId;
 end;
 
@@ -1378,29 +1381,33 @@ 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}
@@ -1422,7 +1429,7 @@ var
     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