Migrate Rects to (pos, size) representation

This commit is contained in:
Tamás Bálint Misius 2024-10-10 19:51:59 +02:00
parent 2cc5d9bbbb
commit c2bb777212
No known key found for this signature in database
GPG Key ID: 5B472A12F6ECA9F2
11 changed files with 87 additions and 117 deletions

View File

@ -121,44 +121,44 @@ void RasterizeEllipseRows(Vec2<float> radiusSquared, F f)
} }
// Call f for every point on the boundary of the indicated rectangle (so that // Call f for every point on the boundary of the indicated rectangle (so that
// TopLeft and BottomRight are both corners). // pos and BottomRight are both corners).
template<typename F> template<typename F>
void RasterizeRect(Rect<int> rect, F f) void RasterizeRect(Rect<int> rect, F f)
{ {
for (int x = rect.TopLeft.X; x <= rect.BottomRight.X; x++) for (int x = rect.pos.X; x < rect.pos.X + rect.size.X; x++)
f(Vec2(x, rect.TopLeft.Y)); f(Vec2(x, rect.pos.Y));
if (rect.TopLeft.Y != rect.BottomRight.Y) if (rect.pos.Y != rect.pos.Y + rect.size.Y - 1)
for (int x = rect.TopLeft.X; x <= rect.BottomRight.X; x++) for (int x = rect.pos.X; x < rect.pos.X + rect.size.X; x++)
f(Vec2(x, rect.BottomRight.Y)); f(Vec2(x, rect.pos.Y + rect.size.Y - 1));
// corners already drawn // corners already drawn
for (int y = rect.TopLeft.Y + 1; y <= rect.BottomRight.Y - 1; y++) for (int y = rect.pos.Y + 1; y < rect.pos.Y + rect.size.Y - 1; y++)
f(Vec2(rect.TopLeft.X, y)); f(Vec2(rect.pos.X, y));
if (rect.TopLeft.X != rect.BottomRight.X) if (rect.pos.X != rect.pos.X + rect.size.X - 1)
for (int y = rect.TopLeft.Y + 1; y <= rect.BottomRight.Y - 1; y++) for (int y = rect.pos.Y + 1; y < rect.pos.Y + rect.size.Y - 1; y++)
f(Vec2(rect.BottomRight.X, y)); f(Vec2(rect.pos.X + rect.size.X - 1, y));
} }
// Call f for every point on the dotted boundary of the indicated rectangle. // Call f for every point on the dotted boundary of the indicated rectangle.
template<typename F> template<typename F>
void RasterizeDottedRect(Rect<int> rect, F f) void RasterizeDottedRect(Rect<int> rect, F f)
{ {
for (int x = rect.TopLeft.X; x <= rect.BottomRight.X; x += 2) for (int x = rect.pos.X; x < rect.pos.X + rect.size.X; x += 2)
f(Vec2(x, rect.TopLeft.Y)); f(Vec2(x, rect.pos.Y));
int bottomOff = (rect.BottomRight.Y - rect.TopLeft.Y) % 2; int bottomOff = (rect.pos.Y + rect.size.Y - 1 - rect.pos.Y) % 2;
if (rect.TopLeft.Y != rect.BottomRight.Y) if (rect.pos.Y != rect.pos.Y + rect.size.Y - 1)
for (int x = rect.TopLeft.X + bottomOff; x <= rect.BottomRight.X; x += 2) for (int x = rect.pos.X + bottomOff; x < rect.pos.X + rect.size.X; x += 2)
f(Vec2(x, rect.BottomRight.Y)); f(Vec2(x, rect.pos.Y + rect.size.Y - 1));
// corners already drawn // corners already drawn
for (int y = rect.TopLeft.Y + 1 + 1; y <= rect.BottomRight.Y - 1; y += 2) for (int y = rect.pos.Y + 1 + 1; y < rect.pos.Y + rect.size.Y - 1; y += 2)
f(Vec2(rect.TopLeft.X, y)); f(Vec2(rect.pos.X, y));
int leftOff = (rect.BottomRight.X - rect.TopLeft.X + 1) % 2; int leftOff = (rect.pos.X + rect.size.X - 1 - rect.pos.X + 1) % 2;
if (rect.TopLeft.X != rect.BottomRight.X) if (rect.pos.X != rect.pos.X + rect.size.X - 1)
for (int y = rect.TopLeft.Y + 1 + leftOff; y <= rect.BottomRight.Y - 1; y += 2) for (int y = rect.pos.Y + 1 + leftOff; y < rect.pos.Y + rect.size.Y - 1; y += 2)
f(Vec2(rect.BottomRight.X, y)); f(Vec2(rect.pos.X + rect.size.X - 1, y));
} }

View File

@ -107,8 +107,8 @@ struct Vec2
Vec2<T> Clamp(Rect<T> rect) const Vec2<T> Clamp(Rect<T> rect) const
{ {
return Vec2<T>( return Vec2<T>(
std::clamp(X, rect.TopLeft.X, rect.BottomRight.X), std::clamp(X, rect.pos.X, rect.pos.X + rect.size.X - T(1)),
std::clamp(Y, rect.TopLeft.Y, rect.BottomRight.Y) std::clamp(Y, rect.pos.Y, rect.pos.Y + rect.size.Y - T(1))
); );
} }
@ -185,8 +185,8 @@ Mat2<T> const Mat2<T, V>::MirrorY = Mat2<T>(1, 0, 0, -1);
template<typename T, typename V> template<typename T, typename V>
Mat2<T> const Mat2<T, V>::CCW = Mat2<T>(0, 1, -1, 0); // reminder: the Y axis points down Mat2<T> const Mat2<T, V>::CCW = Mat2<T>(0, 1, -1, 0); // reminder: the Y axis points down
template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>> template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
constexpr static inline Rect<T> RectBetween(Vec2<T>, Vec2<T>); constexpr static inline Rect<T> RectSized(Vec2<T>, Vec2<T>);
enum IterationDirection enum IterationDirection
{ {
@ -200,16 +200,15 @@ template<typename T, typename>
struct Rect struct Rect
{ {
// Inclusive // Inclusive
Vec2<T> TopLeft, BottomRight; Vec2<T> pos, size;
private: constexpr Rect(Vec2<T> newPos, Vec2<T> newSize):
constexpr Rect(Vec2<T> topLeft, Vec2<T> bottomRight): pos(newPos),
TopLeft(topLeft), size(newSize)
BottomRight(bottomRight)
{ {
} }
friend constexpr Rect<T> RectBetween<T>(Vec2<T>, Vec2<T>);
private:
struct end_sentinel struct end_sentinel
{}; {};
@ -350,48 +349,25 @@ private:
public: public:
constexpr bool operator==(Rect other) const constexpr bool operator==(Rect other) const
{ {
return TopLeft == other.TopLeft && BottomRight == other.BottomRight; return pos == other.pos && size == other.size;
} }
constexpr bool operator!=(Rect other) const constexpr bool operator!=(Rect other) const
{ {
return TopLeft != other.TopLeft || BottomRight != other.BottomRight; return pos != other.pos || size != other.size;
} }
constexpr explicit operator bool() const constexpr explicit operator bool() const
{ {
return BottomRight.X >= TopLeft.X && BottomRight.Y >= TopLeft.Y; return size.X > 0 && size.Y > 0;
}
// Return the smallest rectangle that contains both input rectangles,
// **assuming neither are empty**
Rect<T> operator|(Rect<T> other) const
{
return Rect<T>(
Vec2<T>(std::min(TopLeft.X, other.TopLeft.X), std::min(TopLeft.Y, other.TopLeft.Y)),
Vec2<T>(std::max(BottomRight.X, other.BottomRight.X), std::max(BottomRight.Y, other.BottomRight.Y))
);
} }
// Return the intersection of two rectangles (possibly empty) // Return the intersection of two rectangles (possibly empty)
Rect<T> operator&(Rect<T> other) const Rect<T> operator&(Rect<T> other) const
{ {
auto rect = Rect<T>( auto tl = Vec2<T>(std::max(pos.X , other.pos.X ), std::max(pos.Y , other.pos.Y ));
Vec2<T>(std::max(TopLeft.X, other.TopLeft.X), std::max(TopLeft.Y, other.TopLeft.Y)), auto br1 = Vec2<T>(std::min(pos.X + size.X, other.pos.X + other.size.X), std::min(pos.Y + size.Y, other.pos.Y + other.size.Y));
Vec2<T>(std::min(BottomRight.X, other.BottomRight.X), std::min(BottomRight.Y, other.BottomRight.Y)) return Rect<T>(tl, br1 - tl);
);
return Rect<T>(
rect.TopLeft,
Vec2<T>(
std::max(rect.TopLeft.X - 1, rect.BottomRight.X),
std::max(rect.TopLeft.Y - 1, rect.BottomRight.Y)
)
);
}
inline Rect<T> &operator|=(Rect<T> other)
{
return *this = *this | other;
} }
inline Rect<T> &operator&=(Rect<T> other) inline Rect<T> &operator&=(Rect<T> other)
@ -401,19 +377,13 @@ public:
constexpr bool Contains(Vec2<T> point) const constexpr bool Contains(Vec2<T> point) const
{ {
return point.X >= TopLeft.X && point.X <= BottomRight.X && point.Y >= TopLeft.Y && point.Y <= BottomRight.Y; return point.X >= pos.X && point.X < pos.X + size.X && point.Y >= pos.Y && point.Y < pos.Y + size.Y;
}
template<typename S = T, typename = std::enable_if_t<std::is_integral_v<S>>>
inline Vec2<T> Size() const
{
return BottomRight - TopLeft + Vec2<T>(1, 1);
} }
template<typename S> template<typename S>
Rect<decltype(std::declval<T>() + std::declval<S>())> Inset(S delta) const Rect<decltype(std::declval<T>() + std::declval<S>())> Inset(S delta) const
{ {
return Rect<decltype(std::declval<T>() + std::declval<S>())>(TopLeft + Vec2(delta, delta), BottomRight - Vec2(delta, delta)); return Rect<decltype(std::declval<T>() + std::declval<S>())>(pos + Vec2(delta, delta), size - Vec2(delta, delta) * S(2));
} }
template<IterationDirection D1, IterationDirection D2, typename S = T, typename = std::enable_if_t<std::is_integral_v<T>>> template<IterationDirection D1, IterationDirection D2, typename S = T, typename = std::enable_if_t<std::is_integral_v<T>>>
@ -426,10 +396,10 @@ public:
); );
if constexpr (D1 == TOP_TO_BOTTOM || D1 == BOTTOM_TO_TOP) if constexpr (D1 == TOP_TO_BOTTOM || D1 == BOTTOM_TO_TOP)
{ {
return range_row_major<D1, D2>{TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y}; return range_row_major<D1, D2>{pos.X, pos.Y, pos.X + size.X - T(1), pos.Y + size.Y - T(1)};
} }
else else
return range_column_major<D1, D2>{TopLeft.X, TopLeft.Y, BottomRight.X, BottomRight.Y}; return range_column_major<D1, D2>{pos.X, pos.Y, pos.X + size.X - T(1), pos.Y + size.Y - T(1)};
} }
// Use when the order isn't important // Use when the order isn't important
@ -445,19 +415,19 @@ public:
}; };
template<typename T, typename> template<typename T, typename>
constexpr inline Rect<T> RectSized(Vec2<T> pos, Vec2<T> size)
{
return Rect<T>(pos, size);
}
template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
constexpr inline Rect<T> RectBetween(Vec2<T> topLeft, Vec2<T> bottomRight) constexpr inline Rect<T> RectBetween(Vec2<T> topLeft, Vec2<T> bottomRight)
{ {
return Rect<T>(topLeft, bottomRight); return RectSized(topLeft, bottomRight - topLeft + Vec2<T>(1, 1));
} }
template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>> template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
constexpr inline Rect<T> RectAt(Vec2<T> pos) constexpr inline Rect<T> RectAt(Vec2<T> pos)
{ {
return RectBetween<T>(pos, pos); return RectSized(pos, Vec2<T>(1, 1));
}
template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
constexpr inline Rect<T> RectSized(Vec2<T> topLeft, Vec2<T> dimen)
{
return RectBetween<T>(topLeft, topLeft + dimen - Vec2<T>(1, 1));
} }

View File

@ -36,10 +36,10 @@ void VideoBuffer::Crop(Rect<int> rect)
if (rect == Size().OriginRect()) if (rect == Size().OriginRect())
return; return;
PlaneAdapter<std::vector<pixel> &> newVideo(rect.Size(), std::in_place, video.Base); PlaneAdapter<std::vector<pixel> &> newVideo(rect.size, std::in_place, video.Base);
for (auto y = 0; y < newVideo.Size().Y; y++) for (auto y = 0; y < newVideo.Size().Y; y++)
std::copy_n( std::copy_n(
video.RowIterator(rect.TopLeft + Vec2(0, y)), video.RowIterator(rect.pos + Vec2(0, y)),
newVideo.Size().X, newVideo.Size().X,
newVideo.RowIterator(Vec2(0, y)) newVideo.RowIterator(Vec2(0, y))
); );

View File

@ -135,8 +135,8 @@ void RasterDrawMethods<Derived>::DrawFilledRect(Rect<int> rect, RGB<uint8_t> col
pixel packed = colour.Pack(); pixel packed = colour.Pack();
auto &video = static_cast<Derived &>(*this).video; auto &video = static_cast<Derived &>(*this).video;
if (rect) if (rect)
for (int y = rect.TopLeft.Y; y <= rect.BottomRight.Y; y++) for (int y = rect.pos.Y; y < rect.pos.Y + rect.size.Y; y++)
std::fill_n(video.RowIterator(Vec2(rect.TopLeft.X, y)), rect.Size().X, packed); std::fill_n(video.RowIterator(Vec2(rect.pos.X, y)), rect.size.X, packed);
} }
template<typename Derived> template<typename Derived>
@ -166,22 +166,22 @@ void RasterDrawMethods<Derived>::BlendFilledEllipse(Vec2<int> center, Vec2<int>
template<typename Derived> template<typename Derived>
void RasterDrawMethods<Derived>::BlendImage(pixel const *data, uint8_t alpha, Rect<int> rect) void RasterDrawMethods<Derived>::BlendImage(pixel const *data, uint8_t alpha, Rect<int> rect)
{ {
BlendImage(data, alpha, rect, rect.Size().X); BlendImage(data, alpha, rect, rect.size.X);
} }
template<typename Derived> template<typename Derived>
void RasterDrawMethods<Derived>::BlendImage(pixel const *data, uint8_t alpha, Rect<int> rect, size_t rowStride) void RasterDrawMethods<Derived>::BlendImage(pixel const *data, uint8_t alpha, Rect<int> rect, size_t rowStride)
{ {
auto origin = rect.TopLeft; auto origin = rect.pos;
rect &= clipRect(); rect &= clipRect();
if (alpha == 0xFF) if (alpha == 0xFF)
{ {
auto &video = static_cast<Derived &>(*this).video; auto &video = static_cast<Derived &>(*this).video;
for (int y = rect.TopLeft.Y; y <= rect.BottomRight.Y; y++) for (int y = rect.pos.Y; y < rect.pos.Y + rect.size.Y; y++)
std::copy_n( std::copy_n(
data + (rect.TopLeft.X - origin.X) + (y - origin.Y) * rowStride, data + (rect.pos.X - origin.X) + (y - origin.Y) * rowStride,
rect.Size().X, rect.size.X,
video.RowIterator(Vec2(rect.TopLeft.X, y)) video.RowIterator(Vec2(rect.pos.X, y))
); );
} }
else else
@ -197,13 +197,13 @@ void RasterDrawMethods<Derived>::BlendImage(pixel const *data, uint8_t alpha, Re
template<typename Derived> template<typename Derived>
void RasterDrawMethods<Derived>::XorImage(unsigned char const *data, Rect<int> rect) void RasterDrawMethods<Derived>::XorImage(unsigned char const *data, Rect<int> rect)
{ {
XorImage(data, rect, rect.Size().X); XorImage(data, rect, rect.size.X);
} }
template<typename Derived> template<typename Derived>
void RasterDrawMethods<Derived>::XorImage(unsigned char const *data, Rect<int> rect, size_t rowStride) void RasterDrawMethods<Derived>::XorImage(unsigned char const *data, Rect<int> rect, size_t rowStride)
{ {
auto origin = rect.TopLeft; auto origin = rect.pos;
rect &= clipRect(); rect &= clipRect();
for (auto pos : rect) for (auto pos : rect)
if (data[(pos.X - origin.X) + (pos.Y - origin.Y) * rowStride]) if (data[(pos.X - origin.X) + (pos.Y - origin.Y) * rowStride])
@ -213,13 +213,13 @@ void RasterDrawMethods<Derived>::XorImage(unsigned char const *data, Rect<int> r
template<typename Derived> template<typename Derived>
void RasterDrawMethods<Derived>::BlendRGBAImage(pixel_rgba const *data, Rect<int> rect) void RasterDrawMethods<Derived>::BlendRGBAImage(pixel_rgba const *data, Rect<int> rect)
{ {
BlendRGBAImage(data, rect, rect.Size().X); BlendRGBAImage(data, rect, rect.size.X);
} }
template<typename Derived> template<typename Derived>
void RasterDrawMethods<Derived>::BlendRGBAImage(pixel_rgba const *data, Rect<int> rect, size_t rowStride) void RasterDrawMethods<Derived>::BlendRGBAImage(pixel_rgba const *data, Rect<int> rect, size_t rowStride)
{ {
auto origin = rect.TopLeft; auto origin = rect.pos;
rect &= clipRect(); rect &= clipRect();
for (auto pos : rect) for (auto pos : rect)
{ {

View File

@ -50,7 +50,7 @@ void ToolButton::Draw(const ui::Point& screenPos)
{ {
Graphics * g = GetGraphics(); Graphics * g = GetGraphics();
auto rect = ClipRect; auto rect = ClipRect;
if (ClipRect.Size().X && ClipRect.Size().Y) if (ClipRect.size.X && ClipRect.size.Y)
g->SwapClipRect(rect); // old cliprect is now in rect g->SwapClipRect(rect); // old cliprect is now in rect
int totalColour = Appearance.BackgroundInactive.Blue + (3*Appearance.BackgroundInactive.Green) + (2*Appearance.BackgroundInactive.Red); int totalColour = Appearance.BackgroundInactive.Blue + (3*Appearance.BackgroundInactive.Green) + (2*Appearance.BackgroundInactive.Red);
@ -87,7 +87,7 @@ void ToolButton::Draw(const ui::Point& screenPos)
g->BlendText(screenPos + textPosition, buttonDisplayText, 0x000000_rgb .WithAlpha(255)); g->BlendText(screenPos + textPosition, buttonDisplayText, 0x000000_rgb .WithAlpha(255));
} }
if (ClipRect.Size().X && ClipRect.Size().Y) if (ClipRect.size.X && ClipRect.size.Y)
g->SwapClipRect(rect); // apply old clip rect g->SwapClipRect(rect); // apply old clip rect
} }

View File

@ -80,7 +80,7 @@ void Panel::Draw(const Point& screenPos)
//check if the component is in the screen, draw if it is //check if the component is in the screen, draw if it is
if (rect & Size.OriginRect()) if (rect & Size.OriginRect())
{ {
child->Draw(screenPos + rect.TopLeft); child->Draw(screenPos + rect.pos);
} }
} }

View File

@ -46,7 +46,7 @@ void ProgressBar::Draw(const Point &screenPos)
g->DrawRect(RectSized(screenPos, Size), 0xFFFFFF_rgb); g->DrawRect(RectSized(screenPos, Size), 0xFFFFFF_rgb);
auto inner = RectSized(screenPos + Vec2{ 2, 2 }, Size - Vec2{ 4, 4 }); auto inner = RectSized(screenPos + Vec2{ 2, 2 }, Size - Vec2{ 4, 4 });
auto drawContent = [this, screenPos, g, inner](int beginX, int endX, ui::Colour bgColour, ui::Colour textColour) { auto drawContent = [this, screenPos, g, inner](int beginX, int endX, ui::Colour bgColour, ui::Colour textColour) {
auto clip = RectSized(inner.TopLeft + Vec2{ beginX, 0 }, Vec2{ endX - beginX, inner.Size().Y }) & g->GetClipRect(); auto clip = RectSized(inner.pos + Vec2{ beginX, 0 }, Vec2{ endX - beginX, inner.size.Y }) & g->GetClipRect();
g->SwapClipRect(clip); g->SwapClipRect(clip);
if (bgColour.Alpha) if (bgColour.Alpha)
{ {
@ -58,18 +58,18 @@ void ProgressBar::Draw(const Point &screenPos)
}, progressStatus, textColour); }, progressStatus, textColour);
g->SwapClipRect(clip); g->SwapClipRect(clip);
}; };
drawContent(0, inner.Size().X, 0x000000_rgb .WithAlpha(0), 0xFFFFFF_rgb .WithAlpha(255)); drawContent(0, inner.size.X, 0x000000_rgb .WithAlpha(0), 0xFFFFFF_rgb .WithAlpha(255));
if (progress == -1) if (progress == -1)
{ {
constexpr auto size = 40; constexpr auto size = 40;
auto pos = int(inner.Size().X * intermediatePos / 100); auto pos = int(inner.size.X * intermediatePos / 100);
drawContent(pos, pos + size, style::Colour::WarningTitle, 0x000000_rgb .WithAlpha(255)); drawContent(pos, pos + size, style::Colour::WarningTitle, 0x000000_rgb .WithAlpha(255));
pos -= inner.Size().X; pos -= inner.size.X;
drawContent(pos, pos + size, style::Colour::WarningTitle, 0x000000_rgb .WithAlpha(255)); drawContent(pos, pos + size, style::Colour::WarningTitle, 0x000000_rgb .WithAlpha(255));
} }
else else
{ {
drawContent(0, inner.Size().X * progress / 100, style::Colour::WarningTitle, 0x000000_rgb .WithAlpha(255)); drawContent(0, inner.size.X * progress / 100, style::Colour::WarningTitle, 0x000000_rgb .WithAlpha(255));
} }
} }

View File

@ -189,7 +189,7 @@ void Window::DoDraw()
{ {
auto rect = RectSized(Position + child->Position, child->Size); auto rect = RectSized(Position + child->Position, child->Size);
if (AllowExclusiveDrawing || bool(rect & GetGraphics()->Size().OriginRect())) if (AllowExclusiveDrawing || bool(rect & GetGraphics()->Size().OriginRect()))
child->Draw(rect.TopLeft); child->Draw(rect.pos);
} }
}; };
for (auto child : Components) for (auto child : Components)

View File

@ -261,10 +261,10 @@ static int setClipRect(lua_State *L)
int h = luaL_optinteger(L, 4, WINDOWH); int h = luaL_optinteger(L, 4, WINDOWH);
auto rect = RectSized(Vec2(x, y), Vec2(w, h)); auto rect = RectSized(Vec2(x, y), Vec2(w, h));
lsi->g->SwapClipRect(rect); lsi->g->SwapClipRect(rect);
lua_pushinteger(L, rect.TopLeft.X); lua_pushinteger(L, rect.pos.X);
lua_pushinteger(L, rect.TopLeft.Y); lua_pushinteger(L, rect.pos.Y);
lua_pushinteger(L, rect.Size().X); lua_pushinteger(L, rect.size.X);
lua_pushinteger(L, rect.Size().Y); lua_pushinteger(L, rect.size.Y);
return 4; return 4;
} }

View File

@ -85,10 +85,10 @@ void Simulation::Restore(const Snapshot &snap)
void Simulation::clear_area(int area_x, int area_y, int area_w, int area_h) void Simulation::clear_area(int area_x, int area_y, int area_w, int area_h)
{ {
auto intersection = RES.OriginRect() & RectSized(Vec2{ area_x, area_y }, Vec2{ area_w, area_h }); auto intersection = RES.OriginRect() & RectSized(Vec2{ area_x, area_y }, Vec2{ area_w, area_h });
area_x = intersection.TopLeft.X; area_x = intersection.pos.X;
area_y = intersection.TopLeft.Y; area_y = intersection.pos.Y;
area_w = intersection.Size().X; area_w = intersection.size.X;
area_h = intersection.Size().Y; area_h = intersection.size.Y;
float fx = area_x-.5f, fy = area_y-.5f; float fx = area_x-.5f, fy = area_y-.5f;
for (int i = 0; i <= parts_lastActiveIndex; i++) for (int i = 0; i <= parts_lastActiveIndex; i++)
{ {

View File

@ -53,20 +53,20 @@ void Simulation::Load(const GameSave *save, bool includePressure, Vec2<int> bloc
std::sort(existingParticles.begin(), existingParticles.end(), [](const auto &lhs, const auto &rhs) { std::sort(existingParticles.begin(), existingParticles.end(), [](const auto &lhs, const auto &rhs) {
return std::tie(lhs.pos.Y, lhs.pos.X) < std::tie(rhs.pos.Y, rhs.pos.X); return std::tie(lhs.pos.Y, lhs.pos.X) < std::tie(rhs.pos.Y, rhs.pos.X);
}); });
PlaneAdapter<std::vector<size_t>> existingParticleIndices(pasteArea.Size(), existingParticles.size()); PlaneAdapter<std::vector<size_t>> existingParticleIndices(pasteArea.size, existingParticles.size());
{ {
auto lastPos = Vec2<int>{ -1, -1 }; // not a valid pos in existingParticles auto lastPos = Vec2<int>{ -1, -1 }; // not a valid pos in existingParticles
for (auto it = existingParticles.begin(); it != existingParticles.end(); ++it) for (auto it = existingParticles.begin(); it != existingParticles.end(); ++it)
{ {
if (lastPos != it->pos) if (lastPos != it->pos)
{ {
existingParticleIndices[it->pos - pasteArea.TopLeft] = it - existingParticles.begin(); existingParticleIndices[it->pos - pasteArea.pos] = it - existingParticles.begin();
lastPos = it->pos; lastPos = it->pos;
} }
} }
} }
auto removeExistingParticles = [this, pasteArea, &existingParticles, &existingParticleIndices](Vec2<int> p) { auto removeExistingParticles = [this, pasteArea, &existingParticles, &existingParticleIndices](Vec2<int> p) {
auto rp = p - pasteArea.TopLeft; auto rp = p - pasteArea.pos;
if (existingParticleIndices.Size().OriginRect().Contains(rp)) if (existingParticleIndices.Size().OriginRect().Contains(rp))
{ {
auto index = existingParticleIndices[rp]; auto index = existingParticleIndices[rp];
@ -312,10 +312,10 @@ void Simulation::Load(const GameSave *save, bool includePressure, Vec2<int> bloc
std::unique_ptr<GameSave> Simulation::Save(bool includePressure, Rect<int> partR) // particle coordinates std::unique_ptr<GameSave> Simulation::Save(bool includePressure, Rect<int> partR) // particle coordinates
{ {
auto blockR = RectBetween(partR.TopLeft / CELL, partR.BottomRight / CELL); auto blockR = RectSized(partR.pos / CELL, partR.size / CELL);
auto blockP = blockR.TopLeft; auto blockP = blockR.pos;
auto newSave = std::make_unique<GameSave>(blockR.Size()); auto newSave = std::make_unique<GameSave>(blockR.size);
newSave->frameCount = frameCount; newSave->frameCount = frameCount;
newSave->rngState = rng.state(); newSave->rngState = rng.state();