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
// TopLeft and BottomRight are both corners).
// pos and BottomRight are both corners).
template<typename F>
void RasterizeRect(Rect<int> rect, F f)
{
for (int x = rect.TopLeft.X; x <= rect.BottomRight.X; x++)
f(Vec2(x, rect.TopLeft.Y));
for (int x = rect.pos.X; x < rect.pos.X + rect.size.X; x++)
f(Vec2(x, rect.pos.Y));
if (rect.TopLeft.Y != rect.BottomRight.Y)
for (int x = rect.TopLeft.X; x <= rect.BottomRight.X; x++)
f(Vec2(x, rect.BottomRight.Y));
if (rect.pos.Y != rect.pos.Y + rect.size.Y - 1)
for (int x = rect.pos.X; x < rect.pos.X + rect.size.X; x++)
f(Vec2(x, rect.pos.Y + rect.size.Y - 1));
// corners already drawn
for (int y = rect.TopLeft.Y + 1; y <= rect.BottomRight.Y - 1; y++)
f(Vec2(rect.TopLeft.X, y));
for (int y = rect.pos.Y + 1; y < rect.pos.Y + rect.size.Y - 1; y++)
f(Vec2(rect.pos.X, y));
if (rect.TopLeft.X != rect.BottomRight.X)
for (int y = rect.TopLeft.Y + 1; y <= rect.BottomRight.Y - 1; y++)
f(Vec2(rect.BottomRight.X, y));
if (rect.pos.X != rect.pos.X + rect.size.X - 1)
for (int y = rect.pos.Y + 1; y < rect.pos.Y + rect.size.Y - 1; y++)
f(Vec2(rect.pos.X + rect.size.X - 1, y));
}
// Call f for every point on the dotted boundary of the indicated rectangle.
template<typename F>
void RasterizeDottedRect(Rect<int> rect, F f)
{
for (int x = rect.TopLeft.X; x <= rect.BottomRight.X; x += 2)
f(Vec2(x, rect.TopLeft.Y));
for (int x = rect.pos.X; x < rect.pos.X + rect.size.X; x += 2)
f(Vec2(x, rect.pos.Y));
int bottomOff = (rect.BottomRight.Y - rect.TopLeft.Y) % 2;
if (rect.TopLeft.Y != rect.BottomRight.Y)
for (int x = rect.TopLeft.X + bottomOff; x <= rect.BottomRight.X; x += 2)
f(Vec2(x, rect.BottomRight.Y));
int bottomOff = (rect.pos.Y + rect.size.Y - 1 - rect.pos.Y) % 2;
if (rect.pos.Y != rect.pos.Y + rect.size.Y - 1)
for (int x = rect.pos.X + bottomOff; x < rect.pos.X + rect.size.X; x += 2)
f(Vec2(x, rect.pos.Y + rect.size.Y - 1));
// corners already drawn
for (int y = rect.TopLeft.Y + 1 + 1; y <= rect.BottomRight.Y - 1; y += 2)
f(Vec2(rect.TopLeft.X, y));
for (int y = rect.pos.Y + 1 + 1; y < rect.pos.Y + rect.size.Y - 1; y += 2)
f(Vec2(rect.pos.X, y));
int leftOff = (rect.BottomRight.X - rect.TopLeft.X + 1) % 2;
if (rect.TopLeft.X != rect.BottomRight.X)
for (int y = rect.TopLeft.Y + 1 + leftOff; y <= rect.BottomRight.Y - 1; y += 2)
f(Vec2(rect.BottomRight.X, y));
int leftOff = (rect.pos.X + rect.size.X - 1 - rect.pos.X + 1) % 2;
if (rect.pos.X != rect.pos.X + rect.size.X - 1)
for (int y = rect.pos.Y + 1 + leftOff; y < rect.pos.Y + rect.size.Y - 1; y += 2)
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
{
return Vec2<T>(
std::clamp(X, rect.TopLeft.X, rect.BottomRight.X),
std::clamp(Y, rect.TopLeft.Y, rect.BottomRight.Y)
std::clamp(X, rect.pos.X, rect.pos.X + rect.size.X - T(1)),
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>
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>>>
constexpr static inline Rect<T> RectBetween(Vec2<T>, Vec2<T>);
template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
constexpr static inline Rect<T> RectSized(Vec2<T>, Vec2<T>);
enum IterationDirection
{
@ -200,16 +200,15 @@ template<typename T, typename>
struct Rect
{
// Inclusive
Vec2<T> TopLeft, BottomRight;
Vec2<T> pos, size;
private:
constexpr Rect(Vec2<T> topLeft, Vec2<T> bottomRight):
TopLeft(topLeft),
BottomRight(bottomRight)
constexpr Rect(Vec2<T> newPos, Vec2<T> newSize):
pos(newPos),
size(newSize)
{
}
friend constexpr Rect<T> RectBetween<T>(Vec2<T>, Vec2<T>);
private:
struct end_sentinel
{};
@ -350,48 +349,25 @@ private:
public:
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
{
return TopLeft != other.TopLeft || BottomRight != other.BottomRight;
return pos != other.pos || size != other.size;
}
constexpr explicit operator bool() const
{
return BottomRight.X >= TopLeft.X && BottomRight.Y >= TopLeft.Y;
}
// 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 size.X > 0 && size.Y > 0;
}
// Return the intersection of two rectangles (possibly empty)
Rect<T> operator&(Rect<T> other) const
{
auto rect = Rect<T>(
Vec2<T>(std::max(TopLeft.X, other.TopLeft.X), std::max(TopLeft.Y, other.TopLeft.Y)),
Vec2<T>(std::min(BottomRight.X, other.BottomRight.X), std::min(BottomRight.Y, other.BottomRight.Y))
);
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;
auto tl = Vec2<T>(std::max(pos.X , other.pos.X ), std::max(pos.Y , other.pos.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));
return Rect<T>(tl, br1 - tl);
}
inline Rect<T> &operator&=(Rect<T> other)
@ -401,19 +377,13 @@ public:
constexpr bool Contains(Vec2<T> point) const
{
return point.X >= TopLeft.X && point.X <= BottomRight.X && point.Y >= TopLeft.Y && point.Y <= BottomRight.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);
return point.X >= pos.X && point.X < pos.X + size.X && point.Y >= pos.Y && point.Y < pos.Y + size.Y;
}
template<typename S>
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>>>
@ -426,10 +396,10 @@ public:
);
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
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
@ -445,19 +415,19 @@ public:
};
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)
{
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>>>
constexpr inline Rect<T> RectAt(Vec2<T> pos)
{
return RectBetween<T>(pos, pos);
}
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));
return RectSized(pos, Vec2<T>(1, 1));
}

View File

@ -36,10 +36,10 @@ void VideoBuffer::Crop(Rect<int> rect)
if (rect == Size().OriginRect())
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++)
std::copy_n(
video.RowIterator(rect.TopLeft + Vec2(0, y)),
video.RowIterator(rect.pos + Vec2(0, y)),
newVideo.Size().X,
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();
auto &video = static_cast<Derived &>(*this).video;
if (rect)
for (int y = rect.TopLeft.Y; y <= rect.BottomRight.Y; y++)
std::fill_n(video.RowIterator(Vec2(rect.TopLeft.X, y)), rect.Size().X, packed);
for (int y = rect.pos.Y; y < rect.pos.Y + rect.size.Y; y++)
std::fill_n(video.RowIterator(Vec2(rect.pos.X, y)), rect.size.X, packed);
}
template<typename Derived>
@ -166,22 +166,22 @@ void RasterDrawMethods<Derived>::BlendFilledEllipse(Vec2<int> center, Vec2<int>
template<typename Derived>
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>
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();
if (alpha == 0xFF)
{
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(
data + (rect.TopLeft.X - origin.X) + (y - origin.Y) * rowStride,
rect.Size().X,
video.RowIterator(Vec2(rect.TopLeft.X, y))
data + (rect.pos.X - origin.X) + (y - origin.Y) * rowStride,
rect.size.X,
video.RowIterator(Vec2(rect.pos.X, y))
);
}
else
@ -197,13 +197,13 @@ void RasterDrawMethods<Derived>::BlendImage(pixel const *data, uint8_t alpha, Re
template<typename Derived>
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>
void RasterDrawMethods<Derived>::XorImage(unsigned char const *data, Rect<int> rect, size_t rowStride)
{
auto origin = rect.TopLeft;
auto origin = rect.pos;
rect &= clipRect();
for (auto pos : rect)
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>
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>
void RasterDrawMethods<Derived>::BlendRGBAImage(pixel_rgba const *data, Rect<int> rect, size_t rowStride)
{
auto origin = rect.TopLeft;
auto origin = rect.pos;
rect &= clipRect();
for (auto pos : rect)
{

View File

@ -50,7 +50,7 @@ void ToolButton::Draw(const ui::Point& screenPos)
{
Graphics * g = GetGraphics();
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
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));
}
if (ClipRect.Size().X && ClipRect.Size().Y)
if (ClipRect.size.X && ClipRect.size.Y)
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
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);
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 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);
if (bgColour.Alpha)
{
@ -58,18 +58,18 @@ void ProgressBar::Draw(const Point &screenPos)
}, progressStatus, textColour);
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)
{
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));
pos -= inner.Size().X;
pos -= inner.size.X;
drawContent(pos, pos + size, style::Colour::WarningTitle, 0x000000_rgb .WithAlpha(255));
}
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);
if (AllowExclusiveDrawing || bool(rect & GetGraphics()->Size().OriginRect()))
child->Draw(rect.TopLeft);
child->Draw(rect.pos);
}
};
for (auto child : Components)

View File

@ -261,10 +261,10 @@ static int setClipRect(lua_State *L)
int h = luaL_optinteger(L, 4, WINDOWH);
auto rect = RectSized(Vec2(x, y), Vec2(w, h));
lsi->g->SwapClipRect(rect);
lua_pushinteger(L, rect.TopLeft.X);
lua_pushinteger(L, rect.TopLeft.Y);
lua_pushinteger(L, rect.Size().X);
lua_pushinteger(L, rect.Size().Y);
lua_pushinteger(L, rect.pos.X);
lua_pushinteger(L, rect.pos.Y);
lua_pushinteger(L, rect.size.X);
lua_pushinteger(L, rect.size.Y);
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)
{
auto intersection = RES.OriginRect() & RectSized(Vec2{ area_x, area_y }, Vec2{ area_w, area_h });
area_x = intersection.TopLeft.X;
area_y = intersection.TopLeft.Y;
area_w = intersection.Size().X;
area_h = intersection.Size().Y;
area_x = intersection.pos.X;
area_y = intersection.pos.Y;
area_w = intersection.size.X;
area_h = intersection.size.Y;
float fx = area_x-.5f, fy = area_y-.5f;
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) {
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
for (auto it = existingParticles.begin(); it != existingParticles.end(); ++it)
{
if (lastPos != it->pos)
{
existingParticleIndices[it->pos - pasteArea.TopLeft] = it - existingParticles.begin();
existingParticleIndices[it->pos - pasteArea.pos] = it - existingParticles.begin();
lastPos = it->pos;
}
}
}
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))
{
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
{
auto blockR = RectBetween(partR.TopLeft / CELL, partR.BottomRight / CELL);
auto blockP = blockR.TopLeft;
auto blockR = RectSized(partR.pos / CELL, partR.size / CELL);
auto blockP = blockR.pos;
auto newSave = std::make_unique<GameSave>(blockR.Size());
auto newSave = std::make_unique<GameSave>(blockR.size);
newSave->frameCount = frameCount;
newSave->rngState = rng.state();