graphics: improve setScissor's handling of fractional DPI-scaled coordinates.

This commit is contained in:
Sasha Szpakowski
2026-06-21 14:58:22 -03:00
parent 3eedfb6e1e
commit 142ce87335
11 changed files with 64 additions and 53 deletions
+11
View File
@@ -72,6 +72,17 @@ struct Rect
}
};
struct FRect
{
float x, y;
float w, h;
bool operator == (const FRect &rhs) const
{
return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;
}
};
inline int nextP2(int x)
{
x += (x == 0);
+6 -6
View File
@@ -107,27 +107,27 @@ void Deprecations::draw(Graphics *gfx)
strings.push_back({"\n(And " + std::to_string(remaining) + " more)", white});
int padding = 5;
int width = 600;
float width = 600;
for (const auto &coloredstr : strings)
width = std::max(width, font->getWidth(coloredstr.str) + padding * 2);
width = std::max(width, (float)font->getWidth(coloredstr.str) + padding * 2);
float wraplimit = std::min(gfx->getWidth(), width - padding * 2);
float wraplimit = std::min((float)gfx->getWidth(), width - padding * 2);
std::vector<std::string> wrappedlines;
font->getWrap(strings, wraplimit, wrappedlines);
int linecount = std::min((int) wrappedlines.size(), maxcount);
int height = font->getHeight() * linecount + padding * 2;
float height = font->getHeight() * linecount + padding * 2;
int x = 0;
int y = std::max(gfx->getHeight() - height, 0);
int y = std::max(gfx->getHeight() - height, 0.0f);
gfx->setColor(Colorf(0, 0, 0, 0.85 * alpha));
gfx->rectangle(Graphics::DRAW_FILL, x, y, width, height);
gfx->setColor(Colorf(1, 0.9, 0.8, 1 * alpha));
gfx->setScissor({x, y, width, height});
gfx->setScissor({(float)x, (float)y, width, height});
Matrix4 textm(x + padding, y + padding, 0, 1, 1, 0, 0, 0, 0);
gfx->printf(strings, font.get(), wraplimit, Font::ALIGN_LEFT, textm);
+8 -8
View File
@@ -1489,9 +1489,9 @@ bool Graphics::findVertexAttributes(VertexAttributesID id, VertexAttributes &att
return true;
}
void Graphics::intersectScissor(const Rect &rect)
void Graphics::intersectScissor(const FRect &rect)
{
Rect currect = states.back().scissorRect;
FRect currect = states.back().scissorRect;
if (!states.back().scissor)
{
@@ -1501,17 +1501,17 @@ void Graphics::intersectScissor(const Rect &rect)
currect.h = std::numeric_limits<int>::max();
}
int x1 = std::max(currect.x, rect.x);
int y1 = std::max(currect.y, rect.y);
float x1 = std::max(currect.x, rect.x);
float y1 = std::max(currect.y, rect.y);
int x2 = std::min(currect.x + currect.w, rect.x + rect.w);
int y2 = std::min(currect.y + currect.h, rect.y + rect.h);
float x2 = std::min(currect.x + currect.w, rect.x + rect.w);
float y2 = std::min(currect.y + currect.h, rect.y + rect.h);
Rect newrect = {x1, y1, std::max(0, x2 - x1), std::max(0, y2 - y1)};
FRect newrect = {x1, y1, std::max(0.0f, x2 - x1), std::max(0.0f, y2 - y1)};
setScissor(newrect);
}
bool Graphics::getScissor(Rect &rect) const
bool Graphics::getScissor(FRect &rect) const
{
const DisplayState &state = states.back();
rect = state.scissorRect;
+4 -4
View File
@@ -619,8 +619,8 @@ public:
* and not drawn. Scissoring is automatically enabled.
* @param rect The rectangle defining the scissor area.
**/
virtual void setScissor(const Rect &rect) = 0;
void intersectScissor(const Rect &rect);
virtual void setScissor(const FRect &rect) = 0;
void intersectScissor(const FRect &rect);
/**
* Clears any scissor that has been created.
@@ -631,7 +631,7 @@ public:
* Gets the current scissor box.
* @return Whether the scissor is enabled.
*/
bool getScissor(Rect &rect) const;
bool getScissor(FRect &rect) const;
void setStencilMode(StencilMode mode, int value);
void setStencilMode();
@@ -966,7 +966,7 @@ protected:
float pointSize = 1.0f;
bool scissor = false;
Rect scissorRect = Rect();
FRect scissorRect = FRect();
StencilState stencil;
+1 -1
View File
@@ -88,7 +88,7 @@ public:
void setColor(Colorf c) override;
void setScissor(const Rect &rect) override;
void setScissor(const FRect &rect) override;
void setScissor() override;
void setStencilState(const StencilState &s) override;
+4 -4
View File
@@ -961,10 +961,10 @@ void Graphics::applyRenderState(id<MTLRenderCommandEncoder> encoder, VertexAttri
if (state.scissor)
{
double dpiscale = getCurrentDPIScale();
rect.x = (NSUInteger)(state.scissorRect.x*dpiscale);
rect.y = (NSUInteger)(state.scissorRect.y*dpiscale);
rect.width = (NSUInteger)(state.scissorRect.w*dpiscale);
rect.height = (NSUInteger)(state.scissorRect.h*dpiscale);
rect.x = (NSUInteger)roundf(state.scissorRect.x*dpiscale);
rect.y = (NSUInteger)roundf(state.scissorRect.y*dpiscale);
rect.width = (NSUInteger)roundf(state.scissorRect.w*dpiscale);
rect.height = (NSUInteger)roundf(state.scissorRect.h*dpiscale);
if (rtw > 0 && (int)rect.x >= rtw)
rect.x = rtw - 1;
+6 -6
View File
@@ -1306,7 +1306,7 @@ int Graphics::getBackbufferMSAA() const
return internalBackbuffer.get() ? internalBackbuffer->getMSAA() : 0;
}
void Graphics::setScissor(const Rect &rect, bool rtActive)
void Graphics::setScissor(const FRect &rect, bool rtActive)
{
flushBatchedDraws();
@@ -1318,10 +1318,10 @@ void Graphics::setScissor(const Rect &rect, bool rtActive)
double dpiscale = getCurrentDPIScale();
Rect glrect;
glrect.x = (int) (rect.x * dpiscale);
glrect.y = (int) (rect.y * dpiscale);
glrect.w = (int) (rect.w * dpiscale);
glrect.h = (int) (rect.h * dpiscale);
glrect.x = (int) roundf(rect.x * dpiscale);
glrect.y = (int) roundf(rect.y * dpiscale);
glrect.w = (int) roundf(rect.w * dpiscale);
glrect.h = (int) roundf(rect.h * dpiscale);
// OpenGL's reversed y-coordinate is compensated for in OpenGL::setScissor.
gl.setScissor(glrect, rtActive);
@@ -1330,7 +1330,7 @@ void Graphics::setScissor(const Rect &rect, bool rtActive)
state.scissorRect = rect;
}
void Graphics::setScissor(const Rect &rect)
void Graphics::setScissor(const FRect &rect)
{
setScissor(rect, isRenderTargetActive());
}
+2 -2
View File
@@ -84,7 +84,7 @@ public:
void setColor(Colorf c) override;
void setScissor(const Rect &rect) override;
void setScissor(const FRect &rect) override;
void setScissor() override;
void setStencilState(const StencilState &s) override;
@@ -154,7 +154,7 @@ private:
void setDebug(bool enable);
void setScissor(const Rect &rect, bool rtActive);
void setScissor(const FRect &rect, bool rtActive);
uint32 computePixelFormatUsage(PixelFormat format, bool readable);
+6 -6
View File
@@ -997,14 +997,14 @@ void Graphics::applyScissor()
if (states.back().scissor)
{
const Rect &rect = states.back().scissorRect;
const FRect &rect = states.back().scissorRect;
double dpiScale = getCurrentDPIScale();
int minScissorX = (int)(rect.x * dpiScale);
int minScissorY = (int)(rect.y * dpiScale);
int minScissorX = (int)roundf(rect.x * dpiScale);
int minScissorY = (int)roundf(rect.y * dpiScale);
int maxScissorX = minScissorX + (int)(rect.w * dpiScale) - 1;
int maxScissorY = minScissorY + (int)(rect.h * dpiScale) - 1;
int maxScissorX = minScissorX + (int)roundf(rect.w * dpiScale) - 1;
int maxScissorY = minScissorY + (int)roundf(rect.h * dpiScale) - 1;
// Avoid negative offsets.
int minX = std::max(scissor.offset.x, minScissorX);
@@ -1030,7 +1030,7 @@ void Graphics::applyScissor()
vkCmdSetScissor(commandBuffers.at(currentFrame), 0, 1, &scissor);
}
void Graphics::setScissor(const Rect &rect)
void Graphics::setScissor(const FRect &rect)
{
flushBatchedDraws();
+1 -1
View File
@@ -246,7 +246,7 @@ public:
void setActive(bool active) override;
int getBackbufferMSAA() const override;
void setColor(Colorf c) override;
void setScissor(const Rect &rect) override;
void setScissor(const FRect &rect) override;
void setScissor() override;
void setStencilState(const StencilState &s) override;
void setDepthMode(CompareMode compare, bool write) override;
+15 -15
View File
@@ -568,11 +568,11 @@ int w_setScissor(lua_State *L)
return 0;
}
Rect rect;
rect.x = (int) luaL_checkinteger(L, 1);
rect.y = (int) luaL_checkinteger(L, 2);
rect.w = (int) luaL_checkinteger(L, 3);
rect.h = (int) luaL_checkinteger(L, 4);
FRect rect;
rect.x = (float) luaL_checknumber(L, 1);
rect.y = (float) luaL_checknumber(L, 2);
rect.w = (float) luaL_checknumber(L, 3);
rect.h = (float) luaL_checknumber(L, 4);
if (rect.w < 0 || rect.h < 0)
return luaL_error(L, "Can't set scissor with negative width and/or height.");
@@ -583,11 +583,11 @@ int w_setScissor(lua_State *L)
int w_intersectScissor(lua_State *L)
{
Rect rect;
rect.x = (int) luaL_checkinteger(L, 1);
rect.y = (int) luaL_checkinteger(L, 2);
rect.w = (int) luaL_checkinteger(L, 3);
rect.h = (int) luaL_checkinteger(L, 4);
FRect rect;
rect.x = (float) luaL_checknumber(L, 1);
rect.y = (float) luaL_checknumber(L, 2);
rect.w = (float) luaL_checknumber(L, 3);
rect.h = (float) luaL_checknumber(L, 4);
if (rect.w < 0 || rect.h < 0)
return luaL_error(L, "Can't set scissor with negative width and/or height.");
@@ -598,14 +598,14 @@ int w_intersectScissor(lua_State *L)
int w_getScissor(lua_State *L)
{
Rect rect;
FRect rect;
if (!instance()->getScissor(rect))
return 0;
lua_pushinteger(L, rect.x);
lua_pushinteger(L, rect.y);
lua_pushinteger(L, rect.w);
lua_pushinteger(L, rect.h);
lua_pushnumber(L, rect.x);
lua_pushnumber(L, rect.y);
lua_pushnumber(L, rect.w);
lua_pushnumber(L, rect.h);
return 4;
}