Add clip rect feature to Graphics and gfx.setClipRect

Also retire the separate VideoBuffer in Panel and hiding ToolButtons in the GameView ToolButton panel in favour of clip rects.
This commit is contained in:
Tamás Bálint Misius 2022-10-11 20:24:11 +02:00
parent f18bd6553f
commit 715333295b
No account linked to committer's email address
12 changed files with 127 additions and 33 deletions

View File

@ -1081,3 +1081,23 @@ VideoBuffer Graphics::DumpFrame()
std::copy(vid, vid+(WINDOWW*WINDOWH), newBuffer.Buffer); std::copy(vid, vid+(WINDOWW*WINDOWH), newBuffer.Buffer);
return newBuffer; return newBuffer;
} }
void Graphics::SetClipRect(int &x, int &y, int &w, int &h)
{
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;
}

View File

@ -70,6 +70,11 @@ public:
class Graphics class Graphics
{ {
int clipx1 = 0;
int clipy1 = 0;
int clipx2 = WINDOWW;
int clipy2 = WINDOWH;
public: public:
pixel *vid; pixel *vid;
int sdl_scale; int sdl_scale;
@ -122,13 +127,14 @@ public:
void clearrect(int x, int y, int width, int height); void clearrect(int x, int y, int width, int height);
void gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2); void gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2);
void draw_image(pixel *img, int x, int y, int w, int h, int a); void draw_image(const pixel *img, int x, int y, int w, int h, int a);
void draw_image(const VideoBuffer & vidBuf, int x, int y, int a); void draw_image(const VideoBuffer * vidBuf, int x, int y, int a);
void draw_image(VideoBuffer * vidBuf, int x, int y, int a);
void draw_rgba_image(const unsigned char *data, int x, int y, float alpha); void draw_rgba_image(const unsigned char *data, int x, int y, float alpha);
Graphics(); Graphics();
~Graphics(); ~Graphics();
void SetClipRect(int &x, int &y, int &w, int &h);
}; };
#endif #endif

View File

@ -104,7 +104,11 @@ int PIXELMETHODS_CLASS::addchar(int x, int y, String::value_type c, int r, int g
TPT_INLINE void PIXELMETHODS_CLASS::xor_pixel(int x, int y) TPT_INLINE void PIXELMETHODS_CLASS::xor_pixel(int x, int y)
{ {
int c; int c;
if (x<0 || y<0 || x>=XRES || y>=YRES) #ifdef DO_CLIPCHECK
if (x<clipx1 || y<clipy1 || x>=clipx2 || y>=clipy2)
#else
if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES)
#endif
return; return;
c = vid[y*(VIDXRES)+x]; c = vid[y*(VIDXRES)+x];
c = PIXB(c) + 3*PIXG(c) + 2*PIXR(c); c = PIXB(c) + 3*PIXG(c) + 2*PIXR(c);
@ -117,7 +121,11 @@ TPT_INLINE void PIXELMETHODS_CLASS::xor_pixel(int x, int y)
void PIXELMETHODS_CLASS::blendpixel(int x, int y, int r, int g, int b, int a) void PIXELMETHODS_CLASS::blendpixel(int x, int y, int r, int g, int b, int a)
{ {
pixel t; pixel t;
#ifdef DO_CLIPCHECK
if (x<clipx1 || y<clipy1 || x>=clipx2 || y>=clipy2)
#else
if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES) if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES)
#endif
return; return;
if (a!=255) if (a!=255)
{ {
@ -132,7 +140,11 @@ void PIXELMETHODS_CLASS::blendpixel(int x, int y, int r, int g, int b, int a)
void PIXELMETHODS_CLASS::addpixel(int x, int y, int r, int g, int b, int a) void PIXELMETHODS_CLASS::addpixel(int x, int y, int r, int g, int b, int a)
{ {
pixel t; pixel t;
#ifdef DO_CLIPCHECK
if (x<clipx1 || y<clipy1 || x>=clipx2 || y>=clipy2)
#else
if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES) if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES)
#endif
return; return;
t = vid[y*(VIDXRES)+x]; t = vid[y*(VIDXRES)+x];
r = (a*r + 255*PIXR(t)) >> 8; r = (a*r + 255*PIXR(t)) >> 8;
@ -376,6 +388,20 @@ void PIXELMETHODS_CLASS::clearrect(int x, int y, int w, int h)
w -= 1; w -= 1;
h -= 1; 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;
}
#else
if (x+w > VIDXRES) w = VIDXRES-x; if (x+w > VIDXRES) w = VIDXRES-x;
if (y+h > VIDYRES) h = VIDYRES-y; if (y+h > VIDYRES) h = VIDYRES-y;
if (x<0) if (x<0)
@ -388,6 +414,7 @@ void PIXELMETHODS_CLASS::clearrect(int x, int y, int w, int h)
h += y; h += y;
y = 0; y = 0;
} }
#endif
if (w<0 || h<0) if (w<0 || h<0)
return; return;
@ -395,7 +422,7 @@ void PIXELMETHODS_CLASS::clearrect(int x, int y, int w, int h)
memset(vid+(x+(VIDXRES)*(y+i)), 0, PIXELSIZE*w); memset(vid+(x+(VIDXRES)*(y+i)), 0, PIXELSIZE*w);
} }
void PIXELMETHODS_CLASS::draw_image(pixel *img, int x, int y, int w, int h, int a) void PIXELMETHODS_CLASS::draw_image(const pixel *img, int x, int y, int w, int h, int a)
{ {
int startX = 0; int startX = 0;
if (!img) if (!img)
@ -428,6 +455,9 @@ void PIXELMETHODS_CLASS::draw_image(pixel *img, int x, int y, int w, int h, int
img += startX; img += startX;
for (int i = startX; i < w; i++) for (int i = startX; i < w; i++)
{ {
#ifdef DO_CLIPCHECK
if (!(x+i<clipx1 || y+j<clipy1 || x+i>=clipx2 || y+j>=clipy2))
#endif
vid[(y+j)*(VIDXRES)+(x+i)] = *img; vid[(y+j)*(VIDXRES)+(x+i)] = *img;
img++; img++;
} }
@ -450,12 +480,7 @@ void PIXELMETHODS_CLASS::draw_image(pixel *img, int x, int y, int w, int h, int
} }
} }
void PIXELMETHODS_CLASS::draw_image(const VideoBuffer & vidBuf, int x, int y, int a) void PIXELMETHODS_CLASS::draw_image(const VideoBuffer * vidBuf, int x, int y, int a)
{
draw_image(vidBuf.Buffer, x, y, vidBuf.Width, vidBuf.Height, a);
}
void PIXELMETHODS_CLASS::draw_image(VideoBuffer * vidBuf, int x, int y, int a)
{ {
draw_image(vidBuf->Buffer, x, y, vidBuf->Width, vidBuf->Height, a); draw_image(vidBuf->Buffer, x, y, vidBuf->Width, vidBuf->Height, a);
} }

View File

@ -28,6 +28,7 @@ void Graphics::Finalise()
#define VIDXRES WINDOWW #define VIDXRES WINDOWW
#define VIDYRES WINDOWH #define VIDYRES WINDOWH
#define PIXELMETHODS_CLASS Graphics #define PIXELMETHODS_CLASS Graphics
#define DO_CLIPCHECK
#include "RasterDrawMethods.inl" #include "RasterDrawMethods.inl"
#undef VIDYRES #undef VIDYRES
#undef VIDXRES #undef VIDXRES

View File

@ -120,9 +120,8 @@ public:
void clearrect(int x, int y, int width, int height); void clearrect(int x, int y, int width, int height);
void gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2); void gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2);
void draw_image(pixel *img, int x, int y, int w, int h, int a); void draw_image(const pixel *img, int x, int y, int w, int h, int a);
void draw_image(const VideoBuffer & vidBuf, int w, int h, int a); void draw_image(const VideoBuffer * vidBuf, int w, int h, int a);
void draw_image(VideoBuffer * vidBuf, int w, int h, int a);
VideoBuffer DumpFrame(); VideoBuffer DumpFrame();

View File

@ -576,6 +576,11 @@ void GameView::NotifyToolListChanged(GameModel * sender)
else else
tempButton = new ToolButton(ui::Point(currentX, YRES+1), ui::Point(30, 18), tool->GetName(), tool->GetIdentifier(), tool->GetDescription()); 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;
//currentY -= 17; //currentY -= 17;
currentX -= 31; currentX -= 31;
tempButton->tool = tool; tempButton->tool = tool;
@ -1014,10 +1019,6 @@ void GameView::updateToolButtonScroll()
for (auto *button : toolButtons) for (auto *button : toolButtons)
{ {
button->Position.X -= offsetDelta; button->Position.X -= offsetDelta;
if (button->Position.X + button->Size.X <= 0 || (button->Position.X + button->Size.X) > XRES - 2)
button->Visible = false;
else
button->Visible = true;
} }
// Ensure that mouseLeave events are make their way to the buttons should they move from underneath the mouse pointer // Ensure that mouseLeave events are make their way to the buttons should they move from underneath the mouse pointer
@ -1803,7 +1804,24 @@ void GameView::DoExit()
void GameView::DoDraw() void GameView::DoDraw()
{ {
Window::DoDraw(); Window::DoDraw();
constexpr std::array<int, 9> fadeout = { { // * Gamma-corrected.
255, 195, 145, 103, 69, 42, 23, 10, 3
} };
auto *g = GetGraphics();
for (auto x = 0U; x < fadeout.size(); ++x)
{
g->draw_line(x, YRES + 1, x, YRES + 18, 0, 0, 0, fadeout[x]);
g->draw_line(XRES - x, YRES + 1, XRES - x, YRES + 18, 0, 0, 0, fadeout[x]);
}
c->Tick(); 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
}
} }
void GameView::NotifyNotificationsChanged(GameModel * sender) void GameView::NotifyNotificationsChanged(GameModel * sender)

View File

@ -49,6 +49,14 @@ void ToolButton::OnMouseUp(int x, int y, unsigned int button)
void ToolButton::Draw(const ui::Point& screenPos) void ToolButton::Draw(const ui::Point& screenPos)
{ {
Graphics * g = GetGraphics(); Graphics * g = GetGraphics();
int x = clipRectX;
int y = clipRectY;
int w = clipRectW;
int h = clipRectH;
if (clipRectW && clipRectH)
{
g->SetClipRect(x, y, w, h); // old cliprect is now in x, y, w, h
}
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);
if (Appearance.GetTexture()) if (Appearance.GetTexture())
@ -81,6 +89,10 @@ void ToolButton::Draw(const ui::Point& screenPos)
{ {
g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, buttonDisplayText, 0, 0, 0, 255); g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, buttonDisplayText, 0, 0, 0, 255);
} }
if (clipRectW && clipRectH)
{
g->SetClipRect(x, y, w, h); // apply old clip rect
}
} }
void ToolButton::SetSelectionState(int state) void ToolButton::SetSelectionState(int state)

View File

@ -18,6 +18,10 @@ public:
void SetSelectionState(int state); void SetSelectionState(int state);
int GetSelectionState(); int GetSelectionState();
Tool *tool; Tool *tool;
int clipRectX = 0;
int clipRectY = 0;
int clipRectW = 0;
int clipRectH = 0;
}; };
#endif /* TOOLBUTTON_H_ */ #endif /* TOOLBUTTON_H_ */

View File

@ -13,7 +13,6 @@ Panel::Panel(Point position, Point size):
ViewportPosition(0, 0), ViewportPosition(0, 0),
mouseInside(false) mouseInside(false)
{ {
myVid = new pixel[WINDOWW*WINDOWH];
} }
Panel::~Panel() Panel::~Panel()
@ -22,7 +21,6 @@ Panel::~Panel()
{ {
delete children[i]; delete children[i];
} }
delete[] myVid;
} }
void Panel::AddChild(Component* c) void Panel::AddChild(Component* c)
@ -66,12 +64,14 @@ void Panel::RemoveChild(unsigned idx, bool freeMem)
void Panel::Draw(const Point& screenPos) void Panel::Draw(const Point& screenPos)
{ {
// draw ourself first // draw ourself first
XDraw(screenPos); XDraw(screenPos);
pixel * lastVid = ui::Engine::Ref().g->vid;
ui::Engine::Ref().g->vid = myVid; int x = screenPos.X;
std::fill(myVid, myVid+(WINDOWW*WINDOWH), 0); 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
// attempt to draw all children // attempt to draw all children
for (size_t i = 0; i < children.size(); ++i) for (size_t i = 0; i < children.size(); ++i)
@ -85,19 +85,13 @@ void Panel::Draw(const Point& screenPos)
children[i]->Position.X + ViewportPosition.X < ui::Engine::Ref().GetWidth() && children[i]->Position.X + ViewportPosition.X < ui::Engine::Ref().GetWidth() &&
children[i]->Position.Y + ViewportPosition.Y < ui::Engine::Ref().GetHeight() ) children[i]->Position.Y + ViewportPosition.Y < ui::Engine::Ref().GetHeight() )
{ {
Point scrpos = /*screenPos + */children[i]->Position + ViewportPosition; Point scrpos = screenPos + children[i]->Position + ViewportPosition;
children[i]->Draw(scrpos); children[i]->Draw(scrpos);
} }
} }
} }
ui::Engine::Ref().g->vid = lastVid; ui::Engine::Ref().g->SetClipRect(x, y, w, h); // apply old cliprect
//dst=(pixel *)sdl_scrn->pixels+y*sdl_scrn->pitch/PIXELSIZE+x;
for (int row = 0; row < Size.Y; row++)
{
std::copy(myVid+(row*WINDOWW), myVid+(row*WINDOWW)+Size.X, lastVid+((screenPos.Y+row)*WINDOWW)+screenPos.X);
}
} }
void Panel::Tick(float dt) void Panel::Tick(float dt)

View File

@ -22,7 +22,6 @@ class Component;
public: public:
friend class Component; friend class Component;
pixel * myVid;
ui::Point InnerSize; ui::Point InnerSize;
ui::Point ViewportPosition; ui::Point ViewportPosition;

View File

@ -3579,6 +3579,7 @@ void LuaScriptInterface::initGraphicsAPI()
{"fillCircle", graphics_fillCircle}, {"fillCircle", graphics_fillCircle},
{"getColors", graphics_getColors}, {"getColors", graphics_getColors},
{"getHexColor", graphics_getHexColor}, {"getHexColor", graphics_getHexColor},
{"setClipRect", graphics_setClipRect},
{NULL, NULL} {NULL, NULL}
}; };
luaL_register(l, "graphics", graphicsAPIMethods); luaL_register(l, "graphics", graphicsAPIMethods);
@ -3775,6 +3776,20 @@ int LuaScriptInterface::graphics_getHexColor(lua_State * l)
return 1; return 1;
} }
int LuaScriptInterface::graphics_setClipRect(lua_State * l)
{
int x = luaL_optinteger(l, 1, 0);
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);
return 4;
}
void LuaScriptInterface::initFileSystemAPI() void LuaScriptInterface::initFileSystemAPI()
{ {
//Methods //Methods

View File

@ -167,6 +167,7 @@ class LuaScriptInterface: public CommandInterface
static int graphics_fillCircle(lua_State * l); static int graphics_fillCircle(lua_State * l);
static int graphics_getColors(lua_State * l); static int graphics_getColors(lua_State * l);
static int graphics_getHexColor(lua_State * l); static int graphics_getHexColor(lua_State * l);
static int graphics_setClipRect(lua_State * l);
void initFileSystemAPI(); void initFileSystemAPI();
static int fileSystem_list(lua_State * l); static int fileSystem_list(lua_State * l);