mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-20 04:31:09 +02:00
Fix LÖVE 12 scissor seam
This commit is contained in:
committed by
Adrian Castro
parent
e61f231316
commit
84d09d0894
+21
-12
@@ -564,16 +564,24 @@ function Renderer:drawTiltedWorld(zoneList, sx, sy, wox, woy, target)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- LÖVE 11 truncates scissor arguments to framebuffer pixels; the half-pixel
|
||||||
|
-- bias keeps values divided back through a fractional DPI scale from landing
|
||||||
|
-- one short. LÖVE 12 passes fractional arguments through and rounds in the
|
||||||
|
-- graphics backend instead, where that bias shifts each origin by one pixel
|
||||||
|
-- and extends its far edge by two (#673).
|
||||||
|
local SCISSOR_PIXEL_BIAS = 0.5
|
||||||
|
if love and love.getVersion and select(1, love.getVersion()) >= 12 then
|
||||||
|
SCISSOR_PIXEL_BIAS = 0
|
||||||
|
end
|
||||||
|
|
||||||
-- Clamp a scissor rect to the viewport box, then round it outward to whole
|
-- Clamp a scissor rect to the viewport box, then round it outward to whole
|
||||||
-- framebuffer pixels. love.graphics.setScissor truncates x, y, w and h to
|
-- framebuffer pixels. On LÖVE 11, x, y, w and h are truncated independently,
|
||||||
-- pixels independently, so a rect with fractional unit edges (Android's
|
-- so a rect with fractional unit edges (Android's non-integer DPI puts
|
||||||
-- non-integer DPI puts fitScale/dpi in Sx/Sy) loses up to a pixel per side
|
-- fitScale/dpi in Sx/Sy) loses up to a pixel per side and two adjacent SGB
|
||||||
-- and two adjacent SGB zones stop sharing an edge: the letterbox clear shows
|
-- zones stop sharing an edge: the letterbox clear shows through as a seam at
|
||||||
-- through as a horizontal seam at every zone boundary (#373). Rounding
|
-- every zone boundary (#373). Rounding outward makes neighbours overlap by
|
||||||
-- outward makes neighbours overlap by at most one row instead -- the overlap
|
-- at most one row instead; SCISSOR_PIXEL_BIAS preserves that result across the
|
||||||
-- redraws the same canvas pixels one palette later, and past the canvas edge
|
-- LÖVE 11 and 12 conversion rules.
|
||||||
-- there is nothing to draw. The half pixel keeps LOVE's truncation on the
|
|
||||||
-- snapped edge rather than one short of it.
|
|
||||||
local function scissorClamped(x, y, w, h, ox, oy, vpw, vph, dpiX, dpiY)
|
local function scissorClamped(x, y, w, h, ox, oy, vpw, vph, dpiX, dpiY)
|
||||||
local x2, y2 = math.min(x + w, ox + vpw), math.min(y + h, oy + vph)
|
local x2, y2 = math.min(x + w, ox + vpw), math.min(y + h, oy + vph)
|
||||||
x, y = math.max(x, ox), math.max(y, oy)
|
x, y = math.max(x, ox), math.max(y, oy)
|
||||||
@@ -581,9 +589,10 @@ local function scissorClamped(x, y, w, h, ox, oy, vpw, vph, dpiX, dpiY)
|
|||||||
dpiX, dpiY = dpiX or 1, dpiY or 1
|
dpiX, dpiY = dpiX or 1, dpiY or 1
|
||||||
local px1, py1 = math.floor(x * dpiX), math.floor(y * dpiY)
|
local px1, py1 = math.floor(x * dpiX), math.floor(y * dpiY)
|
||||||
local px2, py2 = math.ceil(x2 * dpiX), math.ceil(y2 * dpiY)
|
local px2, py2 = math.ceil(x2 * dpiX), math.ceil(y2 * dpiY)
|
||||||
love.graphics.setScissor((px1 + 0.5) / dpiX, (py1 + 0.5) / dpiY,
|
local b = SCISSOR_PIXEL_BIAS
|
||||||
(px2 - px1 + 0.5) / dpiX,
|
love.graphics.setScissor((px1 + b) / dpiX, (py1 + b) / dpiY,
|
||||||
(py2 - py1 + 0.5) / dpiY)
|
(px2 - px1 + b) / dpiX,
|
||||||
|
(py2 - py1 + b) / dpiY)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,21 +15,41 @@ local check, eq, same = T.check, T.eq, T.same
|
|||||||
-- endFrame's blit closure, which needs canvases and a compiled shader. The
|
-- endFrame's blit closure, which needs canvases and a compiled shader. The
|
||||||
-- source is loaded directly so the rect arithmetic can be exercised with no
|
-- source is loaded directly so the rect arithmetic can be exercised with no
|
||||||
-- GPU, the same way parity_picker_pointer_grab reads RomImporter (#254).
|
-- GPU, the same way parity_picker_pointer_grab reads RomImporter (#254).
|
||||||
local scissorClamped, captured
|
local captured
|
||||||
do
|
local function loadScissor(loveMajor)
|
||||||
local f = io.open("src/render/Renderer.lua", "rb")
|
local f = io.open("src/render/Renderer.lua", "rb")
|
||||||
check(f ~= nil, "Renderer source is readable")
|
check(f ~= nil, "Renderer source is readable")
|
||||||
local src = f and f:read("*a") or ""
|
local src = f and f:read("*a") or ""
|
||||||
if f then f:close() end
|
if f then f:close() end
|
||||||
|
local bias = src:match("\nlocal SCISSOR_PIXEL_BIAS = 0%.5.-\nend\n")
|
||||||
|
check(bias ~= nil, "scissor bias is still version-gated")
|
||||||
local body = src:match("\nlocal function scissorClamped.-\nend\n")
|
local body = src:match("\nlocal function scissorClamped.-\nend\n")
|
||||||
check(body ~= nil, "scissorClamped is still a single local function")
|
check(body ~= nil, "scissorClamped is still a single local function")
|
||||||
local fakeLove = { graphics = { setScissor = function(x, y, w, h)
|
local fakeLove = {
|
||||||
captured = { x = x, y = y, w = w, h = h }
|
getVersion = function() return loveMajor, 0, 0 end,
|
||||||
end } }
|
graphics = { setScissor = function(x, y, w, h)
|
||||||
local chunk = assert(loadstring("local love = ...\n" .. (body or "")
|
captured = { x = x, y = y, w = w, h = h }
|
||||||
|
end },
|
||||||
|
}
|
||||||
|
local chunk = assert(loadstring("local love = ...\n" .. (bias or "")
|
||||||
|
.. (body or "")
|
||||||
.. "\nreturn scissorClamped"))
|
.. "\nreturn scissorClamped"))
|
||||||
scissorClamped = chunk(fakeLove)
|
local scissor = chunk(fakeLove)
|
||||||
check(type(scissorClamped) == "function", "scissorClamped loads standalone")
|
check(type(scissor) == "function", "scissorClamped loads standalone")
|
||||||
|
return scissor
|
||||||
|
end
|
||||||
|
local scissorClamped = loadScissor(11)
|
||||||
|
|
||||||
|
-- LÖVE 12 changed setScissor from truncating Lua integers to accepting floats
|
||||||
|
-- and rounding in the backend. Its arguments must therefore describe the
|
||||||
|
-- already-snapped rectangle exactly, without LÖVE 11's half-pixel nudge.
|
||||||
|
do
|
||||||
|
local scissor12 = loadScissor(12)
|
||||||
|
captured = nil
|
||||||
|
check(scissor12(50, 60, 10, 20, 0, 0, 100, 100, 2, 2),
|
||||||
|
"LÖVE 12 integer test rect draws")
|
||||||
|
same(captured, { x = 50, y = 60, w = 10, h = 20 },
|
||||||
|
"LÖVE 12 receives an unbiased snapped scissor")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- The title's three SGB zones in canvas pixels (PaletteFX.zone turns the
|
-- The title's three SGB zones in canvas pixels (PaletteFX.zone turns the
|
||||||
|
|||||||
Reference in New Issue
Block a user