From 5599208111f3a6c4f303cb719a26e8e405e82a69 Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Wed, 23 Aug 2017 20:42:46 +0300 Subject: [PATCH] fixed bug in grid raytracer: use `const`, Luke! --- src/game/g_grid.pas | 65 +++++++++++++++++++++++++++++++++---------- src/game/g_holmes.pas | 51 +++++++++++++++++++++++++++++++-- 2 files changed, 100 insertions(+), 16 deletions(-) diff --git a/src/game/g_grid.pas b/src/game/g_grid.pas index 81f19c1..2e7105e 100644 --- a/src/game/g_grid.pas +++ b/src/game/g_grid.pas @@ -15,6 +15,9 @@ *) // universal spatial grid {$INCLUDE ../shared/a_modes.inc} +{$IF DEFINED(D2F_DEBUG)} + {.$DEFINE D2F_DEBUG_RAYTRACE} +{$ENDIF} unit g_grid; interface @@ -84,6 +87,9 @@ type public dbgShowTraceLog: Boolean; + {$IF DEFINED(D2F_DEBUG)} + dbgRayTraceTileHitCB: TCellQueryCB; + {$ENDIF} private function allocCell (): Integer; @@ -136,13 +142,13 @@ type // you can set enabled/disabled flag, tho (but iterator can still return objects disabled inside it) // cb with `(nil)` will be called before processing new tile // no callback: return `true` on the nearest hit - function traceRay (x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP; overload; - function traceRay (out ex, ey: Integer; ax0, ay0, ax1, ay1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP; + function traceRay (const x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP; overload; + function traceRay (out ex, ey: Integer; const ax0, ay0, ax1, ay1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP; //WARNING: don't modify grid while any query is in progress (no checks are made!) // you can set enabled/disabled flag, tho (but iterator can still return objects disabled inside it) // trace line along the grid, calling `cb` for all objects in passed cells, in no particular order - function forEachAlongLine (x0, y0, x1, y1: Integer; cb: TGridAlongQueryCB; tagmask: Integer=-1; log: Boolean=false): ITP; + function forEachAlongLine (const x0, y0, x1, y1: Integer; cb: TGridAlongQueryCB; tagmask: Integer=-1; log: Boolean=false): ITP; // debug procedure forEachBodyCell (body: TBodyProxyId; cb: TCellQueryCB); @@ -367,6 +373,9 @@ var idx: Integer; begin dbgShowTraceLog := false; + {$IF DEFINED(D2F_DEBUG)} + dbgRayTraceTileHitCB := nil; + {$ENDIF} { if aTileSize < 1 then aTileSize := 1; if aTileSize > 8192 then aTileSize := 8192; // arbitrary limit @@ -1111,7 +1120,7 @@ end; // ////////////////////////////////////////////////////////////////////////// // // no callback: return `true` on the nearest hit -function TBodyGridBase.traceRay (x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP; +function TBodyGridBase.traceRay (const x0, y0, x1, y1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP; var ex, ey: Integer; begin @@ -1121,7 +1130,7 @@ end; // no callback: return `true` on the nearest hit // you are not supposed to understand this -function TBodyGridBase.traceRay (out ex, ey: Integer; ax0, ay0, ax1, ay1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP; +function TBodyGridBase.traceRay (out ex, ey: Integer; const ax0, ay0, ax1, ay1: Integer; cb: TGridRayQueryCB; tagmask: Integer=-1): ITP; const tsize = mTileSize; var @@ -1169,6 +1178,10 @@ begin maxx := gw*tsize-1; maxy := gh*tsize-1; + {$IF DEFINED(D2F_DEBUG_RAYTRACE)} + if assigned(dbgRayTraceTileHitCB) then e_WriteLog(Format('TRACING: (%d,%d)-(%d,%d) [(%d,%d)-(%d,%d)]; maxdistsq=%d', [ax0, ay0, ax1, ay1, minx, miny, maxx, maxy, lastDistSq]), MSG_NOTIFY); + {$ENDIF} + x0 := ax0; y0 := ay0; x1 := ax1; @@ -1309,16 +1322,20 @@ begin if (xd = term) then exit; {$IF DEFINED(D2F_DEBUG)} - if (xptr^ < 0) or (yptr^ < 0) or (xptr^ >= gw*tsize) and (yptr^ > mHeight*tsize) then raise Exception.Create('raycaster internal error (0)'); + if (xptr^ < 0) or (yptr^ < 0) or (xptr^ >= gw*tsize) and (yptr^ >= gh*tsize) then raise Exception.Create('raycaster internal error (0)'); {$ENDIF} + lastGA := (yptr^ div tsize)*gw+(xptr^ div tsize); + ccidx := mGrid[lastGA]; - //if (dbgShowTraceLog) then e_WriteLog(Format('raycast start: (%d,%d)-(%d,%d); xptr^=%d; yptr^=%d', [ax0, ay0, ax1, ay1, xptr^, yptr^]), MSG_NOTIFY); + {$IF DEFINED(D2F_DEBUG_RAYTRACE)} + //if assigned(dbgRayTraceTileHitCB) then e_WriteLog('1:TRACING!', MSG_NOTIFY); + {$ENDIF} - // restore query coords - Inc(ax0, minx); - Inc(ay0, miny); - //Inc(ax1, minx); - //Inc(ay1, miny); + {$IF DEFINED(D2F_DEBUG_RAYTRACE)} + if assigned(dbgRayTraceTileHitCB) then dbgRayTraceTileHitCB((xptr^ div tsize*tsize)+minx, (yptr^ div tsize*tsize)+miny); + {$ENDIF} + + //if (dbgShowTraceLog) then e_WriteLog(Format('raycast start: (%d,%d)-(%d,%d); xptr^=%d; yptr^=%d', [ax0, ay0, ax1, ay1, xptr^, yptr^]), MSG_NOTIFY); // increase query counter Inc(mLastQuery); @@ -1336,13 +1353,16 @@ begin begin // check cell(s) {$IF DEFINED(D2F_DEBUG)} - if (xptr^ < 0) or (yptr^ < 0) or (xptr^ >= gw*tsize) and (yptr^ > mHeight*tsize) then raise Exception.Create('raycaster internal error (0)'); + if (xptr^ < 0) or (yptr^ < 0) or (xptr^ >= gw*tsize) and (yptr^ >= gh*tsize) then raise Exception.Create('raycaster internal error (0)'); {$ENDIF} // new tile? ga := (yptr^ div tsize)*gw+(xptr^ div tsize); if (ga <> lastGA) then begin // yes + {$IF DEFINED(D2F_DEBUG)} + if assigned(dbgRayTraceTileHitCB) then dbgRayTraceTileHitCB((xptr^ div tsize*tsize)+minx, (yptr^ div tsize*tsize)+miny); + {$ENDIF} if (ccidx <> -1) then begin // signal cell completion @@ -1392,11 +1412,28 @@ begin ey := prevy; exit; end; + (* + {$IF DEFINED(D2F_DEBUG_RAYTRACE)} + distSq := distanceSq(ax0, ay0, prevx, prevy); + if assigned(dbgRayTraceTileHitCB) then e_WriteLog(Format(' hit(%d): a=(%d,%d), h=(%d,%d), p=(%d,%d); distsq=%d; lastsq=%d', [cc.bodies[f], ax0, ay0, x, y, prevx, prevy, distSq, lastDistSq]), MSG_NOTIFY); + if (distSq < lastDistSq) then + begin + wasHit := true; + lastDistSq := distSq; + ex := prevx; + ey := prevy; + lastObj := px.mObj; + end; + {$ENDIF} + *) end else begin // remember this hitpoint if it is nearer than an old one distSq := distanceSq(ax0, ay0, prevx, prevy); + {$IF DEFINED(D2F_DEBUG_RAYTRACE)} + if assigned(dbgRayTraceTileHitCB) then e_WriteLog(Format(' hit(%d): a=(%d,%d), h=(%d,%d), p=(%d,%d); distsq=%d; lastsq=%d', [cc.bodies[f], ax0, ay0, x, y, prevx, prevy, distSq, lastDistSq]), MSG_NOTIFY); + {$ENDIF} if (distSq < lastDistSq) then begin wasHit := true; @@ -1445,7 +1482,7 @@ end; // ////////////////////////////////////////////////////////////////////////// // //FIXME! optimize this with real tile walking -function TBodyGridBase.forEachAlongLine (x0, y0, x1, y1: Integer; cb: TGridAlongQueryCB; tagmask: Integer=-1; log: Boolean=false): ITP; +function TBodyGridBase.forEachAlongLine (const x0, y0, x1, y1: Integer; cb: TGridAlongQueryCB; tagmask: Integer=-1; log: Boolean=false): ITP; const tsize = mTileSize; var diff --git a/src/game/g_holmes.pas b/src/game/g_holmes.pas index 39669fa..210368d 100644 --- a/src/game/g_holmes.pas +++ b/src/game/g_holmes.pas @@ -103,6 +103,7 @@ var msB: Word = 0; // button state kbS: Word = 0; // keyboard modifiers state showMonsInfo: Boolean = false; + showMonsLOS2Plr: Boolean = false; // ////////////////////////////////////////////////////////////////////////// // @@ -248,6 +249,20 @@ procedure plrDebugDraw (); fillRect(cx, cy, monsGrid.tileSize, monsGrid.tileSize, 0, 128, 0, 64); end; + procedure hilightCell1 (cx, cy: Integer); + begin + //e_WriteLog(Format('h1: (%d,%d)', [cx, cy]), MSG_NOTIFY); + fillRect(cx, cy, monsGrid.tileSize, monsGrid.tileSize, 255, 255, 0, 92); + end; + + function hilightWallTrc (pan: TPanel; tag: Integer; x, y, prevx, prevy: Integer): Boolean; + begin + result := false; // don't stop + if (pan = nil) then exit; // cell completion, ignore + //e_WriteLog(Format('h1: (%d,%d)', [cx, cy]), MSG_NOTIFY); + fillRect(pan.X, pan.Y, pan.Width, pan.Height, 0, 128, 128, 64); + end; + function monsCollector (mon: TMonster; tag: Integer): Boolean; var ex, ey: Integer; @@ -288,11 +303,35 @@ procedure plrDebugDraw (); exit; end; mon.getMapBox(mx, my, mw, mh); - drawLine(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, 255, 0, 0, 128); + drawLine(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, 255, 0, 0, 255); + if (g_Map_traceToNearestWall(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, @ex, @ey) <> nil) then + begin + drawLine(mx+mw div 2, my+mh div 2, ex, ey, 0, 255, 0, 255); + end; + end; + + procedure drawLOS2Plr (); + var + emx, emy, emw, emh: Integer; + eplr: TPlayer; + ex, ey: Integer; + begin + eplr := gPlayers[0]; + if (eplr = nil) then exit; + eplr.getMapBox(emx, emy, emw, emh); + mon.getMapBox(mx, my, mw, mh); + drawLine(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, 255, 0, 0, 255); + {$IF DEFINED(D2F_DEBUG)} + //mapGrid.dbgRayTraceTileHitCB := hilightCell1; + {$ENDIF} if (g_Map_traceToNearestWall(mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, @ex, @ey) <> nil) then + //if (mapGrid.traceRay(ex, ey, mx+mw div 2, my+mh div 2, emx+emw div 2, emy+emh div 2, hilightWallTrc, (GridTagWall or GridTagDoor)) <> nil) then begin - drawLine(mx+mw div 2, my+mh div 2, ex, ey, 0, 255, 0, 128); + drawLine(mx+mw div 2, my+mh div 2, ex, ey, 0, 255, 0, 255); end; + {$IF DEFINED(D2F_DEBUG)} + //mapGrid.dbgRayTraceTileHitCB := nil; + {$ENDIF} end; begin @@ -325,6 +364,7 @@ procedure plrDebugDraw (); end; drawMonsterTargetLine(); + if showMonsLOS2Plr then drawLOS2Plr(); { property MonsterRemoved: Boolean read FRemoved write FRemoved; property MonsterPain: Integer read FPain write FPain; @@ -406,6 +446,13 @@ begin showMonsInfo := not showMonsInfo; exit; end; + // M-L: toggle monster LOS to player + if (ev.scan = SDL_SCANCODE_L) and ((ev.kstate and THKeyEvent.ModAlt) <> 0) then + begin + result := true; + showMonsLOS2Plr := not showMonsLOS2Plr; + exit; + end; end; end; -- 2.29.2