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.
This commit is contained in:
Tamás Bálint Misius 2023-12-08 22:10:35 +01:00
parent dd875987b9
commit f8ee7aa0f7
No known key found for this signature in database
GPG Key ID: 5B472A12F6ECA9F2
4 changed files with 78 additions and 44 deletions

View File

@ -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<false>(*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<false>(*sim, t, parts[i].x, parts[i].y, mr.vx, mr.vy);
if (!gn.success)
{
return;

View File

@ -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;
};

View File

@ -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<int> 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<bool PhotoelectricEffect, class Sim>
void PhotoelectricEffectHelper(Sim &sim, int x, int y);
template<>
void PhotoelectricEffectHelper<false, const Simulation>(const Simulation &sim, int x, int y)
{
}
template<>
void PhotoelectricEffectHelper<true, Simulation>(Simulation &sim, int x, int y)
{
sim.photoelectric_effect(x, y);
}
template<bool PhotoelectricEffect, class Sim>
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<PhotoelectricEffect, Sim>(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<false, const Simulation>(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<bool UpdateEmap, class Sim>
void UpdateEmapHelper(Sim &sim, int fin_x, int fin_y);
template<>
void UpdateEmapHelper<false, const Simulation>(const Simulation &sim, int fin_x, int fin_y)
{
}
template<>
void UpdateEmapHelper<true, Simulation>(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<bool UpdateEmap, class Sim>
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<UpdateEmap, Sim>(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<false, const Simulation>(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<true>(*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<true>(*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<true>(*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));

View File

@ -122,21 +122,24 @@ public:
std::unique_ptr<Snapshot> 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<bool UpdateEmap, class Sim>
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<bool PhotoelectricEffect, class Sim>
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();
};