Refactor rect clipping

This commit is contained in:
mniip 2023-02-19 22:58:12 +01:00
parent 31abb8a48f
commit 7d9fdfea4e
16 changed files with 105 additions and 130 deletions

View File

@ -9,21 +9,23 @@ constexpr float M_GRAV = 6.67300e-1f;
//CELL, the size of the pressure, gravity, and wall maps. Larger than 1 to prevent extreme lag
constexpr int CELL = 4;
constexpr int XCELLS = 153;
constexpr int YCELLS = 96;
constexpr auto CELLS = Vec2<int>(153, 96);
constexpr int XCELLS = CELLS.X;
constexpr int YCELLS = CELLS.Y;
constexpr int NCELL = XCELLS * YCELLS;
constexpr Rect<int> CELLS = Rect<int>(Vec2<int>(0, 0), Vec2<int>(XCELLS - 1, YCELLS - 1));
constexpr int XRES = XCELLS * CELL;
constexpr int YRES = YCELLS * CELL;
constexpr auto RES = CELLS * CELL;
constexpr int XRES = RES.X;
constexpr int YRES = RES.Y;
constexpr int NPART = XRES * YRES;
constexpr Rect<int> RES = Rect<int>(Vec2<int>(0, 0), Vec2<int>(XRES - 1, YRES - 1));
constexpr int XCNTR = XRES / 2;
constexpr int YCNTR = YRES / 2;
constexpr int WINDOWW = XRES + BARSIZE;
constexpr int WINDOWH = YRES + MENUSIZE;
constexpr Rect<int> WINDOW = Rect<int>(Vec2<int>(0, 0), Vec2<int>(WINDOWW - 1, WINDOWH - 1));
constexpr auto WINDOW = RES + Vec2<int>(BARSIZE, MENUSIZE);
constexpr int WINDOWW = WINDOW.X;
constexpr int WINDOWH = WINDOW.Y;
constexpr int MAXSIGNS = 16;

View File

@ -122,16 +122,16 @@ inline Vec2<int> lroundNegInf(Vec2<float> v)
Vec2<int> GameSave::Translate(Vec2<int> translate)
{
auto bounds = Rect<float>(Vec2<float>::Zero);
auto bounds = RectAt(Vec2<float>::Zero);
// determine minimum and maximum position of all particles / signs
for (auto &sign : signs)
bounds |= Rect<float>(roundNegInf(Vec2<float>(sign.x, sign.y) + translate));
bounds |= RectAt(roundNegInf(Vec2<float>(sign.x, sign.y) + translate));
for (int i = 0; i < particlesCount; i++)
{
if (!particles[i].type) continue;
bounds |= Rect<float>(roundNegInf(Vec2<float>(particles[i].x, particles[i].y) + translate));
bounds |= RectAt(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<int>(
@ -171,12 +171,12 @@ void GameSave::Transform(Mat2<int> transform, Vec2<int> translate)
Vec2<int>(blockDimen.X * CELL - 1, blockDimen.Y * CELL - 1),
};
// undo any translation caused by rotation
auto bounds = Rect<int>(transform * cornerso[0]);
auto bounds = RectAt(transform * cornerso[0]);
for (int i = 1; i < 4; i++)
bounds |= Rect<int>(transform * cornerso[i]);
bounds |= RectAt(transform * cornerso[i]);
Vec2<int> translateReal = translate;
translate -= bounds.TopLeft;
auto newBounds = bounds.BottomRight - bounds.TopLeft + Vec2<int>(1, 1);
auto newBounds = bounds.Size();
Transform(transform, translate, translateReal, newBounds);
}
@ -204,7 +204,7 @@ void GameSave::Transform(Mat2<int> transform, Vec2<int> translate, Vec2<int> tra
bool patchPipeV = transform == Mat2<int>::MirrorY;
// rotate and translate signs, parts, walls
auto bounds = Rect<int>(Vec2<int>::Zero, newDimen - Vec2<int>(1, 1));
auto bounds = newDimen.OriginRect();
for (auto &sign : signs)
{
auto pos = transform * Vec2<int>(sign.x, sign.y) + translate;
@ -266,7 +266,7 @@ void GameSave::Transform(Mat2<int> transform, Vec2<int> translate, Vec2<int> tra
|| (translated.Y > 0 && (int)translated.Y%CELL == 0)))
blockTranslate.Y = -CELL;
auto blockBounds = Rect<int>(Vec2<int>::Zero, newBlockDimen - Vec2<int>(1, 1));
auto blockBounds = newBlockDimen.OriginRect();
for (int y=0; y<blockDimen.Y; y++)
for (int x=0; x<blockDimen.X; x++)
{

View File

@ -743,24 +743,11 @@ VideoBuffer Graphics::DumpFrame()
return newBuffer;
}
void Graphics::SetClipRect(int &x, int &y, int &w, int &h)
void Graphics::SetClipRect(Rect<int> &rect)
{
int newX = x;
int newY = y;
int newW = w;
int newH = h;
if (newX < 0) newX = 0;
if (newY < 0) newY = 0;
if (newW > WINDOWW - newX) newW = WINDOWW - newX;
if (newH > WINDOWH - newY) newH = WINDOWH - newY;
x = clipx1;
y = clipy1;
w = clipx2 - clipx1;
h = clipy2 - clipy1;
clipx1 = newX;
clipy1 = newY;
clipx2 = newX + newW;
clipy2 = newY + newH;
auto newRect = RectBetween(WINDOW.OriginRect().Clamp(rect.TopLeft), WINDOW.OriginRect().Clamp(rect.BottomRight));
rect = clip;
clip = newRect;
}
bool VideoBuffer::WritePNG(const ByteString &path) const

View File

@ -1,4 +1,5 @@
#pragma once
#include "common/Geometry.h"
#include "common/String.h"
#include "common/tpt-inline.h"
#include "Pixel.h"
@ -68,10 +69,7 @@ public:
class Graphics
{
int clipx1;
int clipy1;
int clipx2;
int clipy2;
Rect<int> clip;
public:
pixel *vid;
@ -131,7 +129,7 @@ public:
Graphics();
~Graphics();
void SetClipRect(int &x, int &y, int &w, int &h);
void SetClipRect(Rect<int> &);
};
bool PngDataToPixels(std::vector<pixel> &imageData, int &imgw, int &imgh, const char *pngData, size_t pngDataSize, bool addBackground);

View File

@ -1,6 +1,9 @@
#pragma once
#include <cstdint>
#include <limits>
#include <type_traits>
typedef unsigned int pixel;
typedef uint32_t pixel;
constexpr int PIXELCHANNELS = 3;
constexpr int PIXELSIZE = 4;
@ -24,3 +27,30 @@ constexpr int PIXB(pixel x)
{
return x & 0xFF;
}
template<typename T, typename = std::enable_if<std::is_arithmetic_v<T>, void>>
struct RGB
{
T Red, Green, Blue;
constexpr RGB(T r, T g, T b):
Red(r),
Green(g),
Blue(b)
{
}
};
template<typename T, typename = std::enable_if<std::is_arithmetic_v<T>, void>>
struct RGBA
{
T Red, Green, Blue, Alpha;
constexpr RGBA(T r, T g, T b, T a = std::numeric_limits<T>::max()):
Red(r),
Green(g),
Blue(b),
Alpha(a)
{
}
};

View File

@ -117,9 +117,9 @@ TPT_INLINE void PIXELMETHODS_CLASS::xor_pixel(int x, int y)
{
int c;
#ifdef DO_CLIPCHECK
if (x<clipx1 || y<clipy1 || x>=clipx2 || y>=clipy2)
if (!clip.Contains(Vec2<int>(x, y)))
#else
if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES)
if (!VIDRES.OriginRect().Contains(Vec2<int>(x, y)))
#endif
return;
c = vid[y*(VIDXRES)+x];
@ -134,9 +134,9 @@ void PIXELMETHODS_CLASS::blendpixel(int x, int y, int r, int g, int b, int a)
{
pixel t;
#ifdef DO_CLIPCHECK
if (x<clipx1 || y<clipy1 || x>=clipx2 || y>=clipy2)
if (!clip.Contains(Vec2<int>(x, y)))
#else
if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES)
if (!VIDRES.OriginRect().Contains(Vec2<int>(x, y)))
#endif
return;
if (a!=255)
@ -153,9 +153,9 @@ void PIXELMETHODS_CLASS::addpixel(int x, int y, int r, int g, int b, int a)
{
pixel t;
#ifdef DO_CLIPCHECK
if (x<clipx1 || y<clipy1 || x>=clipx2 || y>=clipy2)
if (!clip.Contains(Vec2<int>(x, y)))
#else
if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES)
if (!VIDRES.OriginRect().Contains(Vec2<int>(x, y)))
#endif
return;
t = vid[y*(VIDXRES)+x];
@ -401,32 +401,15 @@ void PIXELMETHODS_CLASS::clearrect(int x, int y, int w, int h)
h -= 1;
#ifdef DO_CLIPCHECK
if (x+w > clipx2) w = clipx2-x;
if (y+h > clipy2) h = clipy2-y;
if (x<clipx1)
{
w += x - clipx1;
x = clipx1;
}
if (y<clipy1)
{
h += y - clipy1;
y = clipy1;
}
auto rect = clip.Clamp(RectSized(Vec2<int>(x, y), Vec2<int>(w, h)));
#else
if (x+w > VIDXRES) w = VIDXRES-x;
if (y+h > VIDYRES) h = VIDYRES-y;
if (x<0)
{
w += x;
x = 0;
}
if (y<0)
{
h += y;
y = 0;
}
auto rect = VIDRES.OriginRect().Clamp(RectSized(Vec2<int>(x, y), Vec2<int>(w, h)));
#endif
x = rect.TopLeft.X;
y = rect.TopLeft.Y;
w = rect.Size().X;
h = rect.Size().Y;
if (w<0 || h<0)
return;
@ -468,9 +451,9 @@ void PIXELMETHODS_CLASS::draw_image(const pixel *img, int x, int y, int w, int h
for (int i = startX; i < w; i++)
{
#ifdef DO_CLIPCHECK
if (!(x+i<clipx1 || y+j<clipy1 || x+i>=clipx2 || y+j>=clipy2))
if (clip.Contains(Vec2<int>(x + i, y + j)))
#endif
vid[(y+j)*(VIDXRES)+(x+i)] = *img;
vid[(y+j)*(VIDXRES)+(x+i)] = *img;
img++;
}
}

View File

@ -4,10 +4,7 @@
#include <cstring>
Graphics::Graphics():
clipx1(0),
clipy1(0),
clipx2(WINDOWW),
clipy2(WINDOWH),
clip(WINDOW.OriginRect()),
sdl_scale(1)
{
vid = (pixel *)malloc(PIXELSIZE * (WINDOWW * WINDOWH));

View File

@ -5,8 +5,9 @@
#include "simulation/ElementClasses.h"
#include <cmath>
constexpr auto VIDXRES = WINDOWW;
constexpr auto VIDYRES = WINDOWH;
constexpr auto VIDRES = WINDOW;
constexpr auto VIDXRES = VIDRES.X;
constexpr auto VIDYRES = VIDRES.Y;
void Renderer::RenderBegin()
{

View File

@ -36,10 +36,12 @@ public:
};
GOLWindow::GOLWindow(GameModel * gameModel_, Simulation *sim_, int toolSelection, int rule, int colour1, int colour2):
ui::Window(ui::Point(-1, -1), ui::Point(200, 108)),
gameModel(gameModel_),
sim(sim_),
toolSelection(toolSelection)
ui::Window(ui::Point(-1, -1), ui::Point(200, 108)),
highColour(0, 0, 0, 0),
lowColour(0, 0, 0, 0),
gameModel(gameModel_),
sim(sim_),
toolSelection(toolSelection)
{
ui::Label * messageLabel = new ui::Label(ui::Point(4, 5), ui::Point(Size.X-8, 14), "Edit custom GOL type");
messageLabel->SetTextColour(style::Colour::InformationTitle);

View File

@ -575,10 +575,7 @@ void GameView::NotifyToolListChanged(GameModel * sender)
else
tempButton = new ToolButton(ui::Point(currentX, YRES+1), ui::Point(30, 18), tool->GetName(), tool->GetIdentifier(), tool->GetDescription());
tempButton->clipRectX = 1;
tempButton->clipRectY = YRES + 1;
tempButton->clipRectW = XRES - 1;
tempButton->clipRectH = 18;
tempButton->clip = RectBetween(Vec2<int>(1, YRES + 1), Vec2<int>(XRES - 1, YRES + 18));
//currentY -= 17;
currentX -= 31;
@ -1859,11 +1856,8 @@ void GameView::DoDraw()
c->Tick();
{
int x = 0;
int y = 0;
int w = WINDOWW;
int h = WINDOWH;
g->SetClipRect(x, y, w, h); // reset any nonsense cliprect Lua left configured
auto rect = WINDOW.OriginRect();
g->SetClipRect(rect); // reset any nonsense cliprect Lua left configured
}
}

View File

@ -45,13 +45,10 @@ void ToolButton::OnMouseUp(int x, int y, unsigned int button)
void ToolButton::Draw(const ui::Point& screenPos)
{
Graphics * g = GetGraphics();
int x = clipRectX;
int y = clipRectY;
int w = clipRectW;
int h = clipRectH;
if (clipRectW && clipRectH)
auto rect = clip;
if (rect)
{
g->SetClipRect(x, y, w, h); // old cliprect is now in x, y, w, h
g->SetClipRect(*rect); // old cliprect is now in rect
}
int totalColour = Appearance.BackgroundInactive.Blue + (3*Appearance.BackgroundInactive.Green) + (2*Appearance.BackgroundInactive.Red);
@ -85,9 +82,9 @@ void ToolButton::Draw(const ui::Point& screenPos)
{
g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, buttonDisplayText, 0, 0, 0, 255);
}
if (clipRectW && clipRectH)
if (rect)
{
g->SetClipRect(x, y, w, h); // apply old clip rect
g->SetClipRect(*rect); // apply old clip rect
}
}

View File

@ -1,5 +1,6 @@
#pragma once
#include "gui/interface/Button.h"
#include <optional>
class Tool;
@ -16,8 +17,5 @@ public:
void SetSelectionState(int state);
int GetSelectionState();
Tool *tool;
int clipRectX = 0;
int clipRectY = 0;
int clipRectW = 0;
int clipRectH = 0;
std::optional<Rect<int>> clip = std::nullopt;
};

View File

@ -23,6 +23,7 @@ namespace ui
BorderHover(255, 255, 255),
BorderInactive(200, 200, 200),
BorderActive(235, 235, 235),
BorderFavorite(255, 255, 0),
BorderDisabled(100, 100, 100),
Margin(1, 4),

View File

@ -1,21 +1,8 @@
#pragma once
#include "graphics/Pixel.h"
#include <cstdint>
namespace ui
{
class Colour
{
public:
unsigned char Red, Green, Blue, Alpha;
Colour(unsigned char red, unsigned char green, unsigned char blue):
Red(red), Green(green), Blue(blue), Alpha(255)
{
}
Colour(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha):
Red(red), Green(green), Blue(blue), Alpha(alpha)
{
}
Colour()
{
}
};
using Colour = RGBA<uint8_t>;
}

View File

@ -67,11 +67,8 @@ void Panel::Draw(const Point& screenPos)
// draw ourself first
XDraw(screenPos);
int x = screenPos.X;
int y = screenPos.Y;
int w = Size.X;
int h = Size.Y;
ui::Engine::Ref().g->SetClipRect(x, y, w, h); // old cliprect is now in x, y, w, h
auto rect = RectSized(screenPos, Size);
ui::Engine::Ref().g->SetClipRect(rect); // old cliprect is now in rect
// attempt to draw all children
for (size_t i = 0; i < children.size(); ++i)
@ -91,7 +88,7 @@ void Panel::Draw(const Point& screenPos)
}
}
ui::Engine::Ref().g->SetClipRect(x, y, w, h); // apply old cliprect
ui::Engine::Ref().g->SetClipRect(rect); // apply old cliprect
}
void Panel::Tick(float dt)

View File

@ -3901,11 +3901,12 @@ int LuaScriptInterface::graphics_setClipRect(lua_State * l)
int y = luaL_optinteger(l, 2, 0);
int w = luaL_optinteger(l, 3, WINDOWW);
int h = luaL_optinteger(l, 4, WINDOWH);
luacon_g->SetClipRect(x, y, w, h);
lua_pushinteger(l, x);
lua_pushinteger(l, y);
lua_pushinteger(l, w);
lua_pushinteger(l, h);
auto rect = RectSized(Vec2<int>(x, y), Vec2<int>(w, h));
luacon_g->SetClipRect(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);
return 4;
}