From f8ee7aa0f7798dcdae12bddeb5d6cbf70dd7f0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Fri, 8 Dec 2023 22:10:35 +0100 Subject: [PATCH] Sort out constness of Simulation::PlanMove And a bunch of other member functions. This got rid of some nasty assumptions documented only in the form of comments, in exchange for some nasty template nonsense. --- src/debug/SurfaceNormals.cpp | 6 +-- src/debug/SurfaceNormals.h | 4 +- src/simulation/Simulation.cpp | 92 ++++++++++++++++++++++++----------- src/simulation/Simulation.h | 20 ++++---- 4 files changed, 78 insertions(+), 44 deletions(-) diff --git a/src/debug/SurfaceNormals.cpp b/src/debug/SurfaceNormals.cpp index 9cf8e6da1..da034f796 100644 --- a/src/debug/SurfaceNormals.cpp +++ b/src/debug/SurfaceNormals.cpp @@ -6,7 +6,7 @@ #include "simulation/ElementClasses.h" #include "graphics/Graphics.h" -SurfaceNormals::SurfaceNormals(unsigned int id, Simulation *newSim, GameView *newView, GameController *newController) : +SurfaceNormals::SurfaceNormals(unsigned int id, const Simulation *newSim, GameView *newView, GameController *newController) : DebugInfo(id), sim(newSim), view(newView), controller(newController) { } @@ -29,7 +29,7 @@ void SurfaceNormals::Draw() auto &parts = sim->parts; auto x = int(parts[i].x + 0.5f); auto y = int(parts[i].y + 0.5f); - auto mr = sim->PlanMove(i, x, y, false); + auto mr = Simulation::PlanMove(*sim, i, x, y); if (t == PT_PHOT) { if (parts[i].flags & FLAG_SKIPMOVE) @@ -48,7 +48,7 @@ void SurfaceNormals::Draw() } } } - auto gn = sim->get_normal_interp(t, parts[i].x, parts[i].y, mr.vx, mr.vy); + auto gn = sim->get_normal_interp(*sim, t, parts[i].x, parts[i].y, mr.vx, mr.vy); if (!gn.success) { return; diff --git a/src/debug/SurfaceNormals.h b/src/debug/SurfaceNormals.h index 48bcf5d96..5c767f1ea 100644 --- a/src/debug/SurfaceNormals.h +++ b/src/debug/SurfaceNormals.h @@ -6,12 +6,12 @@ class GameView; class GameController; class SurfaceNormals : public DebugInfo { - Simulation *sim; + const Simulation *sim; GameView *view; GameController *controller; public: - SurfaceNormals(unsigned int id, Simulation *newSim, GameView *newView, GameController *newController); + SurfaceNormals(unsigned int id, const Simulation *newSim, GameView *newView, GameController *newController); void Draw() override; }; diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index dab7bbd2e..a2fa78680 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -18,6 +18,11 @@ extern int Element_LOLZ_lolz[XRES/9][YRES/9]; extern int Element_LOVE_RuleTable[9][9]; extern int Element_LOVE_love[XRES/9][YRES/9]; +static float remainder_p(float x, float y) +{ + return std::fmod(x, y) + (x>=0 ? 0 : y); +} + MissingElements Simulation::Load(const GameSave *save, bool includePressure, Vec2 blockP) // block coordinates { MissingElements missingElements; @@ -1620,7 +1625,7 @@ void Simulation::photoelectric_effect(int nx, int ny)//create sparks from PHOT w } } -int Simulation::is_blocking(int t, int x, int y) +int Simulation::is_blocking(int t, int x, int y) const { if (t & REFRACT) { if (x<0 || y<0 || x>=XRES || y>=YRES) @@ -1633,7 +1638,7 @@ int Simulation::is_blocking(int t, int x, int y) return !eval_move(t, x, y, NULL); } -int Simulation::is_boundary(int pt, int x, int y) +int Simulation::is_boundary(int pt, int x, int y) const { if (!is_blocking(pt,x,y)) return 0; @@ -1642,7 +1647,7 @@ int Simulation::is_boundary(int pt, int x, int y) return 1; } -int Simulation::find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool reverse) +int Simulation::find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool reverse) const { static int dx[8] = {1,1,0,-1,-1,-1,0,1}; static int dy[8] = {0,1,1,1,0,-1,-1,-1}; @@ -1681,7 +1686,7 @@ int Simulation::find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool return 0; } -Simulation::GetNormalResult Simulation::get_normal(int pt, int x, int y, float dx, float dy) +Simulation::GetNormalResult Simulation::get_normal(int pt, int x, int y, float dx, float dy) const { int ldm, rdm, lm, rm; int lx, ly, lv, rx, ry, rv; @@ -1726,7 +1731,24 @@ Simulation::GetNormalResult Simulation::get_normal(int pt, int x, int y, float d return { true, nx, ny, lx, ly, rx, ry }; } -Simulation::GetNormalResult Simulation::get_normal_interp(int pt, float x0, float y0, float dx, float dy) + + +template +void PhotoelectricEffectHelper(Sim &sim, int x, int y); + +template<> +void PhotoelectricEffectHelper(const Simulation &sim, int x, int y) +{ +} + +template<> +void PhotoelectricEffectHelper(Simulation &sim, int x, int y) +{ + sim.photoelectric_effect(x, y); +} + +template +Simulation::GetNormalResult Simulation::get_normal_interp(Sim &sim, int pt, float x0, float y0, float dx, float dy) { int x, y, i; @@ -1740,7 +1762,7 @@ Simulation::GetNormalResult Simulation::get_normal_interp(int pt, float x0, floa { return { false }; } - if (is_boundary(pt, x, y)) + if (sim.is_boundary(pt, x, y)) break; x0 += dx; y0 += dy; @@ -1749,11 +1771,14 @@ Simulation::GetNormalResult Simulation::get_normal_interp(int pt, float x0, floa return { false }; if (pt == PT_PHOT) - photoelectric_effect(x, y); + PhotoelectricEffectHelper(sim, x, y); - return get_normal(pt, x, y, dx, dy); + return sim.get_normal(pt, x, y, dx, dy); } +template +Simulation::GetNormalResult Simulation::get_normal_interp(const Simulation &sim, int pt, float x0, float y0, float dx, float dy); + void Simulation::kill_part(int i)//kills particle number i { if (i < 0 || i >= NPART) @@ -2122,14 +2147,31 @@ void Simulation::delete_part(int x, int y)//calls kill_part with the particle lo kill_part(ID(i)); } -Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update_emap) +template +void UpdateEmapHelper(Sim &sim, int fin_x, int fin_y); + +template<> +void UpdateEmapHelper(const Simulation &sim, int fin_x, int fin_y) { +} + +template<> +void UpdateEmapHelper(Simulation &sim, int fin_x, int fin_y) +{ + if (sim.bmap[fin_y/CELL][fin_x/CELL]==WL_DETECT && sim.emap[fin_y/CELL][fin_x/CELL]<8) + sim.set_emap(fin_x/CELL, fin_y/CELL); +} + +template +Simulation::PlanMoveResult Simulation::PlanMove(Sim &sim, int i, int x, int y) +{ + auto &parts = sim.parts; + auto &bmap = sim.bmap; + auto &emap = sim.emap; + auto &pmap = sim.pmap; + auto edgeMode = sim.edgeMode; auto &sd = SimulationData::CRef(); auto &can_move = sd.can_move; - // This function would be const if not for calling set_emap if update_emap is true, - // and users of this function *expect* it to be const if update_emap is false. So - // whenever you change something here, make sure it compiles *as const* if you - // remove the set_emap call. auto t = parts[i].type; int fin_x, fin_y, clear_x, clear_y; float fin_xf, fin_yf, clear_xf, clear_yf; @@ -2205,7 +2247,7 @@ Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update } //block if particle can't move (0), or some special cases where it returns 1 (can_move = 3 but returns 1 meaning particle will be eaten) //also photons are still blocked (slowed down) by any particle (even ones it can move through), and absorb wall also blocks particles - int eval = eval_move(t, fin_x, fin_y, NULL); + int eval = sim.eval_move(t, fin_x, fin_y, NULL); if (!eval || (can_move[t][TYP(pmap[fin_y][fin_x])] == 3 && eval == 1) || (t == PT_PHOT && pmap[fin_y][fin_x]) || bmap[fin_y/CELL][fin_x/CELL]==WL_DESTROYALL || closedEholeStart!=(bmap[fin_y/CELL][fin_x/CELL] == WL_EHOLE && !emap[fin_y/CELL][fin_x/CELL])) { // found an obstacle @@ -2215,8 +2257,7 @@ Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update clear_y = (int)(clear_yf+0.5f); break; } - if (update_emap && bmap[fin_y/CELL][fin_x/CELL]==WL_DETECT && emap[fin_y/CELL][fin_x/CELL]<8) - set_emap(fin_x/CELL, fin_y/CELL); + UpdateEmapHelper(sim, fin_x, fin_y); } } return { @@ -2233,6 +2274,9 @@ Simulation::PlanMoveResult Simulation::PlanMove(int i, int x, int y, bool update }; } +template +Simulation::PlanMoveResult Simulation::PlanMove(const Simulation &sim, int i, int x, int y); + void Simulation::UpdateParticles(int start, int end) { //the main particle loop function, goes over all particles. @@ -2876,7 +2920,7 @@ killed: int fin_x, fin_y, clear_x, clear_y; float fin_xf, fin_yf, clear_xf, clear_yf; { - auto mr = PlanMove(i, x, y, true); + auto mr = PlanMove(*this, i, x, y); fin_x = mr.fin_x; fin_y = mr.fin_y; clear_x = mr.clear_x; @@ -2973,7 +3017,7 @@ killed: int lt_glas = (lt == PT_GLAS) || (lt == PT_BGLA); if ((rt_glas && !lt_glas) || (lt_glas && !rt_glas)) { - auto gn = get_normal_interp(REFRACT|t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy); + auto gn = get_normal_interp(*this, REFRACT|t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy); if (!gn.success) { kill_part(i); continue; @@ -3057,7 +3101,7 @@ killed: parts[i].ctype &= mask; } - auto gn = get_normal_interp(t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy); + auto gn = get_normal_interp(*this, t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy); if (gn.success) { auto nrx = gn.nx; @@ -3962,16 +4006,6 @@ Simulation::Simulation(): grav->gravity_mask(); } -int Simulation::remainder_p(int x, int y) -{ - return (x % y) + (x>=0 ? 0 : y); -} - -float Simulation::remainder_p(float x, float y) -{ - return std::fmod(x, y) + (x>=0 ? 0 : y); -} - constexpr size_t ce_log2(size_t n) { return ((n < 2) ? 1 : 1 + ce_log2(n / 2)); diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index 4a71591ba..c9530f041 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -122,21 +122,24 @@ public: std::unique_ptr CreateSnapshot() const; void Restore(const Snapshot &snap); - int is_blocking(int t, int x, int y); - int is_boundary(int pt, int x, int y); - int find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool reverse); + int is_blocking(int t, int x, int y) const; + int is_boundary(int pt, int x, int y) const; + int find_next_boundary(int pt, int *x, int *y, int dm, int *em, bool reverse) const; void photoelectric_effect(int nx, int ny); int do_move(int i, int x, int y, float nxf, float nyf); bool move(int i, int x, int y, float nxf, float nyf); int try_move(int i, int x, int y, int nx, int ny); int eval_move(int pt, int nx, int ny, unsigned *rr) const; + struct PlanMoveResult { int fin_x, fin_y, clear_x, clear_y; float fin_xf, fin_yf, clear_xf, clear_yf; float vx, vy; }; - PlanMoveResult PlanMove(int i, int x, int y, bool update_emap); + template + static PlanMoveResult PlanMove(Sim &sim, int i, int x, int y); + bool IsWallBlocking(int x, int y, int type) const; void create_cherenkov_photon(int pp); void create_gain_photon(int pp); @@ -207,16 +210,13 @@ public: float nx, ny; int lx, ly, rx, ry; }; - GetNormalResult get_normal(int pt, int x, int y, float dx, float dy); - GetNormalResult get_normal_interp(int pt, float x0, float y0, float dx, float dy); + GetNormalResult get_normal(int pt, int x, int y, float dx, float dy) const; + template + static GetNormalResult get_normal_interp(Sim &sim, int pt, float x0, float y0, float dx, float dy); void clear_sim(); Simulation(); ~Simulation(); - // These don't really belong anywhere at the moment, so go here for loop edge mode - static int remainder_p(int x, int y); - static float remainder_p(float x, float y); - private: CoordStack& getCoordStackSingleton(); };