Use integer matrices for GameSave transforms

This commit is contained in:
mniip 2023-02-19 20:15:22 +01:00
parent b2328c41b5
commit 31abb8a48f
5 changed files with 39 additions and 41 deletions

View File

@ -120,9 +120,8 @@ inline Vec2<int> lroundNegInf(Vec2<float> v)
return Vec2<int>(roundNegInf(v));
}
Vec2<float> GameSave::Translate(Vec2<float> translate)
Vec2<int> GameSave::Translate(Vec2<int> translate)
{
Vec2<float> translateReal = translate;
auto bounds = Rect<float>(Vec2<float>::Zero);
// determine minimum and maximum position of all particles / signs
@ -135,18 +134,18 @@ Vec2<float> GameSave::Translate(Vec2<float> translate)
bounds |= Rect<float>(roundNegInf(Vec2<float>(particles[i].x, particles[i].y) + translate));
}
// determine whether corrections are needed. If moving in this direction would delete stuff, expand the save
auto backCorrection = Vec2<float>(
std::max(0.0f, -std::floor(bounds.TopLeft.X / CELL)),
std::max(0.0f, -std::floor(bounds.TopLeft.Y / CELL))
auto backCorrection = Vec2<int>(
std::max(0, -int(std::floor(bounds.TopLeft.X / CELL))),
std::max(0, -int(std::floor(bounds.TopLeft.Y / CELL)))
);
auto frontCorrection = Vec2<float>(
std::max(0, int(bounds.BottomRight.X / CELL) + 1 - blockDimen.X), // TODO: sus. std::floor?
std::max(0, int(bounds.BottomRight.Y / CELL) + 1 - blockDimen.Y)
auto frontCorrection = Vec2<int>(
std::max(0, int(std::floor(bounds.BottomRight.X / CELL)) + 1 - blockDimen.X),
std::max(0, int(std::floor(bounds.BottomRight.Y / CELL)) + 1 - blockDimen.Y)
);
// get new width based on corrections
auto newDimen = [=]() {
return Vec2<int>((Vec2<float>(blockDimen) + backCorrection + frontCorrection) * CELL);
return (blockDimen + backCorrection + frontCorrection) * CELL;
};
if (newDimen().X > XRES)
frontCorrection.X = backCorrection.X = 0;
@ -154,38 +153,37 @@ Vec2<float> GameSave::Translate(Vec2<float> translate)
frontCorrection.Y = backCorrection.Y = 0;
// call Transform to do the transformation we wanted when calling this function
Vec2<int> translateReal = translate;
translate += backCorrection * CELL;
Transform(Mat2<float>::Identity, translate + backCorrection * CELL, translateReal, newDimen());
Transform(Mat2<int>::Identity, translate, translateReal, newDimen());
// 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 backCorrection * (-CELL) + frontCorrection * CELL;
return backCorrection * -CELL + frontCorrection * CELL;
}
void GameSave::Transform(Mat2<float> transform, Vec2<float> translate)
void GameSave::Transform(Mat2<int> transform, Vec2<int> translate)
{
Vec2<float> cornerso[4] = {
Vec2<float>(0, 0),
Vec2<float>(blockDimen.X * CELL - 1, 0),
Vec2<float>(0, blockDimen.Y * CELL - 1),
Vec2<float>(blockDimen.X * CELL - 1, blockDimen.Y * CELL - 1),
Vec2<int> cornerso[4] = {
Vec2<int>(0, 0),
Vec2<int>(blockDimen.X * CELL - 1, 0),
Vec2<int>(0, blockDimen.Y * CELL - 1),
Vec2<int>(blockDimen.X * CELL - 1, blockDimen.Y * CELL - 1),
};
// undo any translation caused by rotation
auto bounds = Rect<float>(transform * cornerso[0]);
auto bounds = Rect<int>(transform * cornerso[0]);
for (int i = 1; i < 4; i++)
bounds |= Rect<float>(transform * cornerso[i]);
// casting as int doesn't quite do what we want with negative numbers, so use floor()
Vec2<float> translateReal = translate - roundNegInf(bounds.TopLeft);
auto newBounds = lroundNegInf(bounds.BottomRight) - lroundNegInf(bounds.TopLeft) + Vec2<int>(1, 1);
bounds |= Rect<int>(transform * cornerso[i]);
Vec2<int> translateReal = translate;
translate -= bounds.TopLeft;
auto newBounds = bounds.BottomRight - bounds.TopLeft + Vec2<int>(1, 1);
Transform(transform, translate, translateReal, newBounds);
}
// 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(Mat2<float> transform, Vec2<float> translate, Vec2<float> translateReal, Vec2<int> newDimen)
void GameSave::Transform(Mat2<int> transform, Vec2<int> translate, Vec2<int> translateReal, Vec2<int> newDimen)
{
newDimen.X = std::min(newDimen.X, XRES);
newDimen.Y = std::min(newDimen.Y, YRES);
@ -201,15 +199,15 @@ void GameSave::Transform(Mat2<float> transform, Vec2<float> translate, Vec2<floa
Plane<float> ambientHeatNew(newBlockDimen.X, newBlockDimen.Y, 0.0f);
// Match these up with the matrices provided in GameView::OnKeyPress.
bool patchPipeR = transform == Mat2<float>::CW;
bool patchPipeH = transform == Mat2<float>::MirrorX;
bool patchPipeV = transform == Mat2<float>::MirrorY;
bool patchPipeR = transform == Mat2<int>::CCW;
bool patchPipeH = transform == Mat2<int>::MirrorX;
bool patchPipeV = transform == Mat2<int>::MirrorY;
// rotate and translate signs, parts, walls
auto bounds = Rect<int>(Vec2<int>::Zero, newDimen - Vec2<int>(1, 1));
for (auto &sign : signs)
{
auto pos = lroundNegInf(transform * Vec2<float>(sign.x, sign.y) + translate);
auto pos = transform * Vec2<int>(sign.x, sign.y) + translate;
if (!bounds.Contains(pos))
{
sign.text[0] = 0;
@ -221,6 +219,7 @@ void GameSave::Transform(Mat2<float> transform, Vec2<float> translate, Vec2<floa
for (int i = 0; i < particlesCount; i++)
{
if (!particles[i].type) continue;
// TODO: should this round?
auto pos = lroundNegInf(transform * Vec2<float>(particles[i].x, particles[i].y) + translate);
if (!bounds.Contains(pos))
{

View File

@ -133,9 +133,9 @@ public:
void setSize(Vec2<int> dimen);
// return value is [ fakeFromNewerVersion, gameData ]
std::pair<bool, std::vector<char>> Serialise() const;
Vec2<float> Translate(Vec2<float> translate);
void Transform(Mat2<float> transform, Vec2<float> translate);
void Transform(Mat2<float> transform, Vec2<float> translate, Vec2<float> translateReal, Vec2<int> newDimen);
Vec2<int> Translate(Vec2<int> translate);
void Transform(Mat2<int> transform, Vec2<int> translate);
void Transform(Mat2<int> transform, Vec2<int> translate, Vec2<int> translateReal, Vec2<int> newDimen);
void Expand(const std::vector<char> &data);

View File

@ -422,17 +422,16 @@ void GameController::LoadStamp(GameSave *stamp)
void GameController::TranslateSave(ui::Point point)
{
auto translate = Vec2<float>(point);
auto translated = gameModel->GetPlaceSave()->Translate(translate);
auto translated = gameModel->GetPlaceSave()->Translate(point);
ui::Point currentPlaceSaveOffset = gameView->GetPlaceSaveOffset();
// resets placeSaveOffset to 0, which is why we back it up first
gameModel->SetPlaceSave(gameModel->GetPlaceSave());
gameView->SetPlaceSaveOffset(ui::Point(translated) + currentPlaceSaveOffset);
gameView->SetPlaceSaveOffset(translated + currentPlaceSaveOffset);
}
void GameController::TransformSave(Mat2<float> transform)
void GameController::TransformSave(Mat2<int> transform)
{
gameModel->GetPlaceSave()->Transform(transform, Vec2<float>::Zero);
gameModel->GetPlaceSave()->Transform(transform, Vec2<int>::Zero);
gameModel->SetPlaceSave(gameModel->GetPlaceSave());
}

View File

@ -153,7 +153,7 @@ public:
void HideConsole();
void FrameStep();
void TranslateSave(ui::Point point);
void TransformSave(Mat2<float> transform);
void TransformSave(Mat2<int> transform);
bool MouseInZoom(ui::Point position);
ui::Point PointTranslate(ui::Point point);
ui::Point PointTranslateNoClamp(ui::Point point);

View File

@ -1364,17 +1364,17 @@ void GameView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
if (ctrl && shift)
{
//Vertical flip
c->TransformSave(Mat2<float>::MirrorY);
c->TransformSave(Mat2<int>::MirrorY);
}
else if (!ctrl && shift)
{
//Horizontal flip
c->TransformSave(Mat2<float>::MirrorX);
c->TransformSave(Mat2<int>::MirrorX);
}
else
{
//Rotate 90deg
c->TransformSave(Mat2<float>::CW);
c->TransformSave(Mat2<int>::CCW);
}
return;
}