diff --git a/src/game/g_map.pas b/src/game/g_map.pas
index b84bf3aaca6170f165147659879aa9e2971c8f28..eabf89645796ad273a1a78531c031497a40b3772 100644 (file)
--- a/src/game/g_map.pas
+++ b/src/game/g_map.pas
uses
e_graphics, g_basic, MAPSTRUCT, g_textures, Classes,
- g_phys, wadreader, BinEditor, g_panel, g_grid, md5, xprofiler;
+ g_phys, wadreader, BinEditor, g_panel, g_grid, z_aabbtree, md5, xprofiler;
type
TMapInfo = record
gdbg_map_use_grid_render: Boolean = true;
gdbg_map_use_grid_coldet: Boolean = true;
+ gdbg_map_use_tree_draw: Boolean = true;
+ gdbg_map_use_tree_coldet: Boolean = false;
profMapCollision: TProfiler = nil; //WARNING: FOR DEBUGGING ONLY!
implementation
GL, GLExt, g_weapons, g_game, g_sound, e_sound, CONFIG,
g_options, MAPREADER, g_triggers, g_player, MAPDEF,
Math, g_monsters, g_saveload, g_language, g_netmsg,
- utils, sfs,
+ utils, sfs, binheap,
ImagingTypes, Imaging, ImagingUtility,
ImagingGif, ImagingNetworkGraphics;
PArrID: Integer;
end;
+type
+ TDynAABBTreeMap = class(TDynAABBTree)
+ function getFleshAABB (var aabb: AABB2D; flesh: TTreeFlesh): Boolean; override;
+ end;
+
+function TDynAABBTreeMap.getFleshAABB (var aabb: AABB2D; flesh: TTreeFlesh): Boolean;
+var
+ pan: TPanel;
+begin
+ if (flesh = nil) then begin result := false; exit; end;
+ pan := (flesh as TPanel);
+ aabb := AABB2D.Create(pan.X, pan.Y, pan.X+pan.Width, pan.Y+pan.Height);
+ //e_WriteLog(Format('getFleshAABB(%d;%d) AABB:(%f,%f)-(%f,%f); valid=%d; volume=%f; x=%d; y=%d; w=%d; h=%d', [pan.tag, pan.ArrIdx, aabb.minX, aabb.minY, aabb.maxX, aabb.maxY, Integer(aabb.valid), aabb.volume, pan.X, pan.Y, pan.Width, pan.Height]), MSG_NOTIFY);
+ result := aabb.valid;
+end;
+
var
PanelById: array of TPanelID;
Textures: TLevelTextureArray;
FlagPoints: Array [FLAG_RED..FLAG_BLUE] of PFlagPoint;
//DOMFlagPoints: Array of TFlagPoint;
gMapGrid: TBodyGrid = nil;
+ mapTree: TDynAABBTree = nil;
procedure g_Map_ProfilersBegin ();
begin
- if (profMapCollision = nil) then profMapCollision := TProfiler.Create('MAP COLLISION');
+ if (profMapCollision = nil) then profMapCollision := TProfiler.Create('MAP COLLISION', g_profile_history_size);
profMapCollision.mainBegin(g_profile_collision);
// create sections
if g_profile_collision then
begin
- profMapCollision.sectionBeginAccum('wall coldet');
+ profMapCollision.sectionBegin('wall coldet');
profMapCollision.sectionEnd();
- profMapCollision.sectionBeginAccum('liquid coldet');
+ profMapCollision.sectionBegin('liquid coldet');
profMapCollision.sectionEnd();
end;
end;
panels^[len] := TPanel.Create(PanelRec, AddTextures, CurTex, Textures);
panels^[len].ArrIdx := len;
+ panels^[len].tag := panelTypeToTag(PanelRec.PanelType);
if sav then
panels^[len].SaveIt := True;
tag := panelTypeToTag(tag);
for idx := High(panels) downto 0 do
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
end;
end;
begin
gMapGrid.Free();
gMapGrid := nil;
+ mapTree.Free();
+ mapTree := nil;
fixMinMax(gWalls);
fixMinMax(gRenderBackgrounds);
end;
gMapGrid := TBodyGrid.Create(mapX0, mapY0, mapX1-mapX0+1, mapY1-mapY0+1);
+ mapTree := TDynAABBTreeMap.Create();
addPanelsToGrid(gWalls, PANEL_WALL); // and PANEL_CLOSEDOOR
addPanelsToGrid(gRenderBackgrounds, PANEL_BACK);
addPanelsToGrid(gBlockMon, PANEL_BLOCKMON);
gMapGrid.dumpStats();
+ e_WriteLog(Format('tree depth: %d; %d nodes used, %d nodes allocated', [mapTree.computeTreeHeight, mapTree.nodeCount, mapTree.nodeAlloced]), MSG_NOTIFY);
+ mapTree.forEachLeaf(nil);
end;
function g_Map_Load(Res: String): Boolean;
begin
gMapGrid.Free();
gMapGrid := nil;
+ mapTree.Free();
+ mapTree := nil;
Result := False;
gMapInfo.Map := Res;
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;
if gdbg_map_use_grid_render then
begin
- gMapGrid.forEachInAABB(x0, y0, wdt, hgt, checker);
+ if gdbg_map_use_tree_draw then
+ begin
+ mapTree.aabbQuery(x0, y0, wdt, hgt, checkerTree);
+ end
+ else
+ begin
+ gMapGrid.forEachInAABB(x0, y0, wdt, hgt, checker);
+ end;
// sort and draw the list (we need to sort it, or rendering is fucked)
while gDrawPanelList.count > 0 do
begin
@@ -1955,8 +2003,25 @@ 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
- gMapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker);
+ if gdbg_map_use_tree_draw then
+ begin
+ mapTree.aabbQuery(lightX-radius, lightY-radius, radius*2, radius*2, checkerTree);
+ end
+ else
+ begin
+ gMapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker);
+ end;
end;
@@ -2212,13 +2277,28 @@ 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');
try
if gdbg_map_use_grid_coldet then
begin
- result := gMapGrid.forEachInAABB(X, Y, Width, Height, checker);
+ if gdbg_map_use_tree_coldet then
+ begin
+ result := mapTree.aabbQuery(X, Y, Width, Height, checkerTree);
+ end
+ else
+ begin
+ result := gMapGrid.forEachInAABB(X, Y, Width, Height, checker);
+ end;
end
else
begin
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;}
begin
//TODO: detailed profile?
if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('liquid coldet');
try
- if not gdbg_map_use_grid_coldet then
+ if gdbg_map_use_grid_coldet then
begin
- result := g_Map_CollideLiquid_TextureOld(X, Y, Width, Height);
+ texid := TEXTURE_NONE;
+ if gdbg_map_use_tree_coldet then
+ begin
+ mapTree.aabbQuery(X, Y, Width, Height, checkerTree);
+ {
+ cctype1 := cctype;
+ texid1 := texid;
+ cctype := 3;
+ texid := TEXTURE_NONE;
+ gMapGrid.forEachInAABB(X, Y, Width, Height, checker);
+ if (cctype1 <> cctype) or (texid1 <> texid) then
+ begin
+ e_WriteLog(Format('g_Map_CollideLiquid_Texture(%d, %d, %u, %u): tree(cctype:%d;texid:%u); grid(cctype:%d;texid:%u)', [X, Y, Width, Height, cctype1, texid1, cctype, texid]), MSG_WARNING);
+ end;}
+ end
+ else
+ begin
+ gMapGrid.forEachInAABB(X, Y, Width, Height, checker);
+ end;
+ result := texid;
end
else
begin
- texid := TEXTURE_NONE;
- gMapGrid.forEachInAABB(X, Y, Width, Height, checker);
- result := texid;
+ result := g_Map_CollideLiquid_TextureOld(X, Y, Width, Height);
end;
finally
if (profMapCollision <> nil) then profMapCollision.sectionEnd();