From ec7e4d0515981f6f3503fc06552b73dfeaf8b3e6 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Wed, 16 Aug 2017 11:17:46 +0300 Subject: [PATCH] simplified grid code (removed alot of pasta); rendering on Another Station now seems to work --- src/game/g_grid.pas | 209 ++++++++++++++++++++++---------------------- src/game/g_map.pas | 175 ++++++++++++++----------------------- 2 files changed, 167 insertions(+), 217 deletions(-) diff --git a/src/game/g_grid.pas b/src/game/g_grid.pas index 900a366..ffa0520 100644 --- a/src/game/g_grid.pas +++ b/src/game/g_grid.pas @@ -62,6 +62,8 @@ type next: Integer; // in this cell; index in mCells end; + GridInternalCB = function (grida: Integer): Boolean is nested; // return `true` to stop + TBodyGrid = class(TObject) private mTileSize: Integer; @@ -85,6 +87,8 @@ type procedure insert (body: TBodyProxy); procedure remove (body: TBodyProxy); + function forGridRect (x, y, w, h: Integer; cb: GridInternalCB): Boolean; + public constructor Create (aPixWidth, aPixHeight: Integer; aTileSize: Integer=GridDefaultTileSize); destructor Destroy (); override; @@ -324,94 +328,80 @@ begin end; -procedure TBodyGrid.insert (body: TBodyProxy); +function TBodyGrid.forGridRect (x, y, w, h: Integer; cb: GridInternalCB): Boolean; var - dx, dy, gx, gy, cidx: Integer; + gx, gy: Integer; begin - if body = nil then exit; - if (body.mWidth < 1) or (body.mHeight < 1) then exit; - // out of grid? - if (body.mX+body.mWidth <= 0) or (body.mY+body.mHeight <= 0) then exit; - if (body.mX >= mWidth*mTileSize) or (body.mY >= mHeight*mTileSize) then exit; - //e_WriteLog(Format('grid: inserting body: (%d,%d)-(%dx%d)', [body.mX, body.mY, body.mWidth, body.mHeight]), MSG_NOTIFY); - gy := body.mY div mTileSize; - dy := 0; - while (dy < body.mHeight) do + result := false; + if (w < 1) or (h < 1) or not assigned(cb) then exit; + if (x+w <= 0) or (y+h <= 0) then exit; + if (x >= mWidth*mTileSize) or (y >= mHeight*mTileSize) then exit; + for gy := y div mTileSize to (y+h-1) div mTileSize do begin - if (gy >= 0) and (gy < mHeight) then + if (gy < 0) then continue; + if (gy >= mHeight) then break; + for gx := x div mTileSize to (x+w-1) div mTileSize do begin - dx := 0; - gx := body.mX div mTileSize; - while (dx < body.mWidth) do - begin - if (gx >= 0) and (gx < mWidth) then - begin - //e_WriteLog(Format(' 00: allocating cell for grid coords (%d,%d), body coords:(%d,%d)', [gx, gy, dx, dy]), MSG_NOTIFY); - cidx := allocCell(); - //e_WriteLog(Format(' 01: allocated cell for grid coords (%d,%d), body coords:(%d,%d): #%d', [gx, gy, dx, dy, cidx]), MSG_NOTIFY); - mCells[cidx].body := body; - mCells[cidx].next := mGrid[gy*mWidth+gx]; - mGrid[gy*mWidth+gx] := cidx; - //e_WriteLog(Format(' 02: put cell for grid coords (%d,%d), body coords:(%d,%d): #%d', [gx, gy, dx, dy, cidx]), MSG_NOTIFY); - end; - Inc(dx, mTileSize); - Inc(gx); - end; + if (gx < 0) then continue; + if (gx >= mWidth) then break; + if (cb(gy*mWidth+gx)) then begin result := true; exit; end; end; - Inc(dy, mTileSize); - Inc(gy); end; end; -// absolutely not tested -procedure TBodyGrid.remove (body: TBodyProxy); -var - dx, dy, gx, gy, idx, pidx, tmp: Integer; +procedure TBodyGrid.insert (body: TBodyProxy); + + function inserter (grida: Integer): Boolean; + var + cidx: Integer; + begin + result := false; // never stop + // add body to the given grid cell + cidx := allocCell(); + //e_WriteLog(Format(' 01: allocated cell for grid coords (%d,%d), body coords:(%d,%d): #%d', [gx, gy, dx, dy, cidx]), MSG_NOTIFY); + mCells[cidx].body := body; + mCells[cidx].next := mGrid[grida]; + mGrid[grida] := cidx; + end; + begin if body = nil then exit; - if (body.mWidth < 1) or (body.mHeight < 1) then exit; - // out of grid? - if (body.mX+body.mWidth <= 0) or (body.mY+body.mHeight <= 0) then exit; - if (body.mX >= mWidth*mTileSize) or (body.mY >= mHeight*mTileSize) then exit; - gy := body.mY div mTileSize; - dy := 0; - pidx := -1; - while (dy < body.mHeight) do + forGridRect(body.mX, body.mY, body.mWidth, body.mHeight, inserter); +end; + + +// absolutely not tested +procedure TBodyGrid.remove (body: TBodyProxy); + + function remover (grida: Integer): Boolean; + var + pidx, idx, tmp: Integer; begin - if (gy >= 0) and (gy < mHeight) then + result := false; // never stop + // find and remove cell + pidx := -1; + idx := mGrid[grida]; + while idx >= 0 do begin - dx := 0; - gx := body.mX div mTileSize; - while (dx < body.mWidth) do + tmp := mCells[idx].next; + if (mCells[idx].body = body) then + begin + if (pidx = -1) then mGrid[grida] := tmp else mCells[pidx].next := tmp; + freeCell(idx); + break; // assume that we cannot have one object added to bucket twice + end + else begin - if (gx >= 0) and (gx < mWidth) then - begin - // find and remove cell - pidx := -1; - idx := mGrid[gy*mWidth+gx]; - while idx >= 0 do - begin - tmp := mCells[idx].next; - if mCells[idx].body = body then - begin - if pidx = -1 then mGrid[gy*mWidth+gx] := tmp else mCells[pidx].next := tmp; - freeCell(idx); - end - else - begin - pidx := idx; - end; - idx := tmp; - end; - end; - Inc(dx, mTileSize); - Inc(gx); + pidx := idx; end; + idx := tmp; end; - Inc(dy, mTileSize); - Inc(gy); end; + +begin + if body = nil then exit; + forGridRect(body.mX, body.mY, body.mWidth, body.mHeight, remover); end; @@ -459,20 +449,30 @@ end; function TBodyGrid.forEachInAABB (x, y, w, h: Integer; cb: GridQueryCB): Boolean; + function iterator (grida: Integer): Boolean; + var + idx: Integer; + begin + result := false; + idx := mGrid[grida]; + while idx >= 0 do + begin + if (mCells[idx].body <> nil) and (mCells[idx].body.mQueryMark <> mLastQuery) then + begin + //e_WriteLog(Format(' query #%d body hit: (%d,%d)-(%dx%d) tag:%d', [mLastQuery, mCells[idx].body.mX, mCells[idx].body.mY, mCells[idx].body.mWidth, mCells[idx].body.mHeight, mCells[idx].body.mTag]), MSG_NOTIFY); + mCells[idx].body.mQueryMark := mLastQuery; + if (cb(mCells[idx].body.mObj, mCells[idx].body.mTag)) then begin result := true; exit; end; + end; + idx := mCells[idx].next; + end; + end; + var - gx, gy, idx: Integer; - minx, miny, maxx, maxy: Integer; + idx: Integer; begin result := false; if not assigned(cb) then exit; - if (w < 1) or (h < 1) then exit; - minx := x; - miny := y; - maxx := x+w-1; - maxy := y+h-1; - if (minx > maxx) or (miny > maxy) then exit; - if (maxx < 0) or (maxy < 0) then exit; - if (minx >= mWidth*mTileSize) or (miny >= mHeight*mTileSize) then exit; + // increase query counter Inc(mLastQuery); if (mLastQuery = 0) then @@ -482,41 +482,38 @@ begin for idx := 0 to High(mCells) do if (mCells[idx].body <> nil) then mCells[idx].body.mQueryMark := 0; end; //e_WriteLog(Format('grid: query #%d: (%d,%d)-(%dx%d)', [mLastQuery, minx, miny, maxx, maxy]), MSG_NOTIFY); - // process grid - for gy := miny div mTileSize to maxy div mTileSize do - begin - if (gy < 0) then continue; - if (gy >= mHeight) then break; - for gx := minx div mTileSize to maxx div mTileSize do - begin - if (gx < 0) then continue; - if (gx >= mWidth) then break; - idx := mGrid[gy*mWidth+gx]; - while idx >= 0 do - begin - if (mCells[idx].body <> nil) and (mCells[idx].body.mQueryMark <> mLastQuery) then - begin - //e_WriteLog(Format(' query #%d body hit: (%d,%d)-(%dx%d) tag:%d', [mLastQuery, mCells[idx].body.mX, mCells[idx].body.mY, mCells[idx].body.mWidth, mCells[idx].body.mHeight, mCells[idx].body.mTag]), MSG_NOTIFY); - mCells[idx].body.mQueryMark := mLastQuery; - if (cb(mCells[idx].body.mObj, mCells[idx].body.mTag)) then begin result := true; exit; end; - end; - idx := mCells[idx].next; - end; - end; - end; + + result := forGridRect(x, y, w, h, iterator); end; function TBodyGrid.getProxyForBody (aObj: TObject; x, y, w, h: Integer): TBodyProxy; +var + res: TBodyProxy = nil; - function qq (obj: TObject; tag: Integer): Boolean; + function iterator (grida: Integer): Boolean; + var + idx: Integer; begin - result := (obj = aObj); + result := false; + idx := mGrid[grida]; + while idx >= 0 do + begin + if (mCells[idx].body <> nil) and (mCells[idx].body = aObj) then + begin + result := true; + res := mCells[idx].body; + exit; + end; + idx := mCells[idx].next; + end; end; begin result := nil; - forEachInAABB(x, y, w, h, qq); + if (aObj = nil) then exit; + forGridRect(x, y, w, h, iterator); + result := res; end; diff --git a/src/game/g_map.pas b/src/game/g_map.pas index d3ac7e0..53b4ae2 100644 --- a/src/game/g_map.pas +++ b/src/game/g_map.pas @@ -960,7 +960,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,7 +1743,7 @@ end; var - pvpset: array of PPanel = nil; // potentially lit panels + pvpset: array of TPanel = 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 @@ -1789,7 +1789,7 @@ var 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]; + pvpset[pvpcount] := panels[idx]; Inc(pvpcount); end; pvpe[stp] := pvpcount-1; @@ -1810,7 +1810,7 @@ begin //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 @@ -1840,109 +1840,7 @@ procedure g_Map_DrawPanelsOld(x0, y0, wdt, hgt: Integer; PanelType: Word); 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 - 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; - 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); @@ -1953,7 +1851,6 @@ begin PANEL_ACID2: DrawPanels(5, gAcid2); PANEL_STEP: DrawPanels(6, gSteps); end; - *) end; @@ -2006,7 +1903,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 @@ -2015,7 +1912,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 @@ -2025,16 +1922,72 @@ 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; + 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 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 + pan := panels[idx]; + 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 + 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 + pan := pvpset[idx]; + 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; + end; + end; + end; + begin - //e_WriteLog(Format('QQQ: qtag:%d', [PanelType]), MSG_NOTIFY); + //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 -- 2.29.2