Sort out scopes in Simulation::UpdateParticles

This commit is contained in:
Tamás Bálint Misius
2023-10-22 10:27:50 +02:00
parent 1c1ef12761
commit edcbeaca56

View File

@@ -2229,27 +2229,16 @@ void Simulation::delete_part(int x, int y)//calls kill_part with the particle lo
void Simulation::UpdateParticles(int start, int end) void Simulation::UpdateParticles(int start, int end)
{ {
int i, j, x, y, t, r, surround_space, s, rt, nt;
float mv, dx, dy, nrx, nry, dp, ctemph, ctempl, gravtot;
int fin_x, fin_y, clear_x, clear_y, stagnant;
float fin_xf, fin_yf, clear_xf, clear_yf;
float nn, ct1, ct2, swappage;
float pt = R_TEMP;
float c_heat = 0.0f;
int h_count = 0;
int surround[8];
int surround_hconduct[8];
bool transitionOccurred;
//the main particle loop function, goes over all particles. //the main particle loop function, goes over all particles.
for (i = start; i < end && i <= parts_lastActiveIndex; i++) for (auto i = start; i < end && i <= parts_lastActiveIndex; i++)
{
if (parts[i].type) if (parts[i].type)
{ {
debug_mostRecentlyUpdated = i; debug_mostRecentlyUpdated = i;
t = parts[i].type; auto t = parts[i].type;
x = (int)(parts[i].x+0.5f); auto x = (int)(parts[i].x+0.5f);
y = (int)(parts[i].y+0.5f); auto y = (int)(parts[i].y+0.5f);
// Kill a particle off screen // Kill a particle off screen
if (x<CELL || y<CELL || x>=XRES-CELL || y>=YRES-CELL) if (x<CELL || y<CELL || x>=XRES-CELL || y>=YRES-CELL)
@@ -2345,18 +2334,28 @@ void Simulation::UpdateParticles(int start, int end)
#endif #endif
} }
transitionOccurred = false; auto transitionOccurred = false;
j = surround_space = nt = 0;//if nt is greater than 1 after this, then there is a particle around the current particle, that is NOT the current particle's type, for water movement. int surround[8];
for (auto nx=-1; nx<2; nx++) auto surround_space = 0;
for (auto ny=-1; ny<2; ny++) { auto nt = 0; //if nt is greater than 1 after this, then there is a particle around the current particle, that is NOT the current particle's type, for water movement.
if (nx||ny) { {
surround[j] = r = pmap[y+ny][x+nx]; auto j = 0;
j++; for (auto nx=-1; nx<2; nx++)
surround_space += (!TYP(r)); // count empty space {
nt += (TYP(r)!=t); // count empty space and particles of different type for (auto ny=-1; ny<2; ny++)
{
if (nx||ny)
{
auto r = pmap[y+ny][x+nx];
surround[j] = r;
j++;
surround_space += (!TYP(r)); // count empty space
nt += (TYP(r)!=t); // count empty space and particles of different type
}
} }
} }
}
float gel_scale = 1.0f; float gel_scale = 1.0f;
if (t==PT_GEL) if (t==PT_GEL)
@@ -2371,10 +2370,10 @@ void Simulation::UpdateParticles(int start, int end)
auto offsetX = int(std::round(convGravX + x)); auto offsetX = int(std::round(convGravX + x));
auto offsetY = int(std::round(convGravY + y)); auto offsetY = int(std::round(convGravY + y));
if ((offsetX != x || offsetY != y) && offsetX >= 0 && offsetX < XRES && offsetY >= 0 && offsetY < YRES) {//some heat convection for liquids if ((offsetX != x || offsetY != y) && offsetX >= 0 && offsetX < XRES && offsetY >= 0 && offsetY < YRES) {//some heat convection for liquids
r = pmap[offsetY][offsetX]; auto r = pmap[offsetY][offsetX];
if (!(!r || parts[i].type != TYP(r))) { if (!(!r || parts[i].type != TYP(r))) {
if (parts[i].temp>parts[ID(r)].temp) { if (parts[i].temp>parts[ID(r)].temp) {
swappage = parts[i].temp; auto swappage = parts[i].temp;
parts[i].temp = parts[ID(r)].temp; parts[i].temp = parts[ID(r)].temp;
parts[ID(r)].temp = swappage; parts[ID(r)].temp = swappage;
} }
@@ -2383,42 +2382,43 @@ void Simulation::UpdateParticles(int start, int end)
} }
//heat transfer code //heat transfer code
h_count = 0;
#ifdef REALISTIC #ifdef REALISTIC
if (t&&(t!=PT_HSWC||parts[i].life==10)&&(elements[t].HeatConduct*gel_scale)) if (t&&(t!=PT_HSWC||parts[i].life==10)&&(elements[t].HeatConduct*gel_scale))
#else #else
auto h_count = 0;
if (t && (t!=PT_HSWC||parts[i].life==10) && rng.chance(int(elements[t].HeatConduct*gel_scale), 250)) if (t && (t!=PT_HSWC||parts[i].life==10) && rng.chance(int(elements[t].HeatConduct*gel_scale), 250))
#endif #endif
{ {
if (aheat_enable && !(elements[t].Properties&PROP_NOAMBHEAT)) if (aheat_enable && !(elements[t].Properties&PROP_NOAMBHEAT))
{ {
#ifdef REALISTIC #ifdef REALISTIC
c_heat = parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight) + hv[y/CELL][x/CELL]*100*(pv[y/CELL][x/CELL]-MIN_PRESSURE)/(MAX_PRESSURE-MIN_PRESSURE)*2; auto c_heat = parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight) + hv[y/CELL][x/CELL]*100*(pv[y/CELL][x/CELL]-MIN_PRESSURE)/(MAX_PRESSURE-MIN_PRESSURE)*2;
float c_Cm = 96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight) + 100*(pv[y/CELL][x/CELL]-MIN_PRESSURE)/(MAX_PRESSURE-MIN_PRESSURE)*2; float c_Cm = 96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight) + 100*(pv[y/CELL][x/CELL]-MIN_PRESSURE)/(MAX_PRESSURE-MIN_PRESSURE)*2;
pt = c_heat/c_Cm; auto pt = c_heat/c_Cm;
pt = restrict_flt(pt, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP); pt = restrict_flt(pt, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP);
parts[i].temp = pt; parts[i].temp = pt;
//Pressure increase from heat (temporary) //Pressure increase from heat (temporary)
pv[y/CELL][x/CELL] += (pt-hv[y/CELL][x/CELL])*0.004; pv[y/CELL][x/CELL] += (pt-hv[y/CELL][x/CELL])*0.004;
hv[y/CELL][x/CELL] = pt; hv[y/CELL][x/CELL] = pt;
#else #else
c_heat = (hv[y/CELL][x/CELL]-parts[i].temp)*0.04; auto c_heat = (hv[y/CELL][x/CELL]-parts[i].temp)*0.04;
c_heat = restrict_flt(c_heat, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP); c_heat = restrict_flt(c_heat, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP);
parts[i].temp += c_heat; parts[i].temp += c_heat;
hv[y/CELL][x/CELL] -= c_heat; hv[y/CELL][x/CELL] -= c_heat;
#endif #endif
} }
c_heat = 0.0f; auto c_heat = 0.0f;
#ifdef REALISTIC #ifdef REALISTIC
float c_Cm = 0.0f; float c_Cm = 0.0f;
#endif #endif
for (j=0; j<8; j++) int surround_hconduct[8];
for (auto j=0; j<8; j++)
{ {
surround_hconduct[j] = i; surround_hconduct[j] = i;
r = surround[j]; auto r = surround[j];
if (!r) if (!r)
continue; continue;
rt = TYP(r); auto rt = TYP(r);
if (rt && elements[rt].HeatConduct && (rt!=PT_HSWC||parts[ID(r)].life==10) if (rt && elements[rt].HeatConduct && (rt!=PT_HSWC||parts[ID(r)].life==10)
&& (t!=PT_FILT||(rt!=PT_BRAY&&rt!=PT_BIZR&&rt!=PT_BIZRG)) && (t!=PT_FILT||(rt!=PT_BRAY&&rt!=PT_BIZR&&rt!=PT_BIZRG))
&& (rt!=PT_FILT||(t!=PT_BRAY&&t!=PT_PHOT&&t!=PT_BIZR&&t!=PT_BIZRG)) && (rt!=PT_FILT||(t!=PT_BRAY&&t!=PT_PHOT&&t!=PT_BIZR&&t!=PT_BIZRG))
@@ -2441,6 +2441,7 @@ void Simulation::UpdateParticles(int start, int end)
h_count++; h_count++;
} }
} }
float pt = R_TEMP;
#ifdef REALISTIC #ifdef REALISTIC
if (t==PT_GEL) if (t==PT_GEL)
gel_scale = parts[i].tmp*2.55f; gel_scale = parts[i].tmp*2.55f;
@@ -2457,13 +2458,14 @@ void Simulation::UpdateParticles(int start, int end)
#else #else
pt = (c_heat+parts[i].temp)/(h_count+1); pt = (c_heat+parts[i].temp)/(h_count+1);
pt = parts[i].temp = restrict_flt(pt, MIN_TEMP, MAX_TEMP); pt = parts[i].temp = restrict_flt(pt, MIN_TEMP, MAX_TEMP);
for (j=0; j<8; j++) for (auto j=0; j<8; j++)
{ {
parts[surround_hconduct[j]].temp = pt; parts[surround_hconduct[j]].temp = pt;
} }
#endif #endif
ctemph = ctempl = pt; auto ctemph = pt;
auto ctempl = pt;
// change boiling point with pressure // change boiling point with pressure
if (((elements[t].Properties&TYPE_LIQUID) && IsElementOrNone(elements[t].HighTemperatureTransition) && (elements[elements[t].HighTemperatureTransition].Properties&TYPE_GAS)) if (((elements[t].Properties&TYPE_LIQUID) && IsElementOrNone(elements[t].HighTemperatureTransition) && (elements[elements[t].HighTemperatureTransition].Properties&TYPE_GAS))
|| t==PT_LNTG || t==PT_SLTW) || t==PT_LNTG || t==PT_SLTW)
@@ -2471,7 +2473,7 @@ void Simulation::UpdateParticles(int start, int end)
else if (((elements[t].Properties&TYPE_GAS) && IsElementOrNone(elements[t].LowTemperatureTransition) && (elements[elements[t].LowTemperatureTransition].Properties&TYPE_LIQUID)) else if (((elements[t].Properties&TYPE_GAS) && IsElementOrNone(elements[t].LowTemperatureTransition) && (elements[elements[t].LowTemperatureTransition].Properties&TYPE_LIQUID))
|| t==PT_WTRV) || t==PT_WTRV)
ctempl -= 2.0f*pv[y/CELL][x/CELL]; ctempl -= 2.0f*pv[y/CELL][x/CELL];
s = 1; auto s = 1;
//A fix for ice with ctype = 0 //A fix for ice with ctype = 0
if ((t==PT_ICEI || t==PT_SNOW) && (!IsElement(parts[i].ctype) || parts[i].ctype==PT_ICEI || parts[i].ctype==PT_SNOW)) if ((t==PT_ICEI || t==PT_SNOW) && (!IsElement(parts[i].ctype) || parts[i].ctype==PT_ICEI || parts[i].ctype==PT_SNOW))
@@ -2665,7 +2667,7 @@ void Simulation::UpdateParticles(int start, int end)
s = 0; s = 0;
#ifdef REALISTIC #ifdef REALISTIC
pt = restrict_flt(pt, MIN_TEMP, MAX_TEMP); pt = restrict_flt(pt, MIN_TEMP, MAX_TEMP);
for (j=0; j<8; j++) for (auto j=0; j<8; j++)
{ {
parts[surround_hconduct[j]].temp = pt; parts[surround_hconduct[j]].temp = pt;
} }
@@ -2787,57 +2789,58 @@ void Simulation::UpdateParticles(int start, int end)
pv[y/CELL][x/CELL] += 0.25f * CFDS; pv[y/CELL][x/CELL] += 0.25f * CFDS;
} }
s = 1;
gravtot = fabs(gravy[(y/CELL)*XCELLS+(x/CELL)])+fabs(gravx[(y/CELL)*XCELLS+(x/CELL)]);
if (elements[t].HighPressureTransition>-1 && pv[y/CELL][x/CELL]>elements[t].HighPressure) {
// particle type change due to high pressure
if (elements[t].HighPressureTransition!=PT_NUM)
t = elements[t].HighPressureTransition;
else if (t==PT_BMTL) {
if (pv[y/CELL][x/CELL]>2.5f)
t = PT_BRMT;
else if (pv[y/CELL][x/CELL]>1.0f && parts[i].tmp==1)
t = PT_BRMT;
else s = 0;
}
else s = 0;
} else if (elements[t].LowPressureTransition>-1 && pv[y/CELL][x/CELL]<elements[t].LowPressure && gravtot<=(elements[t].LowPressure/4.0f)) {
// particle type change due to low pressure
if (elements[t].LowPressureTransition!=PT_NUM)
t = elements[t].LowPressureTransition;
else s = 0;
} else if (elements[t].HighPressureTransition>-1 && gravtot>(elements[t].HighPressure/4.0f)) {
// particle type change due to high gravity
if (elements[t].HighPressureTransition!=PT_NUM)
t = elements[t].HighPressureTransition;
else if (t==PT_BMTL) {
if (gravtot>0.625f)
t = PT_BRMT;
else if (gravtot>0.25f && parts[i].tmp==1)
t = PT_BRMT;
else s = 0;
}
else s = 0;
} else s = 0;
// particle type change occurred
if (s)
{ {
if (t == PT_NONE) auto s = 1;
auto gravtot = fabs(gravy[(y/CELL)*XCELLS+(x/CELL)])+fabs(gravx[(y/CELL)*XCELLS+(x/CELL)]);
if (elements[t].HighPressureTransition>-1 && pv[y/CELL][x/CELL]>elements[t].HighPressure) {
// particle type change due to high pressure
if (elements[t].HighPressureTransition!=PT_NUM)
t = elements[t].HighPressureTransition;
else if (t==PT_BMTL) {
if (pv[y/CELL][x/CELL]>2.5f)
t = PT_BRMT;
else if (pv[y/CELL][x/CELL]>1.0f && parts[i].tmp==1)
t = PT_BRMT;
else s = 0;
}
else s = 0;
} else if (elements[t].LowPressureTransition>-1 && pv[y/CELL][x/CELL]<elements[t].LowPressure && gravtot<=(elements[t].LowPressure/4.0f)) {
// particle type change due to low pressure
if (elements[t].LowPressureTransition!=PT_NUM)
t = elements[t].LowPressureTransition;
else s = 0;
} else if (elements[t].HighPressureTransition>-1 && gravtot>(elements[t].HighPressure/4.0f)) {
// particle type change due to high gravity
if (elements[t].HighPressureTransition!=PT_NUM)
t = elements[t].HighPressureTransition;
else if (t==PT_BMTL) {
if (gravtot>0.625f)
t = PT_BRMT;
else if (gravtot>0.25f && parts[i].tmp==1)
t = PT_BRMT;
else s = 0;
}
else s = 0;
} else s = 0;
// particle type change occurred
if (s)
{ {
kill_part(i); if (t == PT_NONE)
goto killed; {
kill_part(i);
goto killed;
}
parts[i].life = 0;
// part_change_type could refuse to change the type and kill the particle
// for example, changing type to STKM but one already exists
// we need to account for that to not cause simulation corruption issues
if (part_change_type(i,x,y,t))
goto killed;
if (t == PT_FIRE)
parts[i].life = rng.between(120, 169);
transitionOccurred = true;
} }
parts[i].life = 0;
// part_change_type could refuse to change the type and kill the particle
// for example, changing type to STKM but one already exists
// we need to account for that to not cause simulation corruption issues
if (part_change_type(i,x,y,t))
goto killed;
if (t == PT_FIRE)
parts[i].life = rng.between(120, 169);
transitionOccurred = true;
} }
//call the particle update function, if there is one //call the particle update function, if there is one
@@ -2862,57 +2865,44 @@ killed:
if (!parts[i].vx&&!parts[i].vy)//if its not moving, skip to next particle, movement code it next if (!parts[i].vx&&!parts[i].vy)//if its not moving, skip to next particle, movement code it next
continue; continue;
mv = fmaxf(fabsf(parts[i].vx), fabsf(parts[i].vy)); int fin_x, fin_y, clear_x, clear_y;
if (mv < ISTP) float fin_xf, fin_yf, clear_xf, clear_yf;
{ {
clear_x = x; auto mv = fmaxf(fabsf(parts[i].vx), fabsf(parts[i].vy));
clear_y = y; if (mv < ISTP)
clear_xf = parts[i].x;
clear_yf = parts[i].y;
fin_xf = clear_xf + parts[i].vx;
fin_yf = clear_yf + parts[i].vy;
fin_x = (int)(fin_xf+0.5f);
fin_y = (int)(fin_yf+0.5f);
}
else
{
if (mv > MAX_VELOCITY)
{ {
parts[i].vx *= MAX_VELOCITY/mv; clear_x = x;
parts[i].vy *= MAX_VELOCITY/mv; clear_y = y;
mv = MAX_VELOCITY; clear_xf = parts[i].x;
} clear_yf = parts[i].y;
// interpolate to see if there is anything in the way fin_xf = clear_xf + parts[i].vx;
dx = parts[i].vx*ISTP/mv; fin_yf = clear_yf + parts[i].vy;
dy = parts[i].vy*ISTP/mv;
fin_xf = parts[i].x;
fin_yf = parts[i].y;
fin_x = (int)(fin_xf+0.5f);
fin_y = (int)(fin_yf+0.5f);
bool closedEholeStart = InBounds(fin_x, fin_y) && (bmap[fin_y/CELL][fin_x/CELL] == WL_EHOLE && !emap[fin_y/CELL][fin_x/CELL]);
while (1)
{
mv -= ISTP;
fin_xf += dx;
fin_yf += dy;
fin_x = (int)(fin_xf+0.5f); fin_x = (int)(fin_xf+0.5f);
fin_y = (int)(fin_yf+0.5f); fin_y = (int)(fin_yf+0.5f);
if (edgeMode == EDGE_LOOP) }
else
{
if (mv > MAX_VELOCITY)
{ {
bool x_ok = (fin_xf >= CELL-.5f && fin_xf < XRES-CELL-.5f); parts[i].vx *= MAX_VELOCITY/mv;
bool y_ok = (fin_yf >= CELL-.5f && fin_yf < YRES-CELL-.5f); parts[i].vy *= MAX_VELOCITY/mv;
if (!x_ok) mv = MAX_VELOCITY;
fin_xf = remainder_p(fin_xf-CELL+.5f, XRES-CELL*2.0f)+CELL-.5f; }
if (!y_ok) // interpolate to see if there is anything in the way
fin_yf = remainder_p(fin_yf-CELL+.5f, YRES-CELL*2.0f)+CELL-.5f; auto dx = parts[i].vx*ISTP/mv;
auto dy = parts[i].vy*ISTP/mv;
fin_xf = parts[i].x;
fin_yf = parts[i].y;
fin_x = (int)(fin_xf+0.5f);
fin_y = (int)(fin_yf+0.5f);
bool closedEholeStart = InBounds(fin_x, fin_y) && (bmap[fin_y/CELL][fin_x/CELL] == WL_EHOLE && !emap[fin_y/CELL][fin_x/CELL]);
while (1)
{
mv -= ISTP;
fin_xf += dx;
fin_yf += dy;
fin_x = (int)(fin_xf+0.5f); fin_x = (int)(fin_xf+0.5f);
fin_y = (int)(fin_yf+0.5f); fin_y = (int)(fin_yf+0.5f);
}
if (mv <= 0.0f)
{
// nothing found
fin_xf = parts[i].x + parts[i].vx;
fin_yf = parts[i].y + parts[i].vy;
if (edgeMode == EDGE_LOOP) if (edgeMode == EDGE_LOOP)
{ {
bool x_ok = (fin_xf >= CELL-.5f && fin_xf < XRES-CELL-.5f); bool x_ok = (fin_xf >= CELL-.5f && fin_xf < XRES-CELL-.5f);
@@ -2921,33 +2911,50 @@ killed:
fin_xf = remainder_p(fin_xf-CELL+.5f, XRES-CELL*2.0f)+CELL-.5f; fin_xf = remainder_p(fin_xf-CELL+.5f, XRES-CELL*2.0f)+CELL-.5f;
if (!y_ok) if (!y_ok)
fin_yf = remainder_p(fin_yf-CELL+.5f, YRES-CELL*2.0f)+CELL-.5f; fin_yf = remainder_p(fin_yf-CELL+.5f, YRES-CELL*2.0f)+CELL-.5f;
fin_x = (int)(fin_xf+0.5f);
fin_y = (int)(fin_yf+0.5f);
} }
fin_x = (int)(fin_xf+0.5f); if (mv <= 0.0f)
fin_y = (int)(fin_yf+0.5f); {
clear_xf = fin_xf-dx; // nothing found
clear_yf = fin_yf-dy; fin_xf = parts[i].x + parts[i].vx;
clear_x = (int)(clear_xf+0.5f); fin_yf = parts[i].y + parts[i].vy;
clear_y = (int)(clear_yf+0.5f); if (edgeMode == EDGE_LOOP)
break; {
bool x_ok = (fin_xf >= CELL-.5f && fin_xf < XRES-CELL-.5f);
bool y_ok = (fin_yf >= CELL-.5f && fin_yf < YRES-CELL-.5f);
if (!x_ok)
fin_xf = remainder_p(fin_xf-CELL+.5f, XRES-CELL*2.0f)+CELL-.5f;
if (!y_ok)
fin_yf = remainder_p(fin_yf-CELL+.5f, YRES-CELL*2.0f)+CELL-.5f;
}
fin_x = (int)(fin_xf+0.5f);
fin_y = (int)(fin_yf+0.5f);
clear_xf = fin_xf-dx;
clear_yf = fin_yf-dy;
clear_x = (int)(clear_xf+0.5f);
clear_y = (int)(clear_yf+0.5f);
break;
}
//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);
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
clear_xf = fin_xf-dx;
clear_yf = fin_yf-dy;
clear_x = (int)(clear_xf+0.5f);
clear_y = (int)(clear_yf+0.5f);
break;
}
if (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);
} }
//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);
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
clear_xf = fin_xf-dx;
clear_yf = fin_yf-dy;
clear_x = (int)(clear_xf+0.5f);
clear_y = (int)(clear_yf+0.5f);
break;
}
if (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);
} }
} }
stagnant = parts[i].flags & FLAG_STAGNANT; auto stagnant = parts[i].flags & FLAG_STAGNANT;
parts[i].flags &= ~FLAG_STAGNANT; parts[i].flags &= ~FLAG_STAGNANT;
if (t==PT_STKM || t==PT_STKM2 || t==PT_FIGH) if (t==PT_STKM || t==PT_STKM2 || t==PT_FIGH)
@@ -3031,25 +3038,26 @@ killed:
int lt_glas = (lt == PT_GLAS) || (lt == PT_BGLA); int lt_glas = (lt == PT_GLAS) || (lt == PT_BGLA);
if ((rt_glas && !lt_glas) || (lt_glas && !rt_glas)) if ((rt_glas && !lt_glas) || (lt_glas && !rt_glas))
{ {
float nrx, nry;
if (!get_normal_interp(REFRACT|t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy, &nrx, &nry)) { if (!get_normal_interp(REFRACT|t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy, &nrx, &nry)) {
kill_part(i); kill_part(i);
continue; continue;
} }
r = get_wavelength_bin(&parts[i].ctype); auto r = get_wavelength_bin(&parts[i].ctype);
if (r == -1 || !(parts[i].ctype&0x3FFFFFFF)) if (r == -1 || !(parts[i].ctype&0x3FFFFFFF))
{ {
kill_part(i); kill_part(i);
continue; continue;
} }
nn = GLASS_IOR - GLASS_DISP*(r-30)/30.0f; auto nn = GLASS_IOR - GLASS_DISP*(r-30)/30.0f;
nn *= nn; nn *= nn;
auto enter = rt_glas && !lt_glas; auto enter = rt_glas && !lt_glas;
nrx = enter ? -nrx : nrx; nrx = enter ? -nrx : nrx;
nry = enter ? -nry : nry; nry = enter ? -nry : nry;
nn = enter ? 1.0f/nn : nn; nn = enter ? 1.0f/nn : nn;
ct1 = parts[i].vx*nrx + parts[i].vy*nry; auto ct1 = parts[i].vx*nrx + parts[i].vy*nry;
ct2 = 1.0f - (nn*nn)*(1.0f-(ct1*ct1)); auto ct2 = 1.0f - (nn*nn)*(1.0f-(ct1*ct1));
if (ct2 < 0.0f) { if (ct2 < 0.0f) {
// total internal reflection // total internal reflection
parts[i].vx -= 2.0f*ct1*nrx; parts[i].vx -= 2.0f*ct1*nrx;
@@ -3087,7 +3095,7 @@ killed:
kill_part(i); kill_part(i);
continue; continue;
} }
r = pmap[fin_y][fin_x]; auto r = pmap[fin_y][fin_x];
if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP) && !TYP(parts[ID(r)].ctype)) if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP) && !TYP(parts[ID(r)].ctype))
{ {
@@ -3113,6 +3121,7 @@ killed:
parts[i].ctype &= mask; parts[i].ctype &= mask;
} }
float nrx, nry;
if (get_normal_interp(t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy, &nrx, &nry)) if (get_normal_interp(t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy, &nrx, &nry))
{ {
if (TYP(r) == PT_CRMC) if (TYP(r) == PT_CRMC)
@@ -3122,13 +3131,13 @@ killed:
rx = cosf(r); ry = sinf(r); rx = cosf(r); ry = sinf(r);
anrx = rx * nrx + ry * nry; anrx = rx * nrx + ry * nry;
anry = rx * nry - ry * nrx; anry = rx * nry - ry * nrx;
dp = anrx*parts[i].vx + anry*parts[i].vy; auto dp = anrx*parts[i].vx + anry*parts[i].vy;
parts[i].vx -= 2.0f*dp*anrx; parts[i].vx -= 2.0f*dp*anrx;
parts[i].vy -= 2.0f*dp*anry; parts[i].vy -= 2.0f*dp*anry;
} }
else else
{ {
dp = nrx*parts[i].vx + nry*parts[i].vy; auto dp = nrx*parts[i].vx + nry*parts[i].vy;
parts[i].vx -= 2.0f*dp*nrx; parts[i].vx -= 2.0f*dp*nrx;
parts[i].vy -= 2.0f*dp*nry; parts[i].vy -= 2.0f*dp*nry;
} }
@@ -3201,17 +3210,16 @@ killed:
} }
else else
{ {
s = 1; auto r = rng.between(0, 1) * 2 - 1;// position search direction (left/right first)
r = rng.between(0, 1) * 2 - 1;// position search direction (left/right first)
if ((clear_x!=x || clear_y!=y || nt || surround_space) && if ((clear_x!=x || clear_y!=y || nt || surround_space) &&
(fabsf(parts[i].vx)>0.01f || fabsf(parts[i].vy)>0.01f)) (fabsf(parts[i].vx)>0.01f || fabsf(parts[i].vy)>0.01f))
{ {
// allow diagonal movement if target position is blocked // allow diagonal movement if target position is blocked
// but no point trying this if particle is stuck in a block of identical particles // but no point trying this if particle is stuck in a block of identical particles
dx = parts[i].vx - parts[i].vy*r; auto dx = parts[i].vx - parts[i].vy*r;
dy = parts[i].vy + parts[i].vx*r; auto dy = parts[i].vy + parts[i].vx*r;
mv = std::max(fabsf(dx), fabsf(dy)); auto mv = std::max(fabsf(dx), fabsf(dy));
dx /= mv; dx /= mv;
dy /= mv; dy /= mv;
if (do_move(i, x, y, clear_xf+dx, clear_yf+dy)) if (do_move(i, x, y, clear_xf+dx, clear_yf+dy))
@@ -3220,9 +3228,11 @@ killed:
parts[i].vy *= elements[t].Collision; parts[i].vy *= elements[t].Collision;
goto movedone; goto movedone;
} }
swappage = dx; {
dx = dy*r; auto swappage = dx;
dy = -swappage*r; dx = dy*r;
dy = -swappage*r;
}
if (do_move(i, x, y, clear_xf+dx, clear_yf+dy)) if (do_move(i, x, y, clear_xf+dx, clear_yf+dy))
{ {
parts[i].vx *= elements[t].Collision; parts[i].vx *= elements[t].Collision;
@@ -3232,8 +3242,9 @@ killed:
} }
if (elements[t].Falldown>1 && !grav->IsEnabled() && gravityMode==GRAV_VERTICAL && parts[i].vy>fabsf(parts[i].vx)) if (elements[t].Falldown>1 && !grav->IsEnabled() && gravityMode==GRAV_VERTICAL && parts[i].vy>fabsf(parts[i].vx))
{ {
s = 0; auto s = 0;
// stagnant is true if FLAG_STAGNANT was set for this particle in previous frame // stagnant is true if FLAG_STAGNANT was set for this particle in previous frame
int rt;
if (!stagnant || nt) //nt is if there is an something else besides the current particle type, around the particle if (!stagnant || nt) //nt is if there is an something else besides the current particle type, around the particle
rt = 30;//slight less water lag, although it changes how it moves a lot rt = 30;//slight less water lag, although it changes how it moves a lot
else else
@@ -3243,7 +3254,7 @@ killed:
rt = int(parts[i].tmp*0.20f+5.0f); rt = int(parts[i].tmp*0.20f+5.0f);
auto nx = -1, ny = -1; auto nx = -1, ny = -1;
for (j=clear_x+r; j>=0 && j>=clear_x-rt && j<clear_x+rt && j<XRES; j+=r) for (auto j=clear_x+r; j>=0 && j>=clear_x-rt && j<clear_x+rt && j<XRES; j+=r)
{ {
if ((TYP(pmap[fin_y][j])!=t || bmap[fin_y/CELL][j/CELL]) if ((TYP(pmap[fin_y][j])!=t || bmap[fin_y/CELL][j/CELL])
&& (s=do_move(i, x, y, (float)j, fin_yf))) && (s=do_move(i, x, y, (float)j, fin_yf)))
@@ -3266,7 +3277,7 @@ killed:
r = (parts[i].vy>0) ? 1 : -1; r = (parts[i].vy>0) ? 1 : -1;
if (s==1) if (s==1)
for (j=ny+r; j>=0 && j<YRES && j>=ny-rt && j<ny+rt; j+=r) for (auto j=ny+r; j>=0 && j<YRES && j>=ny-rt && j<ny+rt; j+=r)
{ {
if ((TYP(pmap[j][nx])!=t || bmap[j/CELL][nx/CELL]) && do_move(i, nx, ny, (float)nx, (float)j)) if ((TYP(pmap[j][nx])!=t || bmap[j/CELL][nx/CELL]) && do_move(i, nx, ny, (float)nx, (float)j))
break; break;
@@ -3282,11 +3293,11 @@ killed:
else if (elements[t].Falldown>1 && fabsf(pGravX*parts[i].vx+pGravY*parts[i].vy)>fabsf(pGravY*parts[i].vx-pGravX*parts[i].vy)) else if (elements[t].Falldown>1 && fabsf(pGravX*parts[i].vx+pGravY*parts[i].vy)>fabsf(pGravY*parts[i].vx-pGravX*parts[i].vy))
{ {
float nxf, nyf, prev_pGravX, prev_pGravY, ptGrav = elements[t].Gravity; float nxf, nyf, prev_pGravX, prev_pGravY, ptGrav = elements[t].Gravity;
s = 0; auto s = 0;
// stagnant is true if FLAG_STAGNANT was set for this particle in previous frame // stagnant is true if FLAG_STAGNANT was set for this particle in previous frame
// nt is if there is something else besides the current particle type around the particle // nt is if there is something else besides the current particle type around the particle
// 30 gives slightly less water lag, although it changes how it moves a lot // 30 gives slightly less water lag, although it changes how it moves a lot
rt = (!stagnant || nt) ? 30 : 10; auto rt = (!stagnant || nt) ? 30 : 10;
// clear_xf, clear_yf is the last known position that the particle should almost certainly be able to move to // clear_xf, clear_yf is the last known position that the particle should almost certainly be able to move to
nxf = clear_xf; nxf = clear_xf;
@@ -3294,12 +3305,12 @@ killed:
auto nx = clear_x; auto nx = clear_x;
auto ny = clear_y; auto ny = clear_y;
// Look for spaces to move horizontally (perpendicular to gravity direction), keep going until a space is found or the number of positions examined = rt // Look for spaces to move horizontally (perpendicular to gravity direction), keep going until a space is found or the number of positions examined = rt
for (j=0;j<rt;j++) for (auto j=0;j<rt;j++)
{ {
// Calculate overall gravity direction // Calculate overall gravity direction
GetGravityField(nx, ny, ptGrav, 1.0f, pGravX, pGravY); GetGravityField(nx, ny, ptGrav, 1.0f, pGravX, pGravY);
// Scale gravity vector so that the largest component is 1 pixel // Scale gravity vector so that the largest component is 1 pixel
mv = std::max(fabsf(pGravX), fabsf(pGravY)); auto mv = std::max(fabsf(pGravX), fabsf(pGravY));
if (mv<0.0001f) break; if (mv<0.0001f) break;
pGravX /= mv; pGravX /= mv;
pGravY /= mv; pGravY /= mv;
@@ -3346,12 +3357,12 @@ killed:
// Keep going until the particle is blocked (by something that isn't the same element) or the number of positions examined = rt // Keep going until the particle is blocked (by something that isn't the same element) or the number of positions examined = rt
clear_x = nx; clear_x = nx;
clear_y = ny; clear_y = ny;
for (j=0;j<rt;j++) for (auto j=0;j<rt;j++)
{ {
// Calculate overall gravity direction // Calculate overall gravity direction
GetGravityField(nx, ny, ptGrav, 1.0f, pGravX, pGravY); GetGravityField(nx, ny, ptGrav, 1.0f, pGravX, pGravY);
// Scale gravity vector so that the largest component is 1 pixel // Scale gravity vector so that the largest component is 1 pixel
mv = std::max(fabsf(pGravX), fabsf(pGravY)); auto mv = std::max(fabsf(pGravX), fabsf(pGravY));
if (mv<0.0001f) break; if (mv<0.0001f) break;
pGravX /= mv; pGravX /= mv;
pGravY /= mv; pGravY /= mv;
@@ -3391,10 +3402,13 @@ killed:
movedone: movedone:
continue; continue;
} }
}
//'f' was pressed (single frame) //'f' was pressed (single frame)
if (framerender) if (framerender)
{
framerender--; framerender--;
}
} }
void Simulation::RecalcFreeParticles(bool do_life_dec) void Simulation::RecalcFreeParticles(bool do_life_dec)