Fix some deprecation warnings
Namely: - [[deprecated("Use Mat2")]] - [[deprecated("Use Vec2")]] - [[deprecated("Use Mat2::operator*(Vec2)")]] - [[deprecated("Use Vec2<float>::operator*(float)")]] - [[deprecated("Use Vec2::operator+")]] - [[deprecated("Use Vec2::operator-")]] - [[deprecated("Use Vec2::Zero")]] - [[deprecated("Use Mat2::Identity")]]
This commit is contained in:
parent
c8bc8a7285
commit
9bd8bd2274
69
src/Misc.cpp
69
src/Misc.cpp
@ -5,72 +5,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <cmath>
|
||||
|
||||
matrix2d m2d_multiply_m2d(matrix2d m1, matrix2d m2)
|
||||
{
|
||||
matrix2d result = {
|
||||
m1.a*m2.a+m1.b*m2.c, m1.a*m2.b+m1.b*m2.d,
|
||||
m1.c*m2.a+m1.d*m2.c, m1.c*m2.b+m1.d*m2.d
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
vector2d m2d_multiply_v2d(matrix2d m, vector2d v)
|
||||
{
|
||||
vector2d result = {
|
||||
m.a*v.x+m.b*v.y,
|
||||
m.c*v.x+m.d*v.y
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
matrix2d m2d_multiply_float(matrix2d m, float s)
|
||||
{
|
||||
matrix2d result = {
|
||||
m.a*s, m.b*s,
|
||||
m.c*s, m.d*s,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
vector2d v2d_multiply_float(vector2d v, float s)
|
||||
{
|
||||
vector2d result = {
|
||||
v.x*s,
|
||||
v.y*s
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
vector2d v2d_add(vector2d v1, vector2d v2)
|
||||
{
|
||||
vector2d result = {
|
||||
v1.x+v2.x,
|
||||
v1.y+v2.y
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
vector2d v2d_sub(vector2d v1, vector2d v2)
|
||||
{
|
||||
vector2d result = {
|
||||
v1.x-v2.x,
|
||||
v1.y-v2.y
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
matrix2d m2d_new(float me0, float me1, float me2, float me3)
|
||||
{
|
||||
matrix2d result = {me0,me1,me2,me3};
|
||||
return result;
|
||||
}
|
||||
|
||||
vector2d v2d_new(float x, float y)
|
||||
{
|
||||
vector2d result = {x, y};
|
||||
return result;
|
||||
}
|
||||
|
||||
void HSV_to_RGB(int h,int s,int v,int *r,int *g,int *b)//convert 0-255(0-360 for H) HSV values to 0-255 RGB
|
||||
{
|
||||
float hh, ss, vv, c, x;
|
||||
@ -152,9 +86,6 @@ void membwand(void * destv, void * srcv, size_t destsize, size_t srcsize)
|
||||
}
|
||||
}
|
||||
|
||||
vector2d v2d_zero = {0,0};
|
||||
matrix2d m2d_identity = {1,0,0,1};
|
||||
|
||||
bool byteStringEqualsString(const ByteString &str, const char *data, size_t size)
|
||||
{
|
||||
return str.size() == size && !memcmp(str.data(), data, size);
|
||||
|
39
src/Misc.h
39
src/Misc.h
@ -57,45 +57,6 @@ void HSV_to_RGB(int h,int s,int v,int *r,int *g,int *b);
|
||||
void RGB_to_HSV(int r,int g,int b,int *h,int *s,int *v);
|
||||
void membwand(void * dest, void * src, size_t destsize, size_t srcsize);
|
||||
|
||||
// a b
|
||||
// c d
|
||||
struct matrix2d {
|
||||
[[deprecated("Use Mat2")]]
|
||||
float a,b,c,d;
|
||||
};
|
||||
[[deprecated("Use Mat2")]]
|
||||
typedef struct matrix2d matrix2d;
|
||||
|
||||
// column vector
|
||||
struct vector2d {
|
||||
[[deprecated("Use Vec2")]]
|
||||
float x,y;
|
||||
};
|
||||
[[deprecated("Use Vec2")]]
|
||||
typedef struct vector2d vector2d;
|
||||
|
||||
//matrix2d m2d_multiply_m2d(matrix2d m1, matrix2d m2);
|
||||
[[deprecated("Use Mat2::operator*(Vec2)")]]
|
||||
vector2d m2d_multiply_v2d(matrix2d m, vector2d v);
|
||||
//matrix2d m2d_multiply_float(matrix2d m, float s);
|
||||
[[deprecated("Use Vec2<float>::operator*(float)")]]
|
||||
vector2d v2d_multiply_float(vector2d v, float s);
|
||||
|
||||
[[deprecated("Use Vec2::operator+")]]
|
||||
vector2d v2d_add(vector2d v1, vector2d v2);
|
||||
[[deprecated("Use Vec2::operator-")]]
|
||||
vector2d v2d_sub(vector2d v1, vector2d v2);
|
||||
|
||||
[[deprecated("Use Mat2")]]
|
||||
matrix2d m2d_new(float me0, float me1, float me2, float me3);
|
||||
[[deprecated("Use Vec2")]]
|
||||
vector2d v2d_new(float x, float y);
|
||||
|
||||
[[deprecated("Use Vec2::Zero")]]
|
||||
extern vector2d v2d_zero;
|
||||
[[deprecated("Use Mat2::Identity")]]
|
||||
extern matrix2d m2d_identity;
|
||||
|
||||
class ByteString;
|
||||
|
||||
bool byteStringEqualsString(const ByteString &str, const char *data, size_t size);
|
||||
|
@ -111,232 +111,141 @@ std::pair<bool, std::vector<char>> GameSave::Serialise() const
|
||||
return { false, {} };
|
||||
}
|
||||
|
||||
vector2d GameSave::Translate(vector2d translate)
|
||||
{
|
||||
float nx, ny;
|
||||
vector2d pos;
|
||||
vector2d translateReal = translate;
|
||||
float minx = 0, miny = 0, maxx = 0, maxy = 0;
|
||||
// determine minimum and maximum position of all particles / signs
|
||||
for (size_t i = 0; i < signs.size(); i++)
|
||||
{
|
||||
pos = v2d_new(float(signs[i].x), float(signs[i].y));
|
||||
pos = v2d_add(pos,translate);
|
||||
nx = floor(pos.x+0.5f);
|
||||
ny = floor(pos.y+0.5f);
|
||||
if (nx < minx)
|
||||
minx = nx;
|
||||
if (ny < miny)
|
||||
miny = ny;
|
||||
if (nx > maxx)
|
||||
maxx = nx;
|
||||
if (ny > maxy)
|
||||
maxy = ny;
|
||||
}
|
||||
for (int i = 0; i < particlesCount; i++)
|
||||
{
|
||||
if (!particles[i].type) continue;
|
||||
pos = v2d_new(particles[i].x, particles[i].y);
|
||||
pos = v2d_add(pos,translate);
|
||||
nx = floor(pos.x+0.5f);
|
||||
ny = floor(pos.y+0.5f);
|
||||
if (nx < minx)
|
||||
minx = nx;
|
||||
if (ny < miny)
|
||||
miny = ny;
|
||||
if (nx > maxx)
|
||||
maxx = nx;
|
||||
if (ny > maxy)
|
||||
maxy = ny;
|
||||
}
|
||||
// determine whether corrections are needed. If moving in this direction would delete stuff, expand the save
|
||||
vector2d backCorrection = v2d_new(
|
||||
(minx < 0) ? (-floor(minx / CELL)) : 0,
|
||||
(miny < 0) ? (-floor(miny / CELL)) : 0
|
||||
);
|
||||
int blockBoundsX = int(maxx / CELL) + 1, blockBoundsY = int(maxy / CELL) + 1;
|
||||
vector2d frontCorrection = v2d_new(
|
||||
float((blockBoundsX > blockSize.X) ? (blockBoundsX - blockSize.X) : 0),
|
||||
float((blockBoundsY > blockSize.Y) ? (blockBoundsY - blockSize.Y) : 0)
|
||||
);
|
||||
extern const std::array<Vec2<int>, 8> Element_PIPE_offsets;
|
||||
void Element_PIPE_transformPatchOffsets(Particle &part, const std::array<int, 8> &offsetMap);
|
||||
|
||||
// get new width based on corrections
|
||||
auto newWidth = int((blockSize.X + backCorrection.x + frontCorrection.x) * CELL);
|
||||
auto newHeight = int((blockSize.Y + backCorrection.y + frontCorrection.y) * CELL);
|
||||
if (newWidth > XRES)
|
||||
frontCorrection.x = backCorrection.x = 0;
|
||||
if (newHeight > YRES)
|
||||
frontCorrection.y = backCorrection.y = 0;
|
||||
void GameSave::Transform(Mat2<int> transform, Vec2<int> nudge)
|
||||
{
|
||||
// undo translation by rotation
|
||||
auto br = transform * (blockSize * CELL - Vec2{ 1, 1 });
|
||||
auto bbr = transform * (blockSize - Vec2{ 1, 1 });
|
||||
auto translate = Vec2{ std::max(0, -br.X), std::max(0, -br.Y) };
|
||||
auto btranslate = Vec2{ std::max(0, -bbr.X), std::max(0, -bbr.Y) };
|
||||
auto newBlockS = transform * blockSize;
|
||||
newBlockS.X = std::abs(newBlockS.X);
|
||||
newBlockS.Y = std::abs(newBlockS.Y);
|
||||
translate += nudge;
|
||||
|
||||
// call Transform to do the transformation we wanted when calling this function
|
||||
translate = v2d_add(translate, v2d_multiply_float(backCorrection, CELL));
|
||||
Transform(m2d_identity, translate, translateReal, {
|
||||
int((blockSize.X + backCorrection.x + frontCorrection.x) * CELL),
|
||||
int((blockSize.Y + backCorrection.y + frontCorrection.y) * CELL)
|
||||
// Grow as needed.
|
||||
assert((Vec2{ CELL, CELL }.OriginRect().Contains(nudge)));
|
||||
if (nudge.X) newBlockS.X += 1;
|
||||
if (nudge.Y) newBlockS.Y += 1;
|
||||
|
||||
// TODO: allow transforms to yield bigger saves. For this we'd need SaveRenderer (the singleton, not Renderer)
|
||||
// to fully render them (possible with stitching) and Simulation::Load to be able to take only the part that fits.
|
||||
newBlockS = newBlockS.Clamp(RectBetween({ 0, 0 }, CELLS));
|
||||
auto newPartS = newBlockS * CELL;
|
||||
|
||||
// Prepare to patch pipes.
|
||||
std::array<int, 8> pipeOffsetMap;
|
||||
{
|
||||
std::transform(Element_PIPE_offsets.begin(), Element_PIPE_offsets.end(), pipeOffsetMap.begin(), [transform](auto offset) {
|
||||
auto it = std::find(Element_PIPE_offsets.begin(), Element_PIPE_offsets.end(), transform * offset);
|
||||
assert(it != Element_PIPE_offsets.end());
|
||||
return int(it - Element_PIPE_offsets.begin());
|
||||
});
|
||||
|
||||
// return how much we corrected. This is used to offset the position of the current stamp
|
||||
// otherwise it would attempt to recenter it with the current size
|
||||
return v2d_add(v2d_multiply_float(backCorrection, -CELL), v2d_multiply_float(frontCorrection, CELL));
|
||||
}
|
||||
|
||||
void GameSave::Transform(matrix2d transform, vector2d translate)
|
||||
// Translate signs.
|
||||
for (auto i = 0U; i < signs.size(); i++)
|
||||
{
|
||||
int width = blockSize.X*CELL, height = blockSize.Y*CELL;
|
||||
vector2d tmp, ctl, cbr;
|
||||
vector2d cornerso[4];
|
||||
vector2d translateReal = translate;
|
||||
// undo any translation caused by rotation
|
||||
cornerso[0] = v2d_new(0,0);
|
||||
cornerso[1] = v2d_new(float(width-1),0);
|
||||
cornerso[2] = v2d_new(0,float(height-1));
|
||||
cornerso[3] = v2d_new(float(width-1),float(height-1));
|
||||
for (int i = 0; i < 4; i++)
|
||||
auto newPos = transform * Vec2{ signs[i].x, signs[i].y } + translate;
|
||||
if (!newPartS.OriginRect().Contains(newPos))
|
||||
{
|
||||
tmp = m2d_multiply_v2d(transform,cornerso[i]);
|
||||
if (i==0) ctl = cbr = tmp; // top left, bottom right corner
|
||||
if (tmp.x<ctl.x) ctl.x = tmp.x;
|
||||
if (tmp.y<ctl.y) ctl.y = tmp.y;
|
||||
if (tmp.x>cbr.x) cbr.x = tmp.x;
|
||||
if (tmp.y>cbr.y) cbr.y = tmp.y;
|
||||
}
|
||||
// casting as int doesn't quite do what we want with negative numbers, so use floor()
|
||||
tmp = v2d_new(floor(ctl.x+0.5f),floor(ctl.y+0.5f));
|
||||
translate = v2d_sub(translate,tmp);
|
||||
auto newWidth = int(floor(cbr.x+0.5f))-int(floor(ctl.x+0.5f))+1;
|
||||
auto newHeight = int(floor(cbr.y+0.5f))-int(floor(ctl.y+0.5f))+1;
|
||||
Transform(transform, translate, translateReal, { newWidth, newHeight });
|
||||
}
|
||||
|
||||
// transform is a matrix describing how we want to rotate this save
|
||||
// translate can vary depending on whether the save is bring rotated, or if a normal translate caused it to expand
|
||||
// translateReal is the original amount we tried to translate, used to calculate wall shifting
|
||||
void GameSave::Transform(matrix2d transform, vector2d translate, vector2d translateReal, Vec2<int> newPartSize)
|
||||
{
|
||||
if (newPartSize.X>XRES) newPartSize.X = XRES;
|
||||
if (newPartSize.Y>YRES) newPartSize.Y = YRES;
|
||||
|
||||
auto newBlockSize = newPartSize / CELL;
|
||||
|
||||
PlaneAdapter<std::vector<unsigned char>> blockMapNew(newBlockSize, 0);
|
||||
PlaneAdapter<std::vector<float>> fanVelXNew(newBlockSize, 0.0f);
|
||||
PlaneAdapter<std::vector<float>> fanVelYNew(newBlockSize, 0.0f);
|
||||
PlaneAdapter<std::vector<float>> pressureNew(newBlockSize, 0.0f);
|
||||
PlaneAdapter<std::vector<float>> velocityXNew(newBlockSize, 0.0f);
|
||||
PlaneAdapter<std::vector<float>> velocityYNew(newBlockSize, 0.0f);
|
||||
PlaneAdapter<std::vector<float>> ambientHeatNew(newBlockSize, 0.0f);
|
||||
PlaneAdapter<std::vector<unsigned char>> blockAirNew(newBlockSize, 0);
|
||||
PlaneAdapter<std::vector<unsigned char>> blockAirhNew(newBlockSize, 0);
|
||||
|
||||
// Match these up with the matrices provided in GameView::OnKeyPress.
|
||||
bool patchPipeR = transform.a == 0 && transform.b == 1 && transform.c == -1 && transform.d == 0;
|
||||
bool patchPipeH = transform.a == -1 && transform.b == 0 && transform.c == 0 && transform.d == 1;
|
||||
bool patchPipeV = transform.a == 1 && transform.b == 0 && transform.c == 0 && transform.d == -1;
|
||||
|
||||
// rotate and translate signs, parts, walls
|
||||
for (size_t i = 0; i < signs.size(); i++)
|
||||
{
|
||||
auto pos = v2d_new(float(signs[i].x), float(signs[i].y));
|
||||
pos = v2d_add(m2d_multiply_v2d(transform,pos),translate);
|
||||
auto newPos = Vec2{ int(floor(pos.x+0.5f)), int(floor(pos.y+0.5f)) };
|
||||
if (!newPartSize.OriginRect().Contains(newPos))
|
||||
{
|
||||
signs[i].text[0] = 0;
|
||||
signs[i].text.clear();
|
||||
continue;
|
||||
}
|
||||
signs[i].x = newPos.X;
|
||||
signs[i].y = newPos.Y;
|
||||
}
|
||||
|
||||
// Translate particles.
|
||||
for (int i = 0; i < particlesCount; i++)
|
||||
{
|
||||
if (!particles[i].type) continue;
|
||||
auto pos = v2d_new(particles[i].x, particles[i].y);
|
||||
pos = v2d_add(m2d_multiply_v2d(transform,pos),translate);
|
||||
auto newPos = Vec2{ int(floor(pos.x+0.5f)), int(floor(pos.y+0.5f)) };
|
||||
if (!newPartSize.OriginRect().Contains(newPos))
|
||||
if (!particles[i].type)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
{
|
||||
// * We want particles to retain their distance from the centre of the particle grid cell
|
||||
// they are in, but more importantly we also don't want them to change grid cells,
|
||||
// so we just get rid of the edge cases.
|
||||
constexpr auto threshold = 0.001f;
|
||||
auto boundaryDiffX = particles[i].x - (floor(particles[i].x) + 0.5f);
|
||||
if (fabs(boundaryDiffX) < threshold)
|
||||
{
|
||||
particles[i].x += copysign(threshold, boundaryDiffX);
|
||||
}
|
||||
auto boundaryDiffY = particles[i].y - (floor(particles[i].y) + 0.5f);
|
||||
if (fabs(boundaryDiffY) < threshold)
|
||||
{
|
||||
particles[i].y += copysign(threshold, boundaryDiffY);
|
||||
}
|
||||
}
|
||||
if (particles[i].x - floor(particles[i].x) == 0.5f) particles[i].x += 0.001f;
|
||||
if (particles[i].y - floor(particles[i].y) == 0.5f) particles[i].y += 0.001f;
|
||||
auto newPos = transform * Vec2{ particles[i].x, particles[i].y } + translate;
|
||||
if (!newPartS.OriginRect().Contains(Vec2{ int(floor(newPos.X + 0.5f)), int(floor(newPos.Y + 0.5f)) }))
|
||||
{
|
||||
particles[i].type = PT_NONE;
|
||||
continue;
|
||||
}
|
||||
particles[i].x = float(newPos.X);
|
||||
particles[i].y = float(newPos.Y);
|
||||
auto vel = v2d_new(particles[i].vx, particles[i].vy);
|
||||
vel = m2d_multiply_v2d(transform, vel);
|
||||
particles[i].vx = vel.x;
|
||||
particles[i].vy = vel.y;
|
||||
particles[i].x = newPos.X;
|
||||
particles[i].y = newPos.Y;
|
||||
auto newVel = transform * Vec2{ particles[i].vx, particles[i].vy };
|
||||
particles[i].vx = newVel.X;
|
||||
particles[i].vy = newVel.Y;
|
||||
if (particles[i].type == PT_PIPE || particles[i].type == PT_PPIP)
|
||||
{
|
||||
if (patchPipeR)
|
||||
{
|
||||
void Element_PIPE_patchR(Particle &part);
|
||||
Element_PIPE_patchR(particles[i]);
|
||||
}
|
||||
if (patchPipeH)
|
||||
{
|
||||
void Element_PIPE_patchH(Particle &part);
|
||||
Element_PIPE_patchH(particles[i]);
|
||||
}
|
||||
if (patchPipeV)
|
||||
{
|
||||
void Element_PIPE_patchV(Particle &part);
|
||||
Element_PIPE_patchV(particles[i]);
|
||||
}
|
||||
Element_PIPE_transformPatchOffsets(particles[i], pipeOffsetMap);
|
||||
}
|
||||
}
|
||||
|
||||
// translate walls and other grid items when the stamp is shifted more than 4 pixels in any direction
|
||||
int translateX = 0, translateY = 0;
|
||||
if (translateReal.x > 0 && ((int)translated.x%CELL == 3
|
||||
|| (translated.x < 0 && (int)translated.x%CELL == 0)))
|
||||
translateX = CELL;
|
||||
else if (translateReal.x < 0 && ((int)translated.x%CELL == -3
|
||||
|| (translated.x > 0 && (int)translated.x%CELL == 0)))
|
||||
translateX = -CELL;
|
||||
if (translateReal.y > 0 && ((int)translated.y%CELL == 3
|
||||
|| (translated.y < 0 && (int)translated.y%CELL == 0)))
|
||||
translateY = CELL;
|
||||
else if (translateReal.y < 0 && ((int)translated.y%CELL == -3
|
||||
|| (translated.y > 0 && (int)translated.y%CELL == 0)))
|
||||
translateY = -CELL;
|
||||
|
||||
// Translate blocky stuff.
|
||||
PlaneAdapter<std::vector<unsigned char>> newBlockMap(newBlockS, 0);
|
||||
PlaneAdapter<std::vector<float>> newFanVelX(newBlockS, 0.0f);
|
||||
PlaneAdapter<std::vector<float>> newFanVelY(newBlockS, 0.0f);
|
||||
PlaneAdapter<std::vector<float>> newPressure(newBlockS, 0.0f);
|
||||
PlaneAdapter<std::vector<float>> newVelocityX(newBlockS, 0.0f);
|
||||
PlaneAdapter<std::vector<float>> newVelocityY(newBlockS, 0.0f);
|
||||
PlaneAdapter<std::vector<float>> newAmbientHeat(newBlockS, 0.0f);
|
||||
PlaneAdapter<std::vector<unsigned char>> newBlockAir(newBlockS, 0);
|
||||
PlaneAdapter<std::vector<unsigned char>> newBlockAirh(newBlockS, 0);
|
||||
for (auto bpos : blockSize.OriginRect())
|
||||
{
|
||||
auto pos = v2d_new(bpos.X*CELL+CELL*0.4f+translateX, bpos.Y*CELL+CELL*0.4f+translateY);
|
||||
pos = v2d_add(m2d_multiply_v2d(transform,pos),translate);
|
||||
auto newBpos = Vec2{ int(pos.x/CELL), int(pos.y/CELL) };
|
||||
if (!newBlockSize.OriginRect().Contains(newBpos))
|
||||
auto newBpos = transform * bpos + btranslate;
|
||||
if (!newBlockS.OriginRect().Contains(newBpos))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (blockMap[bpos])
|
||||
{
|
||||
blockMapNew[newBpos] = blockMap[bpos];
|
||||
newBlockMap[newBpos] = blockMap[bpos];
|
||||
if (blockMap[bpos] == WL_FAN)
|
||||
{
|
||||
auto vel = v2d_new(fanVelX[bpos], fanVelY[bpos]);
|
||||
vel = m2d_multiply_v2d(transform, vel);
|
||||
fanVelXNew[newBpos] = vel.x;
|
||||
fanVelYNew[newBpos] = vel.y;
|
||||
auto newVel = transform * Vec2{ fanVelX[bpos], fanVelY[bpos] };
|
||||
newFanVelX[newBpos] = newVel.X;
|
||||
newFanVelY[newBpos] = newVel.Y;
|
||||
}
|
||||
}
|
||||
pressureNew[newBpos] = pressure[bpos];
|
||||
velocityXNew[newBpos] = velocityX[bpos];
|
||||
velocityYNew[newBpos] = velocityY[bpos];
|
||||
ambientHeatNew[newBpos] = ambientHeat[bpos];
|
||||
blockAirNew[newBpos] = blockAir[bpos];
|
||||
blockAirhNew[newBpos] = blockAirh[bpos];
|
||||
newPressure[newBpos] = pressure[bpos];
|
||||
newVelocityX[newBpos] = velocityX[bpos];
|
||||
newVelocityY[newBpos] = velocityY[bpos];
|
||||
newAmbientHeat[newBpos] = ambientHeat[bpos];
|
||||
newBlockAir[newBpos] = blockAir[bpos];
|
||||
newBlockAirh[newBpos] = blockAirh[bpos];
|
||||
}
|
||||
translated = v2d_add(m2d_multiply_v2d(transform, translated), translateReal);
|
||||
blockMap = std::move(newBlockMap);
|
||||
fanVelX = std::move(newFanVelX);
|
||||
fanVelY = std::move(newFanVelY);
|
||||
pressure = std::move(newPressure);
|
||||
velocityX = std::move(newVelocityX);
|
||||
velocityY = std::move(newVelocityY);
|
||||
ambientHeat = std::move(newAmbientHeat);
|
||||
blockAir = std::move(newBlockAir);
|
||||
blockAirh = std::move(newBlockAirh);
|
||||
|
||||
blockSize = newBlockSize;
|
||||
|
||||
blockMap = blockMapNew;
|
||||
fanVelX = fanVelXNew;
|
||||
fanVelY = fanVelYNew;
|
||||
pressure = pressureNew;
|
||||
velocityX = velocityXNew;
|
||||
velocityY = velocityYNew;
|
||||
ambientHeat = ambientHeatNew;
|
||||
blockAir = blockAirNew;
|
||||
blockAirh = blockAirhNew;
|
||||
blockSize = newBlockS;
|
||||
}
|
||||
|
||||
static void CheckBsonFieldUser(bson_iterator iter, const char *field, unsigned char **data, unsigned int *fieldLen)
|
||||
|
@ -57,7 +57,6 @@ public:
|
||||
class GameSave
|
||||
{
|
||||
// number of pixels translated. When translating CELL pixels, shift all CELL grids
|
||||
vector2d translated = { 0, 0 };
|
||||
void readOPS(const std::vector<char> &data);
|
||||
void readPSv(const std::vector<char> &data);
|
||||
std::pair<bool, std::vector<char>> serialiseOPS() const;
|
||||
@ -120,9 +119,7 @@ public:
|
||||
void setSize(Vec2<int> newBlockSize);
|
||||
// return value is [ fakeFromNewerVersion, gameData ]
|
||||
std::pair<bool, std::vector<char>> Serialise() const;
|
||||
vector2d Translate(vector2d translate);
|
||||
void Transform(matrix2d transform, vector2d translate);
|
||||
void Transform(matrix2d transform, vector2d translate, vector2d translateReal, Vec2<int> newPartSize);
|
||||
void Transform(Mat2<int> transform, Vec2<int> nudge);
|
||||
|
||||
void Expand(const std::vector<char> &data);
|
||||
|
||||
|
@ -156,6 +156,15 @@ struct Mat2
|
||||
return Vec2<decltype(std::declval<T>() * std::declval<S>())>(A * vec.X + B * vec.Y, C * vec.X + D * vec.Y);
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
constexpr Mat2<decltype(std::declval<T>() * std::declval<S>())> operator*(Mat2<S> mat) const
|
||||
{
|
||||
return Mat2<decltype(std::declval<T>() * std::declval<S>())>(
|
||||
A * mat.A + B * mat.C, A * mat.B + B * mat.D,
|
||||
C * mat.A + D * mat.C, C * mat.B + D * mat.D
|
||||
);
|
||||
}
|
||||
|
||||
static Mat2<T> const Identity, MirrorX, MirrorY, CCW;
|
||||
};
|
||||
|
||||
|
@ -238,7 +238,7 @@ std::pair<int, sign::Type> GameController::GetSignSplit(int signID)
|
||||
|
||||
void GameController::PlaceSave(ui::Point position)
|
||||
{
|
||||
auto *placeSave = gameModel->GetPlaceSave();
|
||||
auto *placeSave = gameModel->GetTransformedPlaceSave();
|
||||
if (placeSave)
|
||||
{
|
||||
HistorySnapshot();
|
||||
@ -248,6 +248,7 @@ void GameController::PlaceSave(ui::Point position)
|
||||
Client::Ref().MergeStampAuthorInfo(placeSave->authors);
|
||||
}
|
||||
}
|
||||
gameModel->SetPlaceSave(nullptr);
|
||||
}
|
||||
|
||||
void GameController::Install()
|
||||
@ -420,23 +421,9 @@ void GameController::LoadStamp(std::unique_ptr<GameSave> stamp)
|
||||
gameModel->SetPlaceSave(std::move(stamp));
|
||||
}
|
||||
|
||||
void GameController::TranslateSave(ui::Point point)
|
||||
void GameController::TransformPlaceSave(Mat2<int> transform, Vec2<int> nudge)
|
||||
{
|
||||
vector2d translate = v2d_new(float(point.X), float(point.Y));
|
||||
auto save = gameModel->TakePlaceSave();
|
||||
vector2d translated = save->Translate(translate);
|
||||
ui::Point currentPlaceSaveOffset = gameView->GetPlaceSaveOffset();
|
||||
// resets placeSaveOffset to 0, which is why we back it up first
|
||||
gameModel->SetPlaceSave(std::move(save));
|
||||
gameView->SetPlaceSaveOffset(ui::Point(int(translated.x), int(translated.y)) + currentPlaceSaveOffset);
|
||||
}
|
||||
|
||||
void GameController::TransformSave(matrix2d transform)
|
||||
{
|
||||
vector2d translate = v2d_zero;
|
||||
auto save = gameModel->TakePlaceSave();
|
||||
save->Transform(transform, translate);
|
||||
gameModel->SetPlaceSave(std::move(save));
|
||||
gameModel->TransformPlaceSave(transform, nudge);
|
||||
}
|
||||
|
||||
void GameController::ToolClick(int toolSelection, ui::Point point)
|
||||
|
@ -152,8 +152,7 @@ public:
|
||||
void ShowConsole();
|
||||
void HideConsole();
|
||||
void FrameStep();
|
||||
void TranslateSave(ui::Point point);
|
||||
void TransformSave(matrix2d transform);
|
||||
void TransformPlaceSave(Mat2<int> transform, Vec2<int> nudge);
|
||||
bool MouseInZoom(ui::Point position);
|
||||
ui::Point PointTranslate(ui::Point point);
|
||||
ui::Point PointTranslateNoClamp(ui::Point point);
|
||||
|
@ -1336,10 +1336,21 @@ void GameModel::ClearSimulation()
|
||||
|
||||
void GameModel::SetPlaceSave(std::unique_ptr<GameSave> save)
|
||||
{
|
||||
transformedPlaceSave.reset();
|
||||
placeSave = std::move(save);
|
||||
notifyPlaceSaveChanged();
|
||||
}
|
||||
|
||||
void GameModel::TransformPlaceSave(Mat2<int> transform, Vec2<int> nudge)
|
||||
{
|
||||
if (placeSave)
|
||||
{
|
||||
transformedPlaceSave = std::make_unique<GameSave>(*placeSave);
|
||||
transformedPlaceSave->Transform(transform, nudge);
|
||||
}
|
||||
notifyTransformedPlaceSaveChanged();
|
||||
}
|
||||
|
||||
void GameModel::SetClipboard(std::unique_ptr<GameSave> save)
|
||||
{
|
||||
clipboard = std::move(save);
|
||||
@ -1350,15 +1361,9 @@ const GameSave *GameModel::GetClipboard() const
|
||||
return clipboard.get();
|
||||
}
|
||||
|
||||
const GameSave *GameModel::GetPlaceSave() const
|
||||
const GameSave *GameModel::GetTransformedPlaceSave() const
|
||||
{
|
||||
return placeSave.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<GameSave> GameModel::TakePlaceSave()
|
||||
{
|
||||
// we don't notify listeners because we'll get a new save soon anyway
|
||||
return std::move(placeSave);
|
||||
return transformedPlaceSave.get();
|
||||
}
|
||||
|
||||
void GameModel::Log(String message, bool printToFile)
|
||||
@ -1559,6 +1564,14 @@ void GameModel::notifyPlaceSaveChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void GameModel::notifyTransformedPlaceSaveChanged()
|
||||
{
|
||||
for (size_t i = 0; i < observers.size(); i++)
|
||||
{
|
||||
observers[i]->NotifyTransformedPlaceSaveChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
void GameModel::notifyLogChanged(String entry)
|
||||
{
|
||||
for (size_t i = 0; i < observers.size(); i++)
|
||||
|
@ -46,6 +46,7 @@ private:
|
||||
//unsigned char * clipboardData;
|
||||
std::unique_ptr<GameSave> clipboard;
|
||||
std::unique_ptr<GameSave> placeSave;
|
||||
std::unique_ptr<GameSave> transformedPlaceSave;
|
||||
std::deque<String> consoleLog;
|
||||
std::vector<GameView*> observers;
|
||||
std::vector<Tool*> toolList;
|
||||
@ -104,6 +105,7 @@ private:
|
||||
void notifyZoomChanged();
|
||||
void notifyClipboardChanged();
|
||||
void notifyPlaceSaveChanged();
|
||||
void notifyTransformedPlaceSaveChanged();
|
||||
void notifyColourSelectorColourChanged();
|
||||
void notifyColourSelectorVisibilityChanged();
|
||||
void notifyColourPresetsChanged();
|
||||
@ -227,11 +229,12 @@ public:
|
||||
ui::Point GetZoomWindowPosition();
|
||||
void SetClipboard(std::unique_ptr<GameSave> save);
|
||||
void SetPlaceSave(std::unique_ptr<GameSave> save);
|
||||
void TransformPlaceSave(Mat2<int> transform, Vec2<int> nudge);
|
||||
void Log(String message, bool printToFile);
|
||||
std::deque<String> GetLog();
|
||||
const GameSave *GetClipboard() const;
|
||||
const GameSave *GetPlaceSave() const;
|
||||
std::unique_ptr<GameSave> TakePlaceSave();
|
||||
const GameSave *GetTransformedPlaceSave() const;
|
||||
bool GetMouseClickRequired();
|
||||
void SetMouseClickRequired(bool mouseClickRequired);
|
||||
bool GetIncludePressure();
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#include "Config.h"
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <SDL.h>
|
||||
|
||||
@ -1198,7 +1199,7 @@ void GameView::OnMouseUp(int x, int y, unsigned button)
|
||||
{
|
||||
if (placeSaveThumb && y <= WINDOWH-BARSIZE)
|
||||
{
|
||||
auto thumb = selectPoint2 - (placeSaveThumb->Size() - placeSaveOffset) / 2;
|
||||
auto thumb = selectPoint2 + placeSaveOffset;
|
||||
thumb = thumb.Clamp(RectBetween(Vec2<int>::Zero, RES - placeSaveThumb->Size()));
|
||||
c->PlaceSave(thumb);
|
||||
}
|
||||
@ -1334,16 +1335,16 @@ void GameView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
|
||||
switch (key)
|
||||
{
|
||||
case SDLK_RIGHT:
|
||||
c->TranslateSave(ui::Point(1, 0));
|
||||
TranslateSave({ 1, 0 });
|
||||
return;
|
||||
case SDLK_LEFT:
|
||||
c->TranslateSave(ui::Point(-1, 0));
|
||||
TranslateSave({ -1, 0 });
|
||||
return;
|
||||
case SDLK_UP:
|
||||
c->TranslateSave(ui::Point(0, -1));
|
||||
TranslateSave({ 0, -1 });
|
||||
return;
|
||||
case SDLK_DOWN:
|
||||
c->TranslateSave(ui::Point(0, 1));
|
||||
TranslateSave({ 0, 1 });
|
||||
return;
|
||||
}
|
||||
if (scan == SDL_SCANCODE_R && !repeat)
|
||||
@ -1351,17 +1352,17 @@ void GameView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
|
||||
if (ctrl && shift)
|
||||
{
|
||||
//Vertical flip
|
||||
c->TransformSave(m2d_new(1,0,0,-1));
|
||||
TransformSave(Mat2<int>::MirrorY);
|
||||
}
|
||||
else if (!ctrl && shift)
|
||||
{
|
||||
//Horizontal flip
|
||||
c->TransformSave(m2d_new(-1,0,0,1));
|
||||
TransformSave(Mat2<int>::MirrorX);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Rotate 90deg
|
||||
c->TransformSave(m2d_new(0,1,-1,0));
|
||||
TransformSave(Mat2<int>::CCW);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1908,16 +1909,62 @@ void GameView::NotifyLogChanged(GameModel * sender, String entry)
|
||||
|
||||
void GameView::NotifyPlaceSaveChanged(GameModel * sender)
|
||||
{
|
||||
placeSaveOffset = ui::Point(0, 0);
|
||||
if(sender->GetPlaceSave())
|
||||
placeSaveTransform = Mat2<int>::Identity;
|
||||
placeSaveTranslate = Vec2<int>::Zero;
|
||||
ApplyTransformPlaceSave();
|
||||
}
|
||||
|
||||
void GameView::TranslateSave(Vec2<int> addToTranslate)
|
||||
{
|
||||
placeSaveThumb = SaveRenderer::Ref().Render(sender->GetPlaceSave(), true, true, sender->GetRenderer());
|
||||
placeSaveTranslate += addToTranslate;
|
||||
ApplyTransformPlaceSave();
|
||||
}
|
||||
|
||||
void GameView::TransformSave(Mat2<int> mulToTransform)
|
||||
{
|
||||
placeSaveTranslate = Vec2<int>::Zero; // reset offset
|
||||
placeSaveTransform = mulToTransform * placeSaveTransform;
|
||||
ApplyTransformPlaceSave();
|
||||
}
|
||||
|
||||
template<class Signed>
|
||||
static std::pair<Signed, Signed> floorDiv(Signed a, Signed b)
|
||||
{
|
||||
auto quo = a / b;
|
||||
auto rem = a % b;
|
||||
if (a < Signed(0) && rem)
|
||||
{
|
||||
quo -= Signed(1);
|
||||
rem += b;
|
||||
}
|
||||
return { quo, rem };
|
||||
}
|
||||
|
||||
void GameView::ApplyTransformPlaceSave()
|
||||
{
|
||||
auto remX = floorDiv(placeSaveTranslate.X, CELL).second;
|
||||
auto remY = floorDiv(placeSaveTranslate.Y, CELL).second;
|
||||
c->TransformPlaceSave(placeSaveTransform, { remX, remY });
|
||||
}
|
||||
|
||||
void GameView::NotifyTransformedPlaceSaveChanged(GameModel *sender)
|
||||
{
|
||||
if (sender->GetTransformedPlaceSave())
|
||||
{
|
||||
placeSaveThumb = SaveRenderer::Ref().Render(sender->GetTransformedPlaceSave(), true, true, sender->GetRenderer());
|
||||
auto [ quoX, remX ] = floorDiv(placeSaveTranslate.X, CELL);
|
||||
auto [ quoY, remY ] = floorDiv(placeSaveTranslate.Y, CELL);
|
||||
placeSaveOffset = Vec2{ quoX, quoY } * CELL;
|
||||
auto usefulSize = placeSaveThumb->Size();
|
||||
if (remX) usefulSize.X -= CELL;
|
||||
if (remY) usefulSize.Y -= CELL;
|
||||
placeSaveOffset -= usefulSize / 2;
|
||||
selectMode = PlaceSave;
|
||||
selectPoint2 = mousePosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
placeSaveThumb = nullptr;
|
||||
placeSaveThumb.reset();
|
||||
selectMode = SelectNone;
|
||||
}
|
||||
}
|
||||
@ -2127,7 +2174,7 @@ void GameView::OnDraw()
|
||||
{
|
||||
if(placeSaveThumb && selectPoint2.X!=-1)
|
||||
{
|
||||
auto thumb = selectPoint2 - (placeSaveThumb->Size() - placeSaveOffset) / 2 + Vec2(1, 1) * CELL / 2;
|
||||
auto thumb = selectPoint2 + placeSaveOffset + Vec2(1, 1) * CELL / 2;
|
||||
thumb = c->NormaliseBlockCoord(thumb).Clamp(RectBetween(Vec2<int>::Zero, RES - placeSaveThumb->Size()));
|
||||
auto rect = RectSized(thumb, placeSaveThumb->Size());
|
||||
ren->BlendImage(placeSaveThumb->Data(), 0x80, rect);
|
||||
|
@ -119,6 +119,11 @@ private:
|
||||
|
||||
std::unique_ptr<VideoBuffer> placeSaveThumb;
|
||||
ui::Point placeSaveOffset;
|
||||
Mat2<int> placeSaveTransform = Mat2<int>::Identity;
|
||||
Vec2<int> placeSaveTranslate = Vec2<int>::Zero;
|
||||
void TranslateSave(Vec2<int> addToTranslate);
|
||||
void TransformSave(Mat2<int> mulToTransform);
|
||||
void ApplyTransformPlaceSave();
|
||||
|
||||
SimulationSample sample;
|
||||
|
||||
@ -185,6 +190,7 @@ public:
|
||||
void NotifyColourPresetsChanged(GameModel * sender);
|
||||
void NotifyColourActivePresetChanged(GameModel * sender);
|
||||
void NotifyPlaceSaveChanged(GameModel * sender);
|
||||
void NotifyTransformedPlaceSaveChanged(GameModel *sender);
|
||||
void NotifyNotificationsChanged(GameModel * sender);
|
||||
void NotifyLogChanged(GameModel * sender, String entry);
|
||||
void NotifyToolTipChanged(GameModel * sender);
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "simulation/ElementCommon.h"
|
||||
|
||||
extern const std::array<Vec2<int>, 8> Element_PIPE_offsets;
|
||||
void Element_PIPE_transformPatchOffsets(Particle &part, const std::array<int, 8> &offsetMap);
|
||||
int Element_PIPE_update(UPDATE_FUNC_ARGS);
|
||||
int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS);
|
||||
void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR);
|
||||
@ -78,40 +80,21 @@ constexpr int PPIP_TMPFLAG_TRIGGER_OFF = 0x08000000;
|
||||
constexpr int PPIP_TMPFLAG_TRIGGER_ON = 0x10000000;
|
||||
constexpr int PPIP_TMPFLAG_TRIGGERS = 0x1C000000;
|
||||
|
||||
signed char pos_1_rx[] = { -1,-1,-1, 0, 0, 1, 1, 1 };
|
||||
signed char pos_1_ry[] = { -1, 0, 1,-1, 1,-1, 0, 1 };
|
||||
const std::array<Vec2<int>, 8> Element_PIPE_offsets = {{
|
||||
{ -1, -1 },
|
||||
{ -1, 0 },
|
||||
{ -1, 1 },
|
||||
{ 0, -1 },
|
||||
{ 0, 1 },
|
||||
{ 1, -1 },
|
||||
{ 1, 0 },
|
||||
{ 1, 1 },
|
||||
}};
|
||||
|
||||
static void transformPatch(Particle &part, const int (&patch)[8])
|
||||
void Element_PIPE_transformPatchOffsets(Particle &part, const std::array<int, 8> &offsetMap)
|
||||
{
|
||||
if (part.tmp & 0x00000200) part.tmp = (part.tmp & 0xFFFFE3FF) | (patch[(part.tmp & 0x00001C00) >> 10] << 10);
|
||||
if (part.tmp & 0x00002000) part.tmp = (part.tmp & 0xFFFE3FFF) | (patch[(part.tmp & 0x0001C000) >> 14] << 14);
|
||||
}
|
||||
|
||||
void Element_PIPE_patchR(Particle &part)
|
||||
{
|
||||
// 035 -> 210
|
||||
// 1 6 -> 4 3
|
||||
// 247 -> 765
|
||||
const int patchR[] = { 2, 4, 7, 1, 6, 0, 3, 5 };
|
||||
transformPatch(part, patchR);
|
||||
}
|
||||
|
||||
void Element_PIPE_patchH(Particle &part)
|
||||
{
|
||||
// 035 -> 530
|
||||
// 1 6 -> 6 1
|
||||
// 247 -> 742
|
||||
const int patchH[] = { 5, 6, 7, 3, 4, 0, 1, 2 };
|
||||
transformPatch(part, patchH);
|
||||
}
|
||||
|
||||
void Element_PIPE_patchV(Particle &part)
|
||||
{
|
||||
// 035 -> 247
|
||||
// 1 6 -> 1 6
|
||||
// 247 -> 035
|
||||
const int patchV[] = { 2, 1, 0, 4, 3, 7, 6, 5 };
|
||||
transformPatch(part, patchV);
|
||||
if (part.tmp & 0x00000200) part.tmp = (part.tmp & 0xFFFFE3FF) | (offsetMap[(part.tmp & 0x00001C00) >> 10] << 10);
|
||||
if (part.tmp & 0x00002000) part.tmp = (part.tmp & 0xFFFE3FFF) | (offsetMap[(part.tmp & 0x0001C000) >> 14] << 14);
|
||||
}
|
||||
|
||||
static unsigned int prevColor(unsigned int flags)
|
||||
@ -260,8 +243,8 @@ int Element_PIPE_update(UPDATE_FUNC_ARGS)
|
||||
rndstore = sim->rng.gen();
|
||||
rnd = rndstore&7;
|
||||
//rndstore = rndstore>>3;
|
||||
rx = pos_1_rx[rnd];
|
||||
ry = pos_1_ry[rnd];
|
||||
rx = Element_PIPE_offsets[rnd].X;
|
||||
ry = Element_PIPE_offsets[rnd].Y;
|
||||
if (BOUNDS_CHECK)
|
||||
{
|
||||
r = pmap[y+ry][x+rx];
|
||||
@ -501,8 +484,8 @@ static void pushParticle(Simulation * sim, int i, int count, int original)
|
||||
{
|
||||
rnd = rndstore&7;
|
||||
rndstore = rndstore>>3;
|
||||
rx = pos_1_rx[rnd];
|
||||
ry = pos_1_ry[rnd];
|
||||
rx = Element_PIPE_offsets[rnd].X;
|
||||
ry = Element_PIPE_offsets[rnd].Y;
|
||||
if (BOUNDS_CHECK)
|
||||
{
|
||||
r = sim->pmap[y+ry][x+rx];
|
||||
@ -537,7 +520,7 @@ static void pushParticle(Simulation * sim, int i, int count, int original)
|
||||
else //predefined 1 pixel thick pipe movement
|
||||
{
|
||||
int coords = 7 - ((sim->parts[i].tmp>>10)&7);
|
||||
r = sim->pmap[y+ pos_1_ry[coords]][x+ pos_1_rx[coords]];
|
||||
r = sim->pmap[y+ Element_PIPE_offsets[coords].Y][x+ Element_PIPE_offsets[coords].X];
|
||||
if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP) && (sim->parts[ID(r)].tmp&PFLAG_COLORS) != notctype && !TYP(sim->parts[ID(r)].ctype))
|
||||
{
|
||||
transfer_pipe_to_pipe(sim->parts+i, sim->parts+(ID(r)), false);
|
||||
@ -563,8 +546,8 @@ static void pushParticle(Simulation * sim, int i, int count, int original)
|
||||
}
|
||||
else if (!r) //Move particles out of pipe automatically, much faster at ends
|
||||
{
|
||||
rx = pos_1_rx[coords];
|
||||
ry = pos_1_ry[coords];
|
||||
rx = Element_PIPE_offsets[coords].X;
|
||||
ry = Element_PIPE_offsets[coords].Y;
|
||||
np = sim->create_part(-1,x+rx,y+ry,TYP(sim->parts[i].ctype));
|
||||
if (np!=-1)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user