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 <sys/types.h>
|
||||||
#include <cmath>
|
#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
|
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;
|
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)
|
bool byteStringEqualsString(const ByteString &str, const char *data, size_t size)
|
||||||
{
|
{
|
||||||
return str.size() == size && !memcmp(str.data(), data, 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 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);
|
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;
|
class ByteString;
|
||||||
|
|
||||||
bool byteStringEqualsString(const ByteString &str, const char *data, size_t size);
|
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, {} };
|
return { false, {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
vector2d GameSave::Translate(vector2d translate)
|
extern const std::array<Vec2<int>, 8> Element_PIPE_offsets;
|
||||||
|
void Element_PIPE_transformPatchOffsets(Particle &part, const std::array<int, 8> &offsetMap);
|
||||||
|
|
||||||
|
void GameSave::Transform(Mat2<int> transform, Vec2<int> nudge)
|
||||||
{
|
{
|
||||||
float nx, ny;
|
// undo translation by rotation
|
||||||
vector2d pos;
|
auto br = transform * (blockSize * CELL - Vec2{ 1, 1 });
|
||||||
vector2d translateReal = translate;
|
auto bbr = transform * (blockSize - Vec2{ 1, 1 });
|
||||||
float minx = 0, miny = 0, maxx = 0, maxy = 0;
|
auto translate = Vec2{ std::max(0, -br.X), std::max(0, -br.Y) };
|
||||||
// determine minimum and maximum position of all particles / signs
|
auto btranslate = Vec2{ std::max(0, -bbr.X), std::max(0, -bbr.Y) };
|
||||||
for (size_t i = 0; i < signs.size(); i++)
|
auto newBlockS = transform * blockSize;
|
||||||
|
newBlockS.X = std::abs(newBlockS.X);
|
||||||
|
newBlockS.Y = std::abs(newBlockS.Y);
|
||||||
|
translate += nudge;
|
||||||
|
|
||||||
|
// 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;
|
||||||
{
|
{
|
||||||
pos = v2d_new(float(signs[i].x), float(signs[i].y));
|
std::transform(Element_PIPE_offsets.begin(), Element_PIPE_offsets.end(), pipeOffsetMap.begin(), [transform](auto offset) {
|
||||||
pos = v2d_add(pos,translate);
|
auto it = std::find(Element_PIPE_offsets.begin(), Element_PIPE_offsets.end(), transform * offset);
|
||||||
nx = floor(pos.x+0.5f);
|
assert(it != Element_PIPE_offsets.end());
|
||||||
ny = floor(pos.y+0.5f);
|
return int(it - Element_PIPE_offsets.begin());
|
||||||
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++)
|
|
||||||
|
// Translate signs.
|
||||||
|
for (auto i = 0U; i < signs.size(); i++)
|
||||||
{
|
{
|
||||||
if (!particles[i].type) continue;
|
auto newPos = transform * Vec2{ signs[i].x, signs[i].y } + translate;
|
||||||
pos = v2d_new(particles[i].x, particles[i].y);
|
if (!newPartS.OriginRect().Contains(newPos))
|
||||||
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)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
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++)
|
|
||||||
{
|
|
||||||
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;
|
continue;
|
||||||
}
|
}
|
||||||
signs[i].x = newPos.X;
|
signs[i].x = newPos.X;
|
||||||
signs[i].y = newPos.Y;
|
signs[i].y = newPos.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Translate particles.
|
||||||
for (int i = 0; i < particlesCount; i++)
|
for (int i = 0; i < particlesCount; i++)
|
||||||
{
|
{
|
||||||
if (!particles[i].type) continue;
|
if (!particles[i].type)
|
||||||
auto pos = v2d_new(particles[i].x, particles[i].y);
|
{
|
||||||
pos = v2d_add(m2d_multiply_v2d(transform,pos),translate);
|
continue;
|
||||||
auto newPos = Vec2{ int(floor(pos.x+0.5f)), int(floor(pos.y+0.5f)) };
|
}
|
||||||
if (!newPartSize.OriginRect().Contains(newPos))
|
{
|
||||||
|
// * 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;
|
particles[i].type = PT_NONE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
particles[i].x = float(newPos.X);
|
particles[i].x = newPos.X;
|
||||||
particles[i].y = float(newPos.Y);
|
particles[i].y = newPos.Y;
|
||||||
auto vel = v2d_new(particles[i].vx, particles[i].vy);
|
auto newVel = transform * Vec2{ particles[i].vx, particles[i].vy };
|
||||||
vel = m2d_multiply_v2d(transform, vel);
|
particles[i].vx = newVel.X;
|
||||||
particles[i].vx = vel.x;
|
particles[i].vy = newVel.Y;
|
||||||
particles[i].vy = vel.y;
|
|
||||||
if (particles[i].type == PT_PIPE || particles[i].type == PT_PPIP)
|
if (particles[i].type == PT_PIPE || particles[i].type == PT_PPIP)
|
||||||
{
|
{
|
||||||
if (patchPipeR)
|
Element_PIPE_transformPatchOffsets(particles[i], pipeOffsetMap);
|
||||||
{
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// translate walls and other grid items when the stamp is shifted more than 4 pixels in any direction
|
// Translate blocky stuff.
|
||||||
int translateX = 0, translateY = 0;
|
PlaneAdapter<std::vector<unsigned char>> newBlockMap(newBlockS, 0);
|
||||||
if (translateReal.x > 0 && ((int)translated.x%CELL == 3
|
PlaneAdapter<std::vector<float>> newFanVelX(newBlockS, 0.0f);
|
||||||
|| (translated.x < 0 && (int)translated.x%CELL == 0)))
|
PlaneAdapter<std::vector<float>> newFanVelY(newBlockS, 0.0f);
|
||||||
translateX = CELL;
|
PlaneAdapter<std::vector<float>> newPressure(newBlockS, 0.0f);
|
||||||
else if (translateReal.x < 0 && ((int)translated.x%CELL == -3
|
PlaneAdapter<std::vector<float>> newVelocityX(newBlockS, 0.0f);
|
||||||
|| (translated.x > 0 && (int)translated.x%CELL == 0)))
|
PlaneAdapter<std::vector<float>> newVelocityY(newBlockS, 0.0f);
|
||||||
translateX = -CELL;
|
PlaneAdapter<std::vector<float>> newAmbientHeat(newBlockS, 0.0f);
|
||||||
if (translateReal.y > 0 && ((int)translated.y%CELL == 3
|
PlaneAdapter<std::vector<unsigned char>> newBlockAir(newBlockS, 0);
|
||||||
|| (translated.y < 0 && (int)translated.y%CELL == 0)))
|
PlaneAdapter<std::vector<unsigned char>> newBlockAirh(newBlockS, 0);
|
||||||
translateY = CELL;
|
|
||||||
else if (translateReal.y < 0 && ((int)translated.y%CELL == -3
|
|
||||||
|| (translated.y > 0 && (int)translated.y%CELL == 0)))
|
|
||||||
translateY = -CELL;
|
|
||||||
|
|
||||||
for (auto bpos : blockSize.OriginRect())
|
for (auto bpos : blockSize.OriginRect())
|
||||||
{
|
{
|
||||||
auto pos = v2d_new(bpos.X*CELL+CELL*0.4f+translateX, bpos.Y*CELL+CELL*0.4f+translateY);
|
auto newBpos = transform * bpos + btranslate;
|
||||||
pos = v2d_add(m2d_multiply_v2d(transform,pos),translate);
|
if (!newBlockS.OriginRect().Contains(newBpos))
|
||||||
auto newBpos = Vec2{ int(pos.x/CELL), int(pos.y/CELL) };
|
{
|
||||||
if (!newBlockSize.OriginRect().Contains(newBpos))
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if (blockMap[bpos])
|
if (blockMap[bpos])
|
||||||
{
|
{
|
||||||
blockMapNew[newBpos] = blockMap[bpos];
|
newBlockMap[newBpos] = blockMap[bpos];
|
||||||
if (blockMap[bpos]==WL_FAN)
|
if (blockMap[bpos] == WL_FAN)
|
||||||
{
|
{
|
||||||
auto vel = v2d_new(fanVelX[bpos], fanVelY[bpos]);
|
auto newVel = transform * Vec2{ fanVelX[bpos], fanVelY[bpos] };
|
||||||
vel = m2d_multiply_v2d(transform, vel);
|
newFanVelX[newBpos] = newVel.X;
|
||||||
fanVelXNew[newBpos] = vel.x;
|
newFanVelY[newBpos] = newVel.Y;
|
||||||
fanVelYNew[newBpos] = vel.y;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pressureNew[newBpos] = pressure[bpos];
|
newPressure[newBpos] = pressure[bpos];
|
||||||
velocityXNew[newBpos] = velocityX[bpos];
|
newVelocityX[newBpos] = velocityX[bpos];
|
||||||
velocityYNew[newBpos] = velocityY[bpos];
|
newVelocityY[newBpos] = velocityY[bpos];
|
||||||
ambientHeatNew[newBpos] = ambientHeat[bpos];
|
newAmbientHeat[newBpos] = ambientHeat[bpos];
|
||||||
blockAirNew[newBpos] = blockAir[bpos];
|
newBlockAir[newBpos] = blockAir[bpos];
|
||||||
blockAirhNew[newBpos] = blockAirh[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;
|
blockSize = newBlockS;
|
||||||
|
|
||||||
blockMap = blockMapNew;
|
|
||||||
fanVelX = fanVelXNew;
|
|
||||||
fanVelY = fanVelYNew;
|
|
||||||
pressure = pressureNew;
|
|
||||||
velocityX = velocityXNew;
|
|
||||||
velocityY = velocityYNew;
|
|
||||||
ambientHeat = ambientHeatNew;
|
|
||||||
blockAir = blockAirNew;
|
|
||||||
blockAirh = blockAirhNew;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CheckBsonFieldUser(bson_iterator iter, const char *field, unsigned char **data, unsigned int *fieldLen)
|
static void CheckBsonFieldUser(bson_iterator iter, const char *field, unsigned char **data, unsigned int *fieldLen)
|
||||||
|
@ -57,7 +57,6 @@ public:
|
|||||||
class GameSave
|
class GameSave
|
||||||
{
|
{
|
||||||
// number of pixels translated. When translating CELL pixels, shift all CELL grids
|
// number of pixels translated. When translating CELL pixels, shift all CELL grids
|
||||||
vector2d translated = { 0, 0 };
|
|
||||||
void readOPS(const std::vector<char> &data);
|
void readOPS(const std::vector<char> &data);
|
||||||
void readPSv(const std::vector<char> &data);
|
void readPSv(const std::vector<char> &data);
|
||||||
std::pair<bool, std::vector<char>> serialiseOPS() const;
|
std::pair<bool, std::vector<char>> serialiseOPS() const;
|
||||||
@ -120,9 +119,7 @@ public:
|
|||||||
void setSize(Vec2<int> newBlockSize);
|
void setSize(Vec2<int> newBlockSize);
|
||||||
// return value is [ fakeFromNewerVersion, gameData ]
|
// return value is [ fakeFromNewerVersion, gameData ]
|
||||||
std::pair<bool, std::vector<char>> Serialise() const;
|
std::pair<bool, std::vector<char>> Serialise() const;
|
||||||
vector2d Translate(vector2d translate);
|
void Transform(Mat2<int> transform, Vec2<int> nudge);
|
||||||
void Transform(matrix2d transform, vector2d translate);
|
|
||||||
void Transform(matrix2d transform, vector2d translate, vector2d translateReal, Vec2<int> newPartSize);
|
|
||||||
|
|
||||||
void Expand(const std::vector<char> &data);
|
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);
|
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;
|
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)
|
void GameController::PlaceSave(ui::Point position)
|
||||||
{
|
{
|
||||||
auto *placeSave = gameModel->GetPlaceSave();
|
auto *placeSave = gameModel->GetTransformedPlaceSave();
|
||||||
if (placeSave)
|
if (placeSave)
|
||||||
{
|
{
|
||||||
HistorySnapshot();
|
HistorySnapshot();
|
||||||
@ -248,6 +248,7 @@ void GameController::PlaceSave(ui::Point position)
|
|||||||
Client::Ref().MergeStampAuthorInfo(placeSave->authors);
|
Client::Ref().MergeStampAuthorInfo(placeSave->authors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gameModel->SetPlaceSave(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameController::Install()
|
void GameController::Install()
|
||||||
@ -420,23 +421,9 @@ void GameController::LoadStamp(std::unique_ptr<GameSave> stamp)
|
|||||||
gameModel->SetPlaceSave(std::move(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));
|
gameModel->TransformPlaceSave(transform, nudge);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameController::ToolClick(int toolSelection, ui::Point point)
|
void GameController::ToolClick(int toolSelection, ui::Point point)
|
||||||
|
@ -152,8 +152,7 @@ public:
|
|||||||
void ShowConsole();
|
void ShowConsole();
|
||||||
void HideConsole();
|
void HideConsole();
|
||||||
void FrameStep();
|
void FrameStep();
|
||||||
void TranslateSave(ui::Point point);
|
void TransformPlaceSave(Mat2<int> transform, Vec2<int> nudge);
|
||||||
void TransformSave(matrix2d transform);
|
|
||||||
bool MouseInZoom(ui::Point position);
|
bool MouseInZoom(ui::Point position);
|
||||||
ui::Point PointTranslate(ui::Point point);
|
ui::Point PointTranslate(ui::Point point);
|
||||||
ui::Point PointTranslateNoClamp(ui::Point point);
|
ui::Point PointTranslateNoClamp(ui::Point point);
|
||||||
|
@ -1336,10 +1336,21 @@ void GameModel::ClearSimulation()
|
|||||||
|
|
||||||
void GameModel::SetPlaceSave(std::unique_ptr<GameSave> save)
|
void GameModel::SetPlaceSave(std::unique_ptr<GameSave> save)
|
||||||
{
|
{
|
||||||
|
transformedPlaceSave.reset();
|
||||||
placeSave = std::move(save);
|
placeSave = std::move(save);
|
||||||
notifyPlaceSaveChanged();
|
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)
|
void GameModel::SetClipboard(std::unique_ptr<GameSave> save)
|
||||||
{
|
{
|
||||||
clipboard = std::move(save);
|
clipboard = std::move(save);
|
||||||
@ -1350,15 +1361,9 @@ const GameSave *GameModel::GetClipboard() const
|
|||||||
return clipboard.get();
|
return clipboard.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const GameSave *GameModel::GetPlaceSave() const
|
const GameSave *GameModel::GetTransformedPlaceSave() const
|
||||||
{
|
{
|
||||||
return placeSave.get();
|
return transformedPlaceSave.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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameModel::Log(String message, bool printToFile)
|
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)
|
void GameModel::notifyLogChanged(String entry)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < observers.size(); i++)
|
for (size_t i = 0; i < observers.size(); i++)
|
||||||
|
@ -46,6 +46,7 @@ private:
|
|||||||
//unsigned char * clipboardData;
|
//unsigned char * clipboardData;
|
||||||
std::unique_ptr<GameSave> clipboard;
|
std::unique_ptr<GameSave> clipboard;
|
||||||
std::unique_ptr<GameSave> placeSave;
|
std::unique_ptr<GameSave> placeSave;
|
||||||
|
std::unique_ptr<GameSave> transformedPlaceSave;
|
||||||
std::deque<String> consoleLog;
|
std::deque<String> consoleLog;
|
||||||
std::vector<GameView*> observers;
|
std::vector<GameView*> observers;
|
||||||
std::vector<Tool*> toolList;
|
std::vector<Tool*> toolList;
|
||||||
@ -104,6 +105,7 @@ private:
|
|||||||
void notifyZoomChanged();
|
void notifyZoomChanged();
|
||||||
void notifyClipboardChanged();
|
void notifyClipboardChanged();
|
||||||
void notifyPlaceSaveChanged();
|
void notifyPlaceSaveChanged();
|
||||||
|
void notifyTransformedPlaceSaveChanged();
|
||||||
void notifyColourSelectorColourChanged();
|
void notifyColourSelectorColourChanged();
|
||||||
void notifyColourSelectorVisibilityChanged();
|
void notifyColourSelectorVisibilityChanged();
|
||||||
void notifyColourPresetsChanged();
|
void notifyColourPresetsChanged();
|
||||||
@ -227,11 +229,12 @@ public:
|
|||||||
ui::Point GetZoomWindowPosition();
|
ui::Point GetZoomWindowPosition();
|
||||||
void SetClipboard(std::unique_ptr<GameSave> save);
|
void SetClipboard(std::unique_ptr<GameSave> save);
|
||||||
void SetPlaceSave(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);
|
void Log(String message, bool printToFile);
|
||||||
std::deque<String> GetLog();
|
std::deque<String> GetLog();
|
||||||
const GameSave *GetClipboard() const;
|
const GameSave *GetClipboard() const;
|
||||||
const GameSave *GetPlaceSave() const;
|
const GameSave *GetPlaceSave() const;
|
||||||
std::unique_ptr<GameSave> TakePlaceSave();
|
const GameSave *GetTransformedPlaceSave() const;
|
||||||
bool GetMouseClickRequired();
|
bool GetMouseClickRequired();
|
||||||
void SetMouseClickRequired(bool mouseClickRequired);
|
void SetMouseClickRequired(bool mouseClickRequired);
|
||||||
bool GetIncludePressure();
|
bool GetIncludePressure();
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
@ -1198,7 +1199,7 @@ void GameView::OnMouseUp(int x, int y, unsigned button)
|
|||||||
{
|
{
|
||||||
if (placeSaveThumb && y <= WINDOWH-BARSIZE)
|
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()));
|
thumb = thumb.Clamp(RectBetween(Vec2<int>::Zero, RES - placeSaveThumb->Size()));
|
||||||
c->PlaceSave(thumb);
|
c->PlaceSave(thumb);
|
||||||
}
|
}
|
||||||
@ -1334,16 +1335,16 @@ void GameView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
|
|||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case SDLK_RIGHT:
|
case SDLK_RIGHT:
|
||||||
c->TranslateSave(ui::Point(1, 0));
|
TranslateSave({ 1, 0 });
|
||||||
return;
|
return;
|
||||||
case SDLK_LEFT:
|
case SDLK_LEFT:
|
||||||
c->TranslateSave(ui::Point(-1, 0));
|
TranslateSave({ -1, 0 });
|
||||||
return;
|
return;
|
||||||
case SDLK_UP:
|
case SDLK_UP:
|
||||||
c->TranslateSave(ui::Point(0, -1));
|
TranslateSave({ 0, -1 });
|
||||||
return;
|
return;
|
||||||
case SDLK_DOWN:
|
case SDLK_DOWN:
|
||||||
c->TranslateSave(ui::Point(0, 1));
|
TranslateSave({ 0, 1 });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (scan == SDL_SCANCODE_R && !repeat)
|
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)
|
if (ctrl && shift)
|
||||||
{
|
{
|
||||||
//Vertical flip
|
//Vertical flip
|
||||||
c->TransformSave(m2d_new(1,0,0,-1));
|
TransformSave(Mat2<int>::MirrorY);
|
||||||
}
|
}
|
||||||
else if (!ctrl && shift)
|
else if (!ctrl && shift)
|
||||||
{
|
{
|
||||||
//Horizontal flip
|
//Horizontal flip
|
||||||
c->TransformSave(m2d_new(-1,0,0,1));
|
TransformSave(Mat2<int>::MirrorX);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Rotate 90deg
|
//Rotate 90deg
|
||||||
c->TransformSave(m2d_new(0,1,-1,0));
|
TransformSave(Mat2<int>::CCW);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1908,16 +1909,62 @@ void GameView::NotifyLogChanged(GameModel * sender, String entry)
|
|||||||
|
|
||||||
void GameView::NotifyPlaceSaveChanged(GameModel * sender)
|
void GameView::NotifyPlaceSaveChanged(GameModel * sender)
|
||||||
{
|
{
|
||||||
placeSaveOffset = ui::Point(0, 0);
|
placeSaveTransform = Mat2<int>::Identity;
|
||||||
if(sender->GetPlaceSave())
|
placeSaveTranslate = Vec2<int>::Zero;
|
||||||
|
ApplyTransformPlaceSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameView::TranslateSave(Vec2<int> addToTranslate)
|
||||||
|
{
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
placeSaveThumb = SaveRenderer::Ref().Render(sender->GetPlaceSave(), true, true, sender->GetRenderer());
|
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;
|
selectMode = PlaceSave;
|
||||||
selectPoint2 = mousePosition;
|
selectPoint2 = mousePosition;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
placeSaveThumb = nullptr;
|
placeSaveThumb.reset();
|
||||||
selectMode = SelectNone;
|
selectMode = SelectNone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2127,7 +2174,7 @@ void GameView::OnDraw()
|
|||||||
{
|
{
|
||||||
if(placeSaveThumb && selectPoint2.X!=-1)
|
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()));
|
thumb = c->NormaliseBlockCoord(thumb).Clamp(RectBetween(Vec2<int>::Zero, RES - placeSaveThumb->Size()));
|
||||||
auto rect = RectSized(thumb, placeSaveThumb->Size());
|
auto rect = RectSized(thumb, placeSaveThumb->Size());
|
||||||
ren->BlendImage(placeSaveThumb->Data(), 0x80, rect);
|
ren->BlendImage(placeSaveThumb->Data(), 0x80, rect);
|
||||||
|
@ -119,6 +119,11 @@ private:
|
|||||||
|
|
||||||
std::unique_ptr<VideoBuffer> placeSaveThumb;
|
std::unique_ptr<VideoBuffer> placeSaveThumb;
|
||||||
ui::Point placeSaveOffset;
|
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;
|
SimulationSample sample;
|
||||||
|
|
||||||
@ -185,6 +190,7 @@ public:
|
|||||||
void NotifyColourPresetsChanged(GameModel * sender);
|
void NotifyColourPresetsChanged(GameModel * sender);
|
||||||
void NotifyColourActivePresetChanged(GameModel * sender);
|
void NotifyColourActivePresetChanged(GameModel * sender);
|
||||||
void NotifyPlaceSaveChanged(GameModel * sender);
|
void NotifyPlaceSaveChanged(GameModel * sender);
|
||||||
|
void NotifyTransformedPlaceSaveChanged(GameModel *sender);
|
||||||
void NotifyNotificationsChanged(GameModel * sender);
|
void NotifyNotificationsChanged(GameModel * sender);
|
||||||
void NotifyLogChanged(GameModel * sender, String entry);
|
void NotifyLogChanged(GameModel * sender, String entry);
|
||||||
void NotifyToolTipChanged(GameModel * sender);
|
void NotifyToolTipChanged(GameModel * sender);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "simulation/ElementCommon.h"
|
#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_update(UPDATE_FUNC_ARGS);
|
||||||
int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS);
|
int Element_PIPE_graphics(GRAPHICS_FUNC_ARGS);
|
||||||
void Element_PIPE_transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part, bool STOR);
|
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_TRIGGER_ON = 0x10000000;
|
||||||
constexpr int PPIP_TMPFLAG_TRIGGERS = 0x1C000000;
|
constexpr int PPIP_TMPFLAG_TRIGGERS = 0x1C000000;
|
||||||
|
|
||||||
signed char pos_1_rx[] = { -1,-1,-1, 0, 0, 1, 1, 1 };
|
const std::array<Vec2<int>, 8> Element_PIPE_offsets = {{
|
||||||
signed char pos_1_ry[] = { -1, 0, 1,-1, 1,-1, 0, 1 };
|
{ -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 & 0x00000200) part.tmp = (part.tmp & 0xFFFFE3FF) | (offsetMap[(part.tmp & 0x00001C00) >> 10] << 10);
|
||||||
if (part.tmp & 0x00002000) part.tmp = (part.tmp & 0xFFFE3FFF) | (patch[(part.tmp & 0x0001C000) >> 14] << 14);
|
if (part.tmp & 0x00002000) part.tmp = (part.tmp & 0xFFFE3FFF) | (offsetMap[(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int prevColor(unsigned int flags)
|
static unsigned int prevColor(unsigned int flags)
|
||||||
@ -260,8 +243,8 @@ int Element_PIPE_update(UPDATE_FUNC_ARGS)
|
|||||||
rndstore = sim->rng.gen();
|
rndstore = sim->rng.gen();
|
||||||
rnd = rndstore&7;
|
rnd = rndstore&7;
|
||||||
//rndstore = rndstore>>3;
|
//rndstore = rndstore>>3;
|
||||||
rx = pos_1_rx[rnd];
|
rx = Element_PIPE_offsets[rnd].X;
|
||||||
ry = pos_1_ry[rnd];
|
ry = Element_PIPE_offsets[rnd].Y;
|
||||||
if (BOUNDS_CHECK)
|
if (BOUNDS_CHECK)
|
||||||
{
|
{
|
||||||
r = pmap[y+ry][x+rx];
|
r = pmap[y+ry][x+rx];
|
||||||
@ -501,8 +484,8 @@ static void pushParticle(Simulation * sim, int i, int count, int original)
|
|||||||
{
|
{
|
||||||
rnd = rndstore&7;
|
rnd = rndstore&7;
|
||||||
rndstore = rndstore>>3;
|
rndstore = rndstore>>3;
|
||||||
rx = pos_1_rx[rnd];
|
rx = Element_PIPE_offsets[rnd].X;
|
||||||
ry = pos_1_ry[rnd];
|
ry = Element_PIPE_offsets[rnd].Y;
|
||||||
if (BOUNDS_CHECK)
|
if (BOUNDS_CHECK)
|
||||||
{
|
{
|
||||||
r = sim->pmap[y+ry][x+rx];
|
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
|
else //predefined 1 pixel thick pipe movement
|
||||||
{
|
{
|
||||||
int coords = 7 - ((sim->parts[i].tmp>>10)&7);
|
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))
|
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);
|
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
|
else if (!r) //Move particles out of pipe automatically, much faster at ends
|
||||||
{
|
{
|
||||||
rx = pos_1_rx[coords];
|
rx = Element_PIPE_offsets[coords].X;
|
||||||
ry = pos_1_ry[coords];
|
ry = Element_PIPE_offsets[coords].Y;
|
||||||
np = sim->create_part(-1,x+rx,y+ry,TYP(sim->parts[i].ctype));
|
np = sim->create_part(-1,x+rx,y+ry,TYP(sim->parts[i].ctype));
|
||||||
if (np!=-1)
|
if (np!=-1)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user