X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_map.pas;h=b97cc00a24f2a3ed8a6a06dc51b9b10e54b850fd;hb=1ac9fc74d98d56a450774702aae19fa1546f2849;hp=a754ff87211b1043a1e280662e771faabe7d99cc;hpb=984a31dcc2636073083a3a3cf8d4d409019d211a;p=d2df-sdl.git diff --git a/src/game/g_map.pas b/src/game/g_map.pas index a754ff8..b97cc00 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -13,15 +13,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *) -{$MODE DELPHI} -{$modeswitch nestedprocvars} +{$INCLUDE ../shared/a_modes.inc} unit g_map; interface uses e_graphics, g_basic, MAPSTRUCT, g_textures, Classes, - g_phys, wadreader, BinEditor, g_panel, g_grid, md5; + g_phys, wadreader, BinEditor, g_panel, g_grid, z_aabbtree, md5, xprofiler; type TMapInfo = record @@ -63,10 +62,6 @@ function g_Map_Exist(Res: String): Boolean; procedure g_Map_Free(); procedure g_Map_Update(); -// build "potentially visible panels" set, so we can avoid looping over all level panels again and again -procedure g_Map_BuildPVP (minx, miny, maxx, maxy: Integer); -procedure g_Map_ResetPVP (); -// do not call this without calling `g_Map_BuildPVP()` or `g_Map_ResetPVP()` first! procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word); procedure g_Map_DrawBack(dx, dy: Integer); @@ -93,10 +88,11 @@ function g_Map_PanelForPID(PanelID: Integer; var PanelArrayID: Integer): PPanel; procedure g_Map_SaveState(Var Mem: TBinMemoryWriter); procedure g_Map_LoadState(Var Mem: TBinMemoryReader); -// build "possibly lit panels" index, so we can avoid looping over all level panels again and again -function g_Map_BuildPLP (ltminx, ltminy, ltmaxx, ltmaxy: Integer): Boolean; // returns `false` if no patels lit procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer); +procedure g_Map_ProfilersBegin (); +procedure g_Map_ProfilersEnd (); + const RESPAWNPOINT_PLAYER1 = 1; RESPAWNPOINT_PLAYER2 = 2; @@ -137,7 +133,13 @@ var gWADHash: TMD5Digest; BackID: DWORD = DWORD(-1); gExternalResources: TStringList; - gMapGrid: TBodyGrid = nil; + + gdbg_map_use_grid_render: Boolean = true; + gdbg_map_use_grid_coldet: Boolean = true; + gdbg_map_use_tree_draw: Boolean = false; + gdbg_map_use_tree_coldet: Boolean = false; + gdbg_map_dump_coldet_tree_queries: Boolean = false; + profMapCollision: TProfiler = nil; //WARNING: FOR DEBUGGING ONLY! implementation @@ -146,28 +148,99 @@ uses 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, - libc; + ImagingGif, ImagingNetworkGraphics; const FLAGRECT: TRectWH = (X:15; Y:12; Width:33; Height:52); MUSIC_SIGNATURE = $4953554D; // 'MUSI' FLAG_SIGNATURE = $47414C46; // 'FLAG' + 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 + case panelType of + PANEL_WALL, PANEL_OPENDOOR, PANEL_CLOSEDOOR: result := GridTagWallDoor; // gWalls + PANEL_BACK: result := GridTagBack; // gRenderBackgrounds + PANEL_FORE: result := GridTagFore; // gRenderForegrounds + PANEL_WATER: result := GridTagWater; // gWater + PANEL_ACID1: result := GridTagAcid1; // gAcid1 + PANEL_ACID2: result := GridTagAcid2; // gAcid2 + PANEL_STEP: result := GridTagStep; // gSteps + PANEL_LIFTUP, PANEL_LIFTDOWN, PANEL_LIFTLEFT, PANEL_LIFTRIGHT: result := GridTagLift; // gLifts -- this is for all lifts + PANEL_BLOCKMON: result := GridTagBlockMon; // gBlockMon -- this is for all blockmons + else result := GridTagInvalid; + end; +end; + + type TPanelID = record PWhere: ^TPanelArray; 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 + result := false; + if (flesh = nil) then exit; + pan := (flesh as TPanel); + if (pan.Width < 1) or (pan.Height < 1) then exit; + aabb := AABB2D.Create(pan.X, pan.Y, pan.X+pan.Width, pan.Y+pan.Height); + //if (pan.Width = 1) then aabb.maxX += 1; + //if (pan.Height = 1) then aabb.maxY += 1; + if not aabb.valid then raise Exception.Create('wutafuuuuuuu?!'); + //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; RespawnPoints: Array of TRespawnPoint; 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', g_profile_history_size); + profMapCollision.mainBegin(g_profile_collision); + // create sections + if g_profile_collision then + begin + profMapCollision.sectionBegin('wall coldet'); + profMapCollision.sectionEnd(); + profMapCollision.sectionBegin('liquid coldet'); + profMapCollision.sectionEnd(); + end; +end; + +procedure g_Map_ProfilersEnd (); +begin + if (profMapCollision <> nil) then profMapCollision.mainEnd(); +end; function g_Map_IsSpecialTexture(Texture: String): Boolean; @@ -379,6 +452,7 @@ begin 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; @@ -907,6 +981,80 @@ begin addResToExternalResList(mapHeader.SkyName); end; +procedure mapCreateGrid (); +var + mapX0: Integer = $3fffffff; + mapY0: Integer = $3fffffff; + mapX1: Integer = -$3fffffff; + mapY1: Integer = -$3fffffff; + + procedure fixMinMax (var panels: TPanelArray); + var + idx: Integer; + begin + for idx := 0 to High(panels) do + begin + if (panels[idx].Width < 1) or (panels[idx].Height < 1) then continue; + if mapX0 > panels[idx].X then mapX0 := panels[idx].X; + if mapY0 > panels[idx].Y then mapY0 := panels[idx].Y; + if mapX1 < panels[idx].X+panels[idx].Width-1 then mapX1 := panels[idx].X+panels[idx].Width-1; + if mapY1 < panels[idx].Y+panels[idx].Height-1 then mapY1 := panels[idx].Y+panels[idx].Height-1; + end; + end; + + procedure addPanelsToGrid (var panels: TPanelArray; tag: Integer); + var + idx: Integer; + begin + 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], tag, true); // as static object + end; + end; + +begin + gMapGrid.Free(); + gMapGrid := nil; + mapTree.Free(); + mapTree := nil; + + fixMinMax(gWalls); + fixMinMax(gRenderBackgrounds); + fixMinMax(gRenderForegrounds); + fixMinMax(gWater); + fixMinMax(gAcid1); + fixMinMax(gAcid2); + fixMinMax(gSteps); + fixMinMax(gLifts); + fixMinMax(gBlockMon); + + if (mapX0 < 0) or (mapY0 < 0) then + begin + e_WriteLog(Format('funny map dimensions: (%d,%d)-(%d,%d)', [mapX0, mapY0, mapX1, mapY1]), MSG_WARNING); + //raise Exception.Create('we are fucked'); + 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(gRenderForegrounds, PANEL_FORE); + addPanelsToGrid(gWater, PANEL_WATER); + addPanelsToGrid(gAcid1, PANEL_ACID1); + addPanelsToGrid(gAcid2, PANEL_ACID2); + addPanelsToGrid(gSteps, PANEL_STEP); + addPanelsToGrid(gLifts, PANEL_LIFTUP); // it doesn't matter which LIFT type is used here + 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; const DefaultMusRes = 'Standart.wad:STDMUS\MUS1'; @@ -938,38 +1086,11 @@ var ok, isAnim, trigRef: Boolean; CurTex, ntn: Integer; - mapX0: Integer = $3fffffff; - mapY0: Integer = $3fffffff; - mapX1: Integer = -$3fffffff; - mapY1: Integer = -$3fffffff; - - procedure fixMinMax (var panels: TPanelArray); - var - idx: Integer; - begin - for idx := 0 to High(panels) do - begin - if (panels[idx].Width < 1) or (panels[idx].Height < 1) then continue; - if mapX0 > panels[idx].X then mapX0 := panels[idx].X; - if mapY0 > panels[idx].Y then mapY0 := panels[idx].Y; - if mapX1 < panels[idx].X+panels[idx].Width-1 then mapX1 := panels[idx].X+panels[idx].Width-1; - if mapY1 < panels[idx].Y+panels[idx].Height-1 then mapY1 := panels[idx].Y+panels[idx].Height-1; - end; - end; - - procedure addPanelsToGrid (var panels: TPanelArray; tag: Integer); - var - idx: Integer; - begin - for idx := 0 to High(panels) do - begin - gMapGrid.insertBody(panels[idx], panels[idx].X, panels[idx].Y, panels[idx].Width, panels[idx].Height, tag); - end; - end; - begin gMapGrid.Free(); gMapGrid := nil; + mapTree.Free(); + mapTree := nil; Result := False; gMapInfo.Map := Res; @@ -1438,26 +1559,7 @@ begin end; e_WriteLog('Creating map grid', MSG_NOTIFY); - - fixMinMax(gWalls); - fixMinMax(gRenderBackgrounds); - fixMinMax(gRenderForegrounds); - fixMinMax(gWater); - fixMinMax(gAcid1); - fixMinMax(gAcid2); - fixMinMax(gSteps); - - gMapGrid := TBodyGrid.Create(mapX1+1, mapY1+1); - - addPanelsToGrid(gWalls, PANEL_WALL); // and PANEL_CLOSEDOOR - addPanelsToGrid(gRenderBackgrounds, PANEL_BACK); - addPanelsToGrid(gRenderForegrounds, PANEL_FORE); - addPanelsToGrid(gWater, PANEL_WATER); - addPanelsToGrid(gAcid1, PANEL_ACID1); - addPanelsToGrid(gAcid2, PANEL_ACID2); - addPanelsToGrid(gSteps, PANEL_STEP); - - gMapGrid.dumpStats(); + mapCreateGrid(); e_WriteLog('Done loading map.', MSG_NOTIFY); Result := True; @@ -1743,75 +1845,7 @@ begin end; -var - pvpset: array of PPanel = nil; // potentially lit panels - pvpb, pvpe: array [0..7] of Integer; // start/end (inclusive) of the correspoinding type panels in pvpset - pvpcount: Integer = -1; // to avoid constant reallocations - -function pvpType (panelType: Word): Integer; -begin - case panelType of - PANEL_WALL, PANEL_CLOSEDOOR: result := 0; // gWalls - PANEL_BACK: result := 1; // gRenderBackgrounds - PANEL_FORE: result := 2; // gRenderForegrounds - PANEL_WATER: result := 3; // gWater - PANEL_ACID1: result := 4; // gAcid1 - PANEL_ACID2: result := 5; // gAcid2 - PANEL_STEP: result := 6; // gSteps - else result := -1; - end; -end; - -procedure g_Map_ResetPVP (); -begin - pvpcount := -1; // special -end; - -procedure g_Map_BuildPVP (minx, miny, maxx, maxy: Integer); -var - idx: Integer; - tpc: Integer; - - procedure checkPanels (var panels: TPanelArray; stp: Integer); - var - idx, x, y, w, h: Integer; - begin - if panels = nil then exit; - tpc := tpc+Length(panels); - if (stp < 0) or (stp > 6) then exit; - pvpb[stp] := pvpcount; - for idx := 0 to High(panels) do - begin - w := panels[idx].Width; - h := panels[idx].Height; - if (w < 1) or (h < 1) then continue; - x := panels[idx].X; - y := panels[idx].Y; - if (x > maxx) or (y > maxy) then continue; - if (x+w <= minx) or (y+h <= miny) then continue; - if pvpcount = length(pvpset) then SetLength(pvpset, pvpcount+32768); - pvpset[pvpcount] := @panels[idx]; - Inc(pvpcount); - end; - pvpe[stp] := pvpcount-1; - end; - -begin - //e_WriteLog(Format('visible rect: (%d,%d)-(%d,%d)', [minx, miny, maxx, maxy]), MSG_NOTIFY); - pvpcount := 0; - for idx := 0 to High(pvpb) do begin pvpb[idx] := 0; pvpe[idx] := -1; end; - tpc := 0; - checkPanels(gWalls, 0); - checkPanels(gRenderBackgrounds, 1); - checkPanels(gRenderForegrounds, 2); - checkPanels(gWater, 3); - checkPanels(gAcid1, 4); - checkPanels(gAcid2, 5); - checkPanels(gSteps, 6); - //e_WriteLog(Format('total panels: %d; visible panels: %d', [tpc, pvpcount]), MSG_NOTIFY); -end; - -procedure g_Map_DrawPanelsOld(x0, y0, wdt, hgt: Integer; PanelType: Word); +procedure g_Map_DrawPanelsOld(PanelType: Word); procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False); var @@ -1819,131 +1853,15 @@ procedure g_Map_DrawPanelsOld(x0, y0, wdt, hgt: Integer; PanelType: Word); begin if (panels <> nil) and (stp >= 0) and (stp <= 6) then begin - if pvpcount < 0 then - begin - // alas, no visible set - for idx := 0 to High(panels) do - begin - if not (drawDoors xor panels[idx].Door) then panels[idx].Draw(); - end; - end - else - begin - // wow, use visible set - if pvpb[stp] <= pvpe[stp] then - begin - for idx := pvpb[stp] to pvpe[stp] do - begin - if not (drawDoors xor pvpset[idx].Door) then pvpset[idx].Draw(); - end; - end; - end; - end; - end; - - procedure dumpPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False); - var - idx: Integer; - begin - if (panels <> nil) and (stp >= 0) and (stp <= 6) then - begin - if pvpcount < 0 then - begin - // alas, no visible set - for idx := 0 to High(panels) do - begin - if not (drawDoors xor panels[idx].Door) then - begin - e_WriteLog(Format(' body hit: (%d,%d)-(%dx%d)', [panels[idx].X, panels[idx].Y, panels[idx].Width, panels[idx].Height]), MSG_NOTIFY); - end; - end; - end - else - begin - // wow, use visible set - if pvpb[stp] <= pvpe[stp] then - begin - for idx := pvpb[stp] to pvpe[stp] do - begin - if not (drawDoors xor pvpset[idx].Door) then - begin - e_WriteLog(Format(' body hit: (%d,%d)-(%dx%d)', [pvpset[idx].X, pvpset[idx].Y, pvpset[idx].Width, pvpset[idx].Height]), MSG_NOTIFY); - end; - end; - end; - end; - end; - end; - - function qq (obj: TObject; tag: Integer): Boolean; - var - pan: TPanel; - begin - result := false; // don't stop, ever - - //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); - end; - if not (obj is TPanel) then - begin - e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); - exit; - end; - //pan := (obj as TPanel); - //e_WriteLog(Format(' !body: (%d,%d)-(%dx%d) tag:%d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY); - - if (tag = PANEL_WALL) then - begin - if (PanelType = PANEL_WALL) then - begin - pan := (obj as TPanel); - if not pan.Door then - begin - //e_WriteLog(Format(' body hit: (%d,%d)-(%dx%d)', [pan.X, pan.Y, pan.Width, pan.Height]), MSG_NOTIFY); - pan.Draw(); - end; - end - else if (PanelType = PANEL_CLOSEDOOR) then - begin - pan := (obj as TPanel); - if pan.Door then - begin - //e_WriteLog(Format(' body hit: (%d,%d)-(%dx%d)', [pan.X, pan.Y, pan.Width, pan.Height]), MSG_NOTIFY); - pan.Draw(); - end; - end - end - else if (PanelType = tag) then - begin - pan := (obj as TPanel); - if not pan.Door then + // alas, no visible set + for idx := 0 to High(panels) do begin - //e_WriteLog(Format(' body hit: (%d,%d)-(%dx%d)', [pan.X, pan.Y, pan.Width, pan.Height]), MSG_NOTIFY); - pan.Draw(); + if not (drawDoors xor panels[idx].Door) then panels[idx].Draw(); end; end; end; begin - //e_WriteLog(Format('QQQ: qtag:%d', [PanelType]), MSG_NOTIFY); - gMapGrid.forEachInAABB(x0, y0, wdt, hgt, qq); - (* - case PanelType of - PANEL_WALL: dumpPanels(0, gWalls); - PANEL_CLOSEDOOR: dumpPanels(0, gWalls, True); - PANEL_BACK: dumpPanels(1, gRenderBackgrounds); - PANEL_FORE: dumpPanels(2, gRenderForegrounds); - PANEL_WATER: dumpPanels(3, gWater); - PANEL_ACID1: dumpPanels(4, gAcid1); - PANEL_ACID2: dumpPanels(5, gAcid2); - PANEL_STEP: dumpPanels(6, gSteps); - end; - *) - - (* case PanelType of PANEL_WALL: DrawPanels(0, gWalls); PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True); @@ -1954,172 +1872,143 @@ begin PANEL_ACID2: DrawPanels(5, gAcid2); PANEL_STEP: DrawPanels(6, gSteps); end; - *) end; + var - gDrawPanelList: array of TPanel = nil; - gDrawPanelListUsed: Integer = 0; + gDrawPanelList: TBinaryHeapObj = nil; -procedure dplClear (); +function dplLess (a, b: TObject): Boolean; begin - gDrawPanelListUsed := 0; + result := ((a as TPanel).ArrIdx < (b as TPanel).ArrIdx); end; -procedure dplAddPanel (pan: TPanel); +procedure dplClear (); begin - if pan = nil then exit; - if gDrawPanelListUsed = Length(gDrawPanelList) then SetLength(gDrawPanelList, gDrawPanelListUsed+4096); // arbitrary number - gDrawPanelList[gDrawPanelListUsed] := pan; - Inc(gDrawPanelListUsed); + if gDrawPanelList = nil then gDrawPanelList := TBinaryHeapObj.Create(@dplLess) else gDrawPanelList.clear(); end; -function dplCompare (p0, p1: Pointer): LongInt; cdecl; -var - pan0, pan1: PPanel; +procedure dplAddPanel (pan: TPanel); begin - pan0 := PPanel(p0); - pan1 := PPanel(p1); - if pan0.ArrIdx < pan1.ArrIdx then result := -1 - else if pan0.ArrIdx > pan1.ArrIdx then result := 1 - else result := 0; + if pan = nil then exit; + gDrawPanelList.insert(pan); end; -procedure dplSort(); -begin - qsort(@gDrawPanelList[0], gDrawPanelListUsed, sizeof(TPanel), &dplCompare); -end; procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word); +var + ptag: Integer; - function qq (obj: TObject; tag: Integer): Boolean; + function checker (obj: TObject; tag: Integer): Boolean; 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; + //pan := (obj as TPanel); + //e_WriteLog(Format(' !body: (%d,%d)-(%dx%d) tag:%d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY); - if obj = nil then - begin - e_WriteLog(Format(' !bodyFUUUUU0: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); - end; - if not (obj is TPanel) then - begin - e_WriteLog(Format(' !bodyFUUUUU1: tag:%d; qtag:%d', [tag, PanelType]), MSG_NOTIFY); - exit; - end; - //pan := (obj as TPanel); - //e_WriteLog(Format(' !body: (%d,%d)-(%dx%d) tag:%d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, tag, PanelType]), MSG_NOTIFY); + pan := (obj as TPanel); + 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; - if (tag = PANEL_WALL) then + procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False); + var + idx: Integer; + pan: TPanel; + begin + if (panels <> nil) and (stp >= 0) and (stp <= 6) then begin - if (PanelType = PANEL_WALL) then - begin - pan := (obj as TPanel); - if not pan.Door then - begin - //e_WriteLog(Format(' body hit: (%d,%d)-(%dx%d)', [pan.X, pan.Y, pan.Width, pan.Height]), MSG_NOTIFY); - dplAddPanel(pan); - end; - end - else if (PanelType = PANEL_CLOSEDOOR) then + // alas, no visible set + for idx := 0 to High(panels) do begin - pan := (obj as TPanel); - if pan.Door then + if not (drawDoors xor panels[idx].Door) then begin - //e_WriteLog(Format(' body hit: (%d,%d)-(%dx%d)', [pan.X, pan.Y, pan.Width, pan.Height]), MSG_NOTIFY); - dplAddPanel(pan); + pan := panels[idx]; + { + if (pan.Width < 1) or (pan.Height < 1) then continue; + if (pan.X+pan.Width <= x0) or (pan.Y+pan.Height <= y0) then continue; + if (pan.X >= x0+wdt) or (pan.Y >= y0+hgt) then continue; + } + pan.Draw(); + //e_WriteLog(Format(' *body hit: (%d,%d)-(%dx%d) tag: %d; qtag:%d', [pan.X, pan.Y, pan.Width, pan.Height, PanelType, PanelType]), MSG_NOTIFY); end; - end - end - else if (PanelType = tag) then - begin - pan := (obj as TPanel); - if not pan.Door then - begin - //e_WriteLog(Format(' body hit: (%d,%d)-(%dx%d)', [pan.X, pan.Y, pan.Width, pan.Height]), MSG_NOTIFY); - dplAddPanel(pan); end; end; end; -var - idx: Integer; begin - //e_WriteLog(Format('QQQ: qtag:%d', [PanelType]), MSG_NOTIFY); - dplClear(); - gMapGrid.forEachInAABB(x0, y0, wdt, hgt, qq); - // sort and draw the list (we need to sort it, or rendering is fucked) - if gDrawPanelListUsed > 0 then - begin - dplSort(); - for idx := 0 to gDrawPanelListUsed-1 do gDrawPanelList[idx].Draw(); - end; + //g_Map_DrawPanelsOld(PanelType); exit; + //e_WriteLog('==================', MSG_NOTIFY); + //e_WriteLog(Format('***QQQ: qtag:%d', [PanelType]), MSG_NOTIFY); dplClear(); -end; - -var - plpset: array of Integer = nil; // potentially lit panels - plpcount: Integer; // to avoid constant reallocations + ptag := panelTypeToTag(PanelType); -function g_Map_BuildPLP (ltminx, ltminy, ltmaxx, ltmaxy: Integer): Boolean; -var - idx: Integer; - panels: TPanelArray; -begin - panels := gWalls; - plpcount := 0; - if (ltminx < ltmaxx) and (ltminy < ltmaxy) then + if gdbg_map_use_grid_render then begin - if panels <> nil then + if gdbg_map_use_tree_draw then begin - for idx := 0 to High(panels) do - begin - if (panels[idx].Width < 1) or (panels[idx].Height < 1) then continue; - if (panels[idx].X+panels[idx].Width <= ltminx) then continue; - if (panels[idx].Y+panels[idx].Height <= ltminy) then continue; - if (panels[idx].X > ltmaxx) then continue; - if (panels[idx].Y > ltmaxy) then continue; - if plpcount = length(plpset) then SetLength(plpset, plpcount+32768); - plpset[plpcount] := idx; - Inc(plpcount); - end; - //e_WriteLog(Format('%d panels left out of %d', [plpcount, Length(panels)]), MSG_NOTIFY); + mapTree.aabbQuery(x0, y0, wdt, hgt, checker, ptag); + 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 + (gDrawPanelList.front() as TPanel).Draw(); + gDrawPanelList.popFront(); + end; + end + else + begin + //e_WriteLog(Format('+++QQQ: qtag:%d', [PanelType]), MSG_NOTIFY); + case PanelType of + PANEL_WALL: DrawPanels(0, gWalls); + PANEL_CLOSEDOOR: DrawPanels(0, gWalls, True); + PANEL_BACK: DrawPanels(1, gRenderBackgrounds); + PANEL_FORE: DrawPanels(2, gRenderForegrounds); + PANEL_WATER: DrawPanels(3, gWater); + PANEL_ACID1: DrawPanels(4, gAcid1); + PANEL_ACID2: DrawPanels(5, gAcid2); + PANEL_STEP: DrawPanels(6, gSteps); end; end; - result := (plpcount > 0); + + //e_WriteLog('==================', MSG_NOTIFY); end; -procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer); - (* old - procedure drawPanels (var panels: TPanelArray); +procedure g_Map_DrawPanelShadowVolumes(lightX: Integer; lightY: Integer; radius: Integer); + function checker (obj: TObject; tag: Integer): Boolean; var - a: Integer; + pan: TPanel; begin - if panels <> nil then - begin - for a := 0 to High(panels) do - begin - panels[a].DrawShadowVolume(lightX, lightY, radius); - end; - end; + result := false; // don't stop, ever + if (tag <> GridTagWallDoor) then exit; // only walls + pan := (obj as TPanel); + pan.DrawShadowVolume(lightX, lightY, radius); end; - *) -var - idx: Integer; + begin - (* - drawPanels(gWalls); - //drawPanels(gRenderForegrounds); - *) - for idx := 0 to plpcount-1 do + if gdbg_map_use_tree_draw then begin - gWalls[plpset[idx]].DrawShadowVolume(lightX, lightY, radius); + mapTree.aabbQuery(lightX-radius, lightY-radius, radius*2, radius*2, checker, GridTagWallDoor); + end + else + begin + gMapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, checker); end; end; + procedure g_Map_DrawBack(dx, dy: Integer); begin if gDrawBackGround and (BackID <> DWORD(-1)) then @@ -2248,9 +2137,40 @@ begin end; end; +function g_Map_CollideLiquid_TextureOld(X, Y: Integer; Width, Height: Word): DWORD; +var + texid: DWORD; + + function checkPanels (var panels: TPanelArray): Boolean; + var + a: Integer; + begin + result := false; + if panels = nil then exit; + for a := 0 to High(panels) do + begin + if g_Collide(X, Y, Width, Height, panels[a].X, panels[a].Y, panels[a].Width, panels[a].Height) then + begin + result := true; + texid := panels[a].GetTextureID(); + exit; + end; + end; + end; + +begin + texid := TEXTURE_NONE; + result := texid; + if not checkPanels(gWater) then + if not checkPanels(gAcid1) then + if not checkPanels(gAcid2) then exit; + result := texid; +end; + + function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; b1x3: Boolean): Boolean; - function qq (obj: TObject; tag: Integer): Boolean; + function checker (obj: TObject; tag: Integer): Boolean; var pan: TPanel; a: Integer; @@ -2272,7 +2192,7 @@ function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; pan := (obj as TPanel); a := pan.ArrIdx; - if WordBool(PanelType and PANEL_WALL) and WordBool(tag and PANEL_WALL) then + if WordBool(PanelType and PANEL_WALL) and (tag = GridTagWallDoor) then begin if gWalls[a].Enabled and g_Collide(X, Y, Width, Height, gWalls[a].X, gWalls[a].Y, gWalls[a].Width, gWalls[a].Height) then begin @@ -2281,7 +2201,7 @@ function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; end; end; - if WordBool(PanelType and PANEL_WATER) and WordBool(tag and PANEL_WATER) then + if WordBool(PanelType and PANEL_WATER) and (tag = GridTagWater) then begin if g_Collide(X, Y, Width, Height, gWater[a].X, gWater[a].Y, gWater[a].Width, gWater[a].Height) then begin @@ -2290,7 +2210,7 @@ function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; end; end; - if WordBool(PanelType and PANEL_ACID1) and WordBool(tag and PANEL_ACID1) then + if WordBool(PanelType and PANEL_ACID1) and (tag = GridTagAcid1) then begin if g_Collide(X, Y, Width, Height, gAcid1[a].X, gAcid1[a].Y, gAcid1[a].Width, gAcid1[a].Height) then begin @@ -2299,7 +2219,7 @@ function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; end; end; - if WordBool(PanelType and PANEL_ACID2) and WordBool(tag and PANEL_ACID2) then + if WordBool(PanelType and PANEL_ACID2) and (tag = GridTagAcid2) then begin if g_Collide(X, Y, Width, Height, gAcid2[a].X, gAcid2[a].Y, gAcid2[a].Width, gAcid2[a].Height) then begin @@ -2308,7 +2228,7 @@ function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; end; end; - if WordBool(PanelType and PANEL_STEP) and WordBool(tag and PANEL_STEP) then + if WordBool(PanelType and PANEL_STEP) and (tag = GridTagStep) then begin if g_Collide(X, Y, Width, Height, gSteps[a].X, gSteps[a].Y, gSteps[a].Width, gSteps[a].Height) then begin @@ -2316,99 +2236,144 @@ function g_Map_CollidePanel(X, Y: Integer; Width, Height: Word; PanelType: Word; exit; end; end; - end; -var - a, h: Integer; -begin - result := gMapGrid.forEachInAABB(X, Y, Width, Height, qq); - if not result then - begin - if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) and (gLifts <> nil) then + if WordBool(PanelType and (PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT)) and (tag = GridTagLift) then begin - h := High(gLifts); - for a := 0 to h do + if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or + (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or + (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or + (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and + g_Collide(X, Y, Width, Height, gLifts[a].X, gLifts[a].Y, gLifts[a].Width, gLifts[a].Height) then begin - if ((WordBool(PanelType and (PANEL_LIFTUP)) and (gLifts[a].LiftType = 0)) or - (WordBool(PanelType and (PANEL_LIFTDOWN)) and (gLifts[a].LiftType = 1)) or - (WordBool(PanelType and (PANEL_LIFTLEFT)) and (gLifts[a].LiftType = 2)) or - (WordBool(PanelType and (PANEL_LIFTRIGHT)) and (gLifts[a].LiftType = 3))) and - g_Collide(X, Y, Width, Height, - gLifts[a].X, gLifts[a].Y, - gLifts[a].Width, gLifts[a].Height) then - begin - Result := True; - Exit; - end; + result := true; + exit; end; end; - if WordBool(PanelType and PANEL_BLOCKMON) and (gBlockMon <> nil) then + if WordBool(PanelType and PANEL_BLOCKMON) and (tag = GridTagBlockMon) then begin - h := High(gBlockMon); - for a := 0 to h do + if ((not b1x3) or ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64)) and + g_Collide(X, Y, Width, Height, gBlockMon[a].X, gBlockMon[a].Y, gBlockMon[a].Width, gBlockMon[a].Height) then begin - if ( (not b1x3) or - ((gBlockMon[a].Width + gBlockMon[a].Height) >= 64) ) and - g_Collide(X, Y, Width, Height, - gBlockMon[a].X, gBlockMon[a].Y, - gBlockMon[a].Width, gBlockMon[a].Height) then + result := True; + exit; + end; + end; + end; + +begin + //TODO: detailed profile + if (profMapCollision <> nil) then profMapCollision.sectionBeginAccum('wall coldet'); + try + if gdbg_map_use_grid_coldet then + begin + if gdbg_map_use_tree_coldet then + begin + result := (mapTree.aabbQuery(X, Y, Width, Height, checker, (GridTagWallDoor or GridTagWater or GridTagAcid1 or GridTagAcid2 or GridTagStep or GridTagLift or GridTagBlockMon)) <> nil); + if (gdbg_map_dump_coldet_tree_queries) and (mapTree.nodesVisited <> 0) then begin - Result := True; - Exit; + //e_WriteLog(Format('map collision: %d nodes visited (%d deep)', [mapTree.nodesVisited, mapTree.nodesDeepVisited]), MSG_NOTIFY); + g_Console_Add(Format('map collision: %d nodes visited (%d deep)', [mapTree.nodesVisited, mapTree.nodesDeepVisited])); end; + end + else + begin + result := gMapGrid.forEachInAABB(X, Y, Width, Height, checker); end; + end + else + begin + result := g_Map_CollidePanelOld(X, Y, Width, Height, PanelType, b1x3); end; + finally + if (profMapCollision <> nil) then profMapCollision.sectionEnd(); end; end; function g_Map_CollideLiquid_Texture(X, Y: Integer; Width, Height: Word): DWORD; var - a, h: Integer; -begin - Result := TEXTURE_NONE; + cctype: Integer = 3; // priority: 0: water, 1: acid1, 2: acid2; 3: others (nothing) + texid: DWORD; - if gWater <> nil then + // slightly different from the old code, but meh... + function checker (obj: TObject; tag: Integer): Boolean; + var + pan: TPanel; + a: Integer; begin - h := High(gWater); - - for a := 0 to h do - if g_Collide(X, Y, Width, Height, - gWater[a].X, gWater[a].Y, - gWater[a].Width, gWater[a].Height) then + 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 + if (tag = GridTagWater) then + begin + if g_Collide(X, Y, Width, Height, gWater[a].X, gWater[a].Y, gWater[a].Width, gWater[a].Height) then begin - Result := gWater[a].GetTextureID(); - Exit; + result := true; // water has highest priority, so stop right here + texid := gWater[a].GetTextureID(); + exit; end; - end; - - if gAcid1 <> nil then - begin - h := High(gAcid1); - - for a := 0 to h do - if g_Collide(X, Y, Width, Height, - gAcid1[a].X, gAcid1[a].Y, - gAcid1[a].Width, gAcid1[a].Height) then + end; + // acid1 + if (cctype > 1) and (tag = GridTagAcid1) then + begin + if g_Collide(X, Y, Width, Height, gAcid1[a].X, gAcid1[a].Y, gAcid1[a].Width, gAcid1[a].Height) then begin - Result := gAcid1[a].GetTextureID(); - Exit; + cctype := 1; + texid := gAcid1[a].GetTextureID(); + exit; end; + end; + // acid2 + if (cctype > 2) and (tag = GridTagAcid2) then + begin + if g_Collide(X, Y, Width, Height, gAcid2[a].X, gAcid2[a].Y, gAcid2[a].Width, gAcid2[a].Height) then + begin + cctype := 2; + texid := gAcid2[a].GetTextureID(); + exit; + end; + end; end; - if gAcid2 <> nil then - begin - h := High(gAcid2); - - for a := 0 to h do - if g_Collide(X, Y, Width, Height, - gAcid2[a].X, gAcid2[a].Y, - gAcid2[a].Width, gAcid2[a].Height) then +{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 gdbg_map_use_grid_coldet then + begin + texid := TEXTURE_NONE; + if gdbg_map_use_tree_coldet then begin - Result := gAcid2[a].GetTextureID(); - Exit; + mapTree.aabbQuery(X, Y, Width, Height, checker); + { + 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 + result := g_Map_CollideLiquid_TextureOld(X, Y, Width, Height); + end; + finally + if (profMapCollision <> nil) then profMapCollision.sectionEnd(); end; end; @@ -2786,8 +2751,9 @@ begin LoadPanelArray(gLifts); ///// ///// -// Îáíîâëÿåì êàðòó ñòîëêíîâåíèé: +// Îáíîâëÿåì êàðòó ñòîëêíîâåíèé è ñåòêó: g_GFX_Init(); + mapCreateGrid(); ///// Çàãðóæàåì ìóçûêó: ///// // Ñèãíàòóðà ìóçûêè: