X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_map.pas;h=b2e35c0eb0b3044abc5308cd98354f286651a9c8;hb=422b1bad780adc75cee9edc8ef16092f29181951;hp=a754ff87211b1043a1e280662e771faabe7d99cc;hpb=984a31dcc2636073083a3a3cf8d4d409019d211a;p=d2df-sdl.git diff --git a/src/game/g_map.pas b/src/game/g_map.pas index a754ff8..b2e35c0 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -63,10 +63,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,8 +89,6 @@ 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); const @@ -148,8 +142,7 @@ uses Math, g_monsters, g_saveload, g_language, g_netmsg, utils, sfs, ImagingTypes, Imaging, ImagingUtility, - ImagingGif, ImagingNetworkGraphics, - libc; + ImagingGif, ImagingNetworkGraphics; const FLAGRECT: TRectWH = (X:15; Y:12; Width:33; Height:52); @@ -961,7 +954,7 @@ var var idx: Integer; begin - for idx := 0 to High(panels) do + for idx := High(panels) downto 0 do begin gMapGrid.insertBody(panels[idx], panels[idx].X, panels[idx].Y, panels[idx].Width, panels[idx].Height, tag); end; @@ -1743,11 +1736,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 @@ -1761,57 +1750,10 @@ begin 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 +1761,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,41 +1780,28 @@ 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; + +function dplLess (a, b: TObject): Boolean; +begin + result := ((a as TPanel).ArrIdx < (b as TPanel).ArrIdx); +end; procedure dplClear (); begin - gDrawPanelListUsed := 0; + if gDrawPanelList = nil then gDrawPanelList := TBinaryHeapObj.Create(@dplLess) else gDrawPanelList.clear(); end; procedure dplAddPanel (pan: TPanel); begin if pan = nil then exit; - if gDrawPanelListUsed = Length(gDrawPanelList) then SetLength(gDrawPanelList, gDrawPanelListUsed+4096); // arbitrary number - gDrawPanelList[gDrawPanelListUsed] := pan; - Inc(gDrawPanelListUsed); + gDrawPanelList.insert(pan); end; -function dplCompare (p0, p1: Pointer): LongInt; cdecl; -var - pan0, pan1: PPanel; -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; -end; - -procedure dplSort(); -begin - qsort(@gDrawPanelList[0], gDrawPanelListUsed, sizeof(TPanel), &dplCompare); -end; procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word); @@ -2019,7 +1832,7 @@ procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word); 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); + //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; end @@ -2028,7 +1841,7 @@ procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word); 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); + //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; end @@ -2038,88 +1851,82 @@ procedure g_Map_DrawPanels(x0, y0, wdt, hgt: Integer; PanelType: Word); 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); + //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; 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; - dplClear(); -end; - -var - plpset: array of Integer = nil; // potentially lit panels - plpcount: Integer; // to avoid constant reallocations - -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 + procedure DrawPanels (stp: Integer; var panels: TPanelArray; drawDoors: Boolean=False); + var + idx: Integer; + pan: TPanel; begin - if panels <> nil then + if (panels <> nil) and (stp >= 0) and (stp <= 6) then begin + // alas, no visible set 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); + if not (drawDoors xor panels[idx].Door) then + begin + 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; + 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; - //e_WriteLog(Format('%d panels left out of %d', [plpcount, Length(panels)]), MSG_NOTIFY); end; end; - result := (plpcount > 0); + +begin + //g_Map_DrawPanelsOld(PanelType); exit; + //e_WriteLog('==================', MSG_NOTIFY); + //e_WriteLog(Format('***QQQ: qtag:%d', [PanelType]), MSG_NOTIFY); + dplClear(); + gMapGrid.forEachInAABB(x0, y0, wdt, hgt, qq); + + // debug + { + 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; + e_WriteLog('==================', MSG_NOTIFY); + } + + // 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; -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 qq (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 <> PANEL_WALL) 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 - begin - gWalls[plpset[idx]].DrawShadowVolume(lightX, lightY, radius); - end; + gMapGrid.forEachInAABB(lightX-radius, lightY-radius, radius*2, radius*2, qq); end; + procedure g_Map_DrawBack(dx, dy: Integer); begin if gDrawBackGround and (BackID <> DWORD(-1)) then