mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-22 21:46:51 +02:00
skins
This commit is contained in:
+13
-6
@@ -294,7 +294,6 @@ function TouchSkin.parse(text)
|
|||||||
page.viewport = { x = num(vp[1], 0), y = num(vp[2], 0),
|
page.viewport = { x = num(vp[1], 0), y = num(vp[2], 0),
|
||||||
w = num(vp[3], 1), h = num(vp[4], 1) }
|
w = num(vp[3], 1), h = num(vp[4], 1) }
|
||||||
page.viewportFill = toBool(kv[p .. "_viewport_fill"])
|
page.viewportFill = toBool(kv[p .. "_viewport_fill"])
|
||||||
page.viewportExpand = toBool(kv[p .. "_viewport_expand"])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
page.pixelCoords = not page.normalized
|
page.pixelCoords = not page.normalized
|
||||||
@@ -447,7 +446,6 @@ function TouchSkin.parseNative(text)
|
|||||||
page.viewport = { x = num(raw.viewport.x, 0), y = num(raw.viewport.y, 0),
|
page.viewport = { x = num(raw.viewport.x, 0), y = num(raw.viewport.y, 0),
|
||||||
w = num(raw.viewport.w, 1), h = num(raw.viewport.h, 1) }
|
w = num(raw.viewport.w, 1), h = num(raw.viewport.h, 1) }
|
||||||
page.viewportFill = raw.viewport.fill == true
|
page.viewportFill = raw.viewport.fill == true
|
||||||
page.viewportExpand = raw.viewport.expand == true
|
|
||||||
end
|
end
|
||||||
for _, c in ipairs(raw.controls or {}) do
|
for _, c in ipairs(raw.controls or {}) do
|
||||||
local buttons, hotkeys, keys, decorative = parseBinds(c.bind or "nul")
|
local buttons, hotkeys, keys, decorative = parseBinds(c.bind or "nul")
|
||||||
@@ -526,7 +524,6 @@ function TouchSkin.toNative(skin)
|
|||||||
x = page.viewport.x, y = page.viewport.y,
|
x = page.viewport.x, y = page.viewport.y,
|
||||||
w = page.viewport.w, h = page.viewport.h,
|
w = page.viewport.w, h = page.viewport.h,
|
||||||
fill = page.viewportFill or nil,
|
fill = page.viewportFill or nil,
|
||||||
expand = page.viewportExpand or nil,
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
for _, ctl in ipairs(page.controls or {}) do
|
for _, ctl in ipairs(page.controls or {}) do
|
||||||
@@ -922,7 +919,6 @@ function TouchSkin.toRetroArchConfig(skin)
|
|||||||
if page.viewport then
|
if page.viewport then
|
||||||
out[#out + 1] = p .. "_viewport = " .. fmtRect(page.viewport)
|
out[#out + 1] = p .. "_viewport = " .. fmtRect(page.viewport)
|
||||||
if page.viewportFill then out[#out + 1] = p .. "_viewport_fill = true" end
|
if page.viewportFill then out[#out + 1] = p .. "_viewport_fill = true" end
|
||||||
if page.viewportExpand then out[#out + 1] = p .. "_viewport_expand = true" end
|
|
||||||
end
|
end
|
||||||
local controls = {}
|
local controls = {}
|
||||||
for _, ctl in ipairs(page.controls or {}) do
|
for _, ctl in ipairs(page.controls or {}) do
|
||||||
@@ -1434,6 +1430,16 @@ local function remainderBox(ox, oy, w, h, bx, by, bw, bh)
|
|||||||
return best[1], best[2], best[3], best[4]
|
return best[1], best[2], best[3], best[4]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- The deck box pinned to the lower edge (see pageBox) leaves room above it
|
||||||
|
-- that belongs to the game, so a screen rect flush with the top of the deck
|
||||||
|
-- grows into it instead of showing a black band.
|
||||||
|
local function deckHeadroom(y, vh, by, bh, oy, h)
|
||||||
|
if by <= oy + 0.5 then return y, vh end
|
||||||
|
if by + bh < oy + h - 0.5 then return y, vh end
|
||||||
|
if y - by > math.max(2, bh * 0.01) then return y, vh end
|
||||||
|
return oy, vh + (y - oy)
|
||||||
|
end
|
||||||
|
|
||||||
function TouchSkin.pageViewport(page, w, h, ox, oy)
|
function TouchSkin.pageViewport(page, w, h, ox, oy)
|
||||||
if not page then return nil end
|
if not page then return nil end
|
||||||
ox, oy = ox or 0, oy or 0
|
ox, oy = ox or 0, oy or 0
|
||||||
@@ -1443,12 +1449,13 @@ function TouchSkin.pageViewport(page, w, h, ox, oy)
|
|||||||
local x, y = bx + v.x * bw, by + v.y * bh
|
local x, y = bx + v.x * bw, by + v.y * bh
|
||||||
local vw, vh = v.w * bw, v.h * bh
|
local vw, vh = v.w * bw, v.h * bh
|
||||||
if vw <= 0 or vh <= 0 then return nil end
|
if vw <= 0 or vh <= 0 then return nil end
|
||||||
return x, y, vw, vh, page.viewportFill == true, page.viewportExpand == true
|
y, vh = deckHeadroom(y, vh, by, bh, oy, h)
|
||||||
|
return x, y, vw, vh, page.viewportFill == true
|
||||||
end
|
end
|
||||||
if page.screenFit == "remainder" then
|
if page.screenFit == "remainder" then
|
||||||
local x, y, vw, vh = remainderBox(ox, oy, w, h, bx, by, bw, bh)
|
local x, y, vw, vh = remainderBox(ox, oy, w, h, bx, by, bw, bh)
|
||||||
if not x then return nil end
|
if not x then return nil end
|
||||||
return x, y, vw, vh, false, false
|
return x, y, vw, vh, false
|
||||||
end
|
end
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1067,9 +1067,22 @@ local GAME_TABS = {
|
|||||||
local HEADER_TABS = {
|
local HEADER_TABS = {
|
||||||
{ id = "mods", key = "tab-mods" },
|
{ id = "mods", key = "tab-mods" },
|
||||||
{ id = "find", key = "tab-find" },
|
{ id = "find", key = "tab-find" },
|
||||||
{ id = "skins", key = "tab-skins", glyph = true },
|
{ id = "skins", key = "tab-skins", glyph = true, beta = true },
|
||||||
{ id = "bug", key = "tab-bug" },
|
{ id = "bug", key = "tab-bug" },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local BETA_TAG_OPTS = { fill = true, bold = true, ink = PAL.inverse }
|
||||||
|
|
||||||
|
local function drawBetaTag(x, y, w, h)
|
||||||
|
Kit.tag(x, y, w, h, "BETA", PAL.yellow, BETA_TAG_OPTS)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function overlayBeta(tx, ty, w, tabH, m)
|
||||||
|
local bh = math.floor(11 * m.s)
|
||||||
|
local bw = math.min(w, Kit.textWidth("micro", "BETA") + math.floor(10 * m.s))
|
||||||
|
drawBetaTag(tx + (w - bw) / 2, ty + tabH - bh - math.floor(2 * m.s), bw, bh)
|
||||||
|
end
|
||||||
|
|
||||||
for _, t in ipairs(HEADER_TABS) do
|
for _, t in ipairs(HEADER_TABS) do
|
||||||
t.opts = { face = "tab", font = "tab", color = t.color, letter = t.letter }
|
t.opts = { face = "tab", font = "tab", color = t.color, letter = t.letter }
|
||||||
if t.glyph then
|
if t.glyph then
|
||||||
@@ -1273,6 +1286,7 @@ local function buildHeader(imp, m)
|
|||||||
o.image = t.icon
|
o.image = t.icon
|
||||||
o.action = chrome.tab[t.id]
|
o.action = chrome.tab[t.id]
|
||||||
btn(imp, tx, ty, w, tabH, t.key, "", o)
|
btn(imp, tx, ty, w, tabH, t.key, "", o)
|
||||||
|
if t.beta then overlayBeta(tx, ty, w, tabH, m) end
|
||||||
tx = tx + w + tabGap
|
tx = tx + w + tabGap
|
||||||
end
|
end
|
||||||
-- The bug-report chip sits LAST, past the sync chip.
|
-- The bug-report chip sits LAST, past the sync chip.
|
||||||
@@ -1290,10 +1304,7 @@ local function buildHeader(imp, m)
|
|||||||
local o = chrome.sync
|
local o = chrome.sync
|
||||||
o.active = imp._syncModal ~= nil
|
o.active = imp._syncModal ~= nil
|
||||||
btn(imp, tx, ty, w, tabH, "tab-sync", "", o)
|
btn(imp, tx, ty, w, tabH, "tab-sync", "", o)
|
||||||
local bh = math.floor(11 * m.s)
|
overlayBeta(tx, ty, w, tabH, m)
|
||||||
local bw = math.min(w, Kit.textWidth("micro", "BETA") + math.floor(10 * m.s))
|
|
||||||
Kit.tag(tx + (w - bw) / 2, ty + tabH - bh - math.floor(2 * m.s), bw, bh,
|
|
||||||
"BETA", o.active and PAL.inverse or PAL.yellow)
|
|
||||||
local eng = imp._sync
|
local eng = imp._sync
|
||||||
if eng and eng.busy and eng:busy() then
|
if eng and eng.busy and eng:busy() then
|
||||||
Kit.spinner(tx + w - math.floor(8 * m.s), ty + math.floor(8 * m.s),
|
Kit.spinner(tx + w - math.floor(8 * m.s), ty + math.floor(8 * m.s),
|
||||||
@@ -4490,8 +4501,8 @@ local function syncTitle(imp, m, px, py, pw, pad)
|
|||||||
Kit.text("button", label, px + pad, py, PAL.heading)
|
Kit.text("button", label, px + pad, py, PAL.heading)
|
||||||
local bh = math.floor(15 * m.s)
|
local bh = math.floor(15 * m.s)
|
||||||
local bw = Kit.textWidth("micro", "BETA") + math.floor(14 * m.s)
|
local bw = Kit.textWidth("micro", "BETA") + math.floor(14 * m.s)
|
||||||
Kit.tag(px + pad + Kit.textWidth("button", label) + math.floor(8 * m.s),
|
drawBetaTag(px + pad + Kit.textWidth("button", label) + math.floor(8 * m.s),
|
||||||
py + (Kit.textHeight("button") - bh) / 2, bw, bh, "BETA", PAL.yellow)
|
py + (Kit.textHeight("button") - bh) / 2, bw, bh)
|
||||||
return py + Kit.textHeight("button") + math.floor(12 * m.s)
|
return py + Kit.textHeight("button") + math.floor(12 * m.s)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ local TouchSkin = require("src.core.TouchSkin")
|
|||||||
|
|
||||||
local Playfield = {}
|
local Playfield = {}
|
||||||
|
|
||||||
Playfield.WIDTH, Playfield.HEIGHT = 160, 144
|
|
||||||
|
|
||||||
Playfield.entered = false
|
Playfield.entered = false
|
||||||
Playfield.box = nil
|
Playfield.box = nil
|
||||||
|
|
||||||
@@ -35,14 +33,9 @@ function Playfield.cutout(sw, sh)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Playfield.rect(sw, sh)
|
function Playfield.rect(sw, sh)
|
||||||
local x, y, w, h, _, expand = Playfield.cutout(sw, sh)
|
local x, y, w, h = Playfield.cutout(sw, sh)
|
||||||
if not x then return 0, 0, sw or 0, sh or 0, false end
|
if not x then return 0, 0, sw or 0, sh or 0, false end
|
||||||
if expand then return x, y, w, h, true end
|
return x, y, w, h, true
|
||||||
local s = math.max(1, math.floor(math.min(w / Playfield.WIDTH,
|
|
||||||
h / Playfield.HEIGHT)))
|
|
||||||
local pw = math.min(w, Playfield.WIDTH * s)
|
|
||||||
local ph = math.min(h, Playfield.HEIGHT * s)
|
|
||||||
return x + math.floor((w - pw) / 2), y + math.floor((h - ph) / 2), pw, ph, true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Playfield.enter(x, y, w, h)
|
function Playfield.enter(x, y, w, h)
|
||||||
|
|||||||
@@ -87,12 +87,12 @@ local function displayMetrics()
|
|||||||
if dpiX < 1e-6 then dpiX = 1 end
|
if dpiX < 1e-6 then dpiX = 1 end
|
||||||
if dpiY < 1e-6 then dpiY = 1 end
|
if dpiY < 1e-6 then dpiY = 1 end
|
||||||
local vx, vy = 0, 0
|
local vx, vy = 0, 0
|
||||||
local cut, grow = false, false
|
local cut = false
|
||||||
local sx, sy, sw, sh, _, expand = Playfield.cutout(pw, ph)
|
local sx, sy, sw, sh = Playfield.cutout(pw, ph)
|
||||||
if sx then
|
if sx then
|
||||||
vx, vy, pw, ph, cut, grow = sx, sy, sw, sh, true, expand
|
vx, vy, pw, ph, cut = sx, sy, sw, sh, true
|
||||||
end
|
end
|
||||||
return ww, wh, pw, ph, dpiX, dpiY, vx, vy, cut, grow
|
return ww, wh, pw, ph, dpiX, dpiY, vx, vy, cut
|
||||||
end
|
end
|
||||||
|
|
||||||
local function positionLift(ph, contentPx, dpiY, cut)
|
local function positionLift(ph, contentPx, dpiY, cut)
|
||||||
@@ -275,7 +275,7 @@ end
|
|||||||
-- corners; flat mode returns exactly today's size (growth factor is 1 when
|
-- corners; flat mode returns exactly today's size (growth factor is 1 when
|
||||||
-- tilt is inactive).
|
-- tilt is inactive).
|
||||||
function Renderer:worldViewSize()
|
function Renderer:worldViewSize()
|
||||||
local _, _, pw, ph, _, dpiY, _, _, cut, grow = displayMetrics()
|
local _, _, pw, ph, _, dpiY, _, _, cut = displayMetrics()
|
||||||
-- FAITHFUL RATIO on mobile. The world pass deliberately expands to cover the
|
-- FAITHFUL RATIO on mobile. The world pass deliberately expands to cover the
|
||||||
-- WHOLE display, so letterbox voids become more map instead of black bars.
|
-- WHOLE display, so letterbox voids become more map instead of black bars.
|
||||||
-- That is why the lock appeared to do nothing in the overworld: it shrank
|
-- That is why the lock appeared to do nothing in the overworld: it shrank
|
||||||
@@ -287,7 +287,6 @@ function Renderer:worldViewSize()
|
|||||||
-- this is the same sum with the viewport standing in for the window, so
|
-- this is the same sum with the viewport standing in for the window, so
|
||||||
-- both platforms show the same map area at the same zoom.
|
-- both platforms show the same map area at the same zoom.
|
||||||
local cap = FaithfulRes.scaleCap()
|
local cap = FaithfulRes.scaleCap()
|
||||||
if not cap and cut and not grow then cap = self:fitScale() end
|
|
||||||
if cap then
|
if cap then
|
||||||
local uiw, uih = self:uiSize()
|
local uiw, uih = self:uiSize()
|
||||||
pw = cut and math.min(pw, uiw * cap) or uiw * cap
|
pw = cut and math.min(pw, uiw * cap) or uiw * cap
|
||||||
|
|||||||
@@ -456,9 +456,10 @@ function Studio.setCanvas(index, fromSync)
|
|||||||
page.viewportFill = false
|
page.viewportFill = false
|
||||||
markDirty()
|
markDirty()
|
||||||
end
|
end
|
||||||
-- A cfg-authored aspect_ratio is the overlay's design aspect; keep it so
|
-- A cfg-authored aspect_ratio is the overlay's design aspect, and bezel art
|
||||||
-- the preview letterboxes like RetroArch instead of stretching (#1503).
|
-- is its own design canvas (TouchSkin.applyImageAspect); keep either so the
|
||||||
if page and not page.aspectFromCfg then
|
-- preview lays the page out exactly the way the game does (#1503).
|
||||||
|
if page and not (page.aspectFromCfg or page.aspectFromImage) then
|
||||||
page.aspect = canvas.w / canvas.h
|
page.aspect = canvas.w / canvas.h
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+15
-4
@@ -749,12 +749,23 @@ function Kit.chip(x, y, w, h, label, on, color, id)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- A status label with no interaction: outlined text, the "INSTALLED"/"UPDATE"
|
-- A status label with no interaction: outlined text, the "INSTALLED"/"UPDATE"
|
||||||
-- markers on mod rows.
|
-- markers on mod rows. Pass opts.fill for a solid chip (BETA badges); ink
|
||||||
function Kit.tag(x, y, w, h, label, color)
|
-- then defaults to PAL.inverse so the label stays readable on the fill.
|
||||||
|
function Kit.tag(x, y, w, h, label, color, opts)
|
||||||
if not G then return end
|
if not G then return end
|
||||||
|
opts = opts or {}
|
||||||
|
if opts.fill then
|
||||||
|
Theme.fillRounded(x, y, w, h, color or PAL.yellow, 1, h / 2)
|
||||||
|
else
|
||||||
Theme.strokeRounded(x, y, w, h, color or PAL.line, 0.7, 1)
|
Theme.strokeRounded(x, y, w, h, color or PAL.line, 0.7, 1)
|
||||||
Kit.textCenter("micro", label, x, y + (h - Kit.textHeight("micro")) / 2, w,
|
end
|
||||||
color or PAL.muted)
|
local ink = opts.ink or (opts.fill and PAL.inverse) or color or PAL.muted
|
||||||
|
local ty = y + (h - Kit.textHeight("micro")) / 2
|
||||||
|
if opts.bold then
|
||||||
|
Kit.textCenterBold("micro", label, x, ty, w, ink)
|
||||||
|
else
|
||||||
|
Kit.textCenter("micro", label, x, ty, w, ink)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Checkbox row. Returns (newChecked, changed).
|
-- Checkbox row. Returns (newChecked, changed).
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
-- Screen-rect check for a touch skin, both generations.
|
||||||
|
--
|
||||||
|
-- POKEPORT_DRIVER=tests/drivers/skin_screen_shot.lua love .
|
||||||
|
-- POKEPORT_GAME=gold POKEPORT_SKIN=my_skin POKEPORT_DRIVER=... love .
|
||||||
|
--
|
||||||
|
-- Gold's cache lives under the DEFAULT save identity, so a POKEPORT_IDENTITY
|
||||||
|
-- sandbox has to be seeded with it first or the boot hangs in the importer:
|
||||||
|
-- cp -R ~/Library/Application\ Support/LOVE/pokemon-love2d/{gold,skins} \
|
||||||
|
-- ~/Library/Application\ Support/LOVE/<identity>/
|
||||||
|
local U = require("tests.drivers.util")
|
||||||
|
local GameVersion = require("src.core.GameVersion")
|
||||||
|
|
||||||
|
local function env(name, fallback)
|
||||||
|
local v = os.getenv(name)
|
||||||
|
if v == nil or v == "" then return fallback end
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
|
||||||
|
local function tap(game, button)
|
||||||
|
game.input.pressQueue[#game.input.pressQueue + 1] = button
|
||||||
|
game.input.state[button] = true
|
||||||
|
U.wait(2)
|
||||||
|
game.input.state[button] = false
|
||||||
|
end
|
||||||
|
|
||||||
|
return function(game)
|
||||||
|
local TouchControls = require("src.core.TouchControls")
|
||||||
|
local out = env("POKEPORT_SHOT_DIR", ".")
|
||||||
|
local gen2 = GameVersion.generation() == 2
|
||||||
|
|
||||||
|
love.window.setMode(tonumber(env("POKEPORT_SHOT_W", 460)),
|
||||||
|
tonumber(env("POKEPORT_SHOT_H", 950)))
|
||||||
|
local skin = env("POKEPORT_SKIN", "gb_anim")
|
||||||
|
local ok, err = TouchControls:selectSkin(skin)
|
||||||
|
assert(ok, "skin " .. skin .. ": " .. tostring(err))
|
||||||
|
|
||||||
|
U.wait(60)
|
||||||
|
if gen2 then
|
||||||
|
local A = require("tests.drivers.gold.adapter")
|
||||||
|
assert(game.world and game.world.map, "gold world did not boot")
|
||||||
|
A.teleport(game, env("POKEPORT_SHOT_MAP", "NEW_BARK_TOWN"), 6, 6)
|
||||||
|
U.wait(120)
|
||||||
|
else
|
||||||
|
local Pokemon = require("src.pokemon.Pokemon")
|
||||||
|
game.save.party = { Pokemon.new(game.data, "CHARIZARD", 50) }
|
||||||
|
U.teleport(game, env("POKEPORT_SHOT_MAP", "PALLET_TOWN"), 10, 8, "down")
|
||||||
|
U.wait(40)
|
||||||
|
end
|
||||||
|
U.shot(game, out .. "/skin_world.png")
|
||||||
|
|
||||||
|
tap(game, "start")
|
||||||
|
U.wait(60)
|
||||||
|
U.shot(game, out .. "/skin_menu.png")
|
||||||
|
|
||||||
|
love.event.quit()
|
||||||
|
while true do coroutine.yield() end
|
||||||
|
end
|
||||||
@@ -316,6 +316,8 @@ check(view:find('"tab-sync"', 1, true) ~= nil,
|
|||||||
local header = view:match("local HEADER_TABS = %{(.-)%}\n")
|
local header = view:match("local HEADER_TABS = %{(.-)%}\n")
|
||||||
check(header and header:find('id = "skins"', 1, true) ~= nil,
|
check(header and header:find('id = "skins"', 1, true) ~= nil,
|
||||||
"and it sits beside the skins tab")
|
"and it sits beside the skins tab")
|
||||||
|
check(header and header:find("beta = true", 1, true) ~= nil,
|
||||||
|
"the skins tab carries a BETA badge too")
|
||||||
check(view:find('"BETA"', 1, true) ~= nil,
|
check(view:find('"BETA"', 1, true) ~= nil,
|
||||||
"the button and the modal are labelled BETA")
|
"the button and the modal are labelled BETA")
|
||||||
check(view:find("buildSyncModal", 1, true) ~= nil,
|
check(view:find("buildSyncModal", 1, true) ~= nil,
|
||||||
|
|||||||
@@ -111,6 +111,25 @@ check(Studio.page().viewport ~= nil, "the SGB cutout cannot be toggled off")
|
|||||||
Studio.setCanvas(#Studio.CANVASES + 1)
|
Studio.setCanvas(#Studio.CANVASES + 1)
|
||||||
eq(Studio.canvasIndex, 1, "canvas selection wraps")
|
eq(Studio.canvasIndex, 1, "canvas selection wraps")
|
||||||
|
|
||||||
|
-- the preview must lay the page out the way the game will, so a preset never
|
||||||
|
-- overwrites the aspect the bezel art (or a cfg) already fixed
|
||||||
|
session()
|
||||||
|
local art = Studio.page()
|
||||||
|
art.aspect, art.aspectFromImage = 0.5625, true
|
||||||
|
Studio.setCanvas(1)
|
||||||
|
near(art.aspect, 0.5625, 1e-9, "bezel art keeps its own aspect on a preset switch")
|
||||||
|
local deckW, deckH = 900, 1700
|
||||||
|
local _, dby, _, dbh = TouchSkin.pageBox(art, deckW, deckH)
|
||||||
|
check(dby > 0 and math.abs(dby + dbh - deckH) < 1e-6,
|
||||||
|
"so a preset taller than the art pins the deck low, as gameplay does")
|
||||||
|
|
||||||
|
session()
|
||||||
|
local plain = Studio.page()
|
||||||
|
plain.aspect, plain.aspectFromImage, plain.aspectFromCfg = nil, nil, nil
|
||||||
|
Studio.setCanvas(1)
|
||||||
|
near(plain.aspect, Studio.canvas().w / Studio.canvas().h, 1e-9,
|
||||||
|
"a page with no art of its own still takes the preset's aspect")
|
||||||
|
|
||||||
Studio.setCanvas(1)
|
Studio.setCanvas(1)
|
||||||
Studio.viewZoom = 1
|
Studio.viewZoom = 1
|
||||||
local cx, cy, cw, ch = Studio.canvasRect(0, 0, 800, 600)
|
local cx, cy, cw, ch = Studio.canvasRect(0, 0, 800, 600)
|
||||||
|
|||||||
@@ -136,11 +136,16 @@ for off = lo, hi do
|
|||||||
end
|
end
|
||||||
Zoom.offset = 0
|
Zoom.offset = 0
|
||||||
|
|
||||||
local capped = select(1, Renderer:worldViewSize())
|
useSkin("0.25,0.1,0.3,0.8")
|
||||||
useSkin("0.25,0.1,0.5,0.6", "overlay0_viewport_expand = true")
|
local tallR = Renderer:frameRects()
|
||||||
local expanded = select(1, Renderer:worldViewSize())
|
local tallVw, tallVh = Renderer:worldViewSize()
|
||||||
check(expanded > capped,
|
local tallSp = Zoom.scale(tallR.Sp)
|
||||||
"viewport_expand lets the survey world fill the cutout instead of the GB box")
|
check(tallVw * tallSp >= tallR.vuw and tallVh * tallSp >= tallR.vuh,
|
||||||
|
"the world pass covers the whole cutout, not just the GB box inside it")
|
||||||
|
check(tallVh * tallSp > tallR.uvph,
|
||||||
|
"so a cutout taller than 160x144 shows map where the UI letterbox ends")
|
||||||
|
check(tallR.uvph < tallR.vuh and tallR.uvpw <= tallR.vuw,
|
||||||
|
"while the UI keeps its whole-pixel letterbox inside that cutout")
|
||||||
useSkin("0.25,0.1,0.5,0.6")
|
useSkin("0.25,0.1,0.5,0.6")
|
||||||
|
|
||||||
setWindow(480, 800)
|
setWindow(480, 800)
|
||||||
@@ -159,22 +164,14 @@ setWindow(1280, 720)
|
|||||||
useSkin("0.25,0.1,0.5,0.6")
|
useSkin("0.25,0.1,0.5,0.6")
|
||||||
local px, py, pw, ph, active = Playfield.rect(1280, 720)
|
local px, py, pw, ph, active = Playfield.rect(1280, 720)
|
||||||
eq(active, true, "Gold sees the cutout too")
|
eq(active, true, "Gold sees the cutout too")
|
||||||
eq(pw, 480, "the playfield is a whole multiple of 160")
|
eq(px, 320, "the playfield is the cutout, at its origin")
|
||||||
eq(ph, 432, "and of 144")
|
eq(py, 72, "on both axes")
|
||||||
check(inside(px, py, pw, ph, 320, 72, 640, 432),
|
eq(pw, 640, "with its full width")
|
||||||
"centred inside the cutout")
|
eq(ph, 432, "and its full height")
|
||||||
eq(Chrome.fitScale(1280, 720), 3, "Chrome fits the playfield")
|
eq(Chrome.fitScale(1280, 720), 3, "Chrome fits whole GB pixels in it")
|
||||||
local cox, coy = Chrome.fitOrigin(1280, 720)
|
local cox, coy = Chrome.fitOrigin(1280, 720)
|
||||||
eq(cox, px, "and centres the panel on it")
|
eq(cox, 320 + 80, "and centres the panel on the cutout")
|
||||||
eq(coy, py, "on both axes")
|
eq(coy, 72, "on both axes")
|
||||||
|
|
||||||
useSkin("0.25,0.1,0.5,0.6", "overlay0_viewport_expand = true")
|
|
||||||
local ex, ey, ew, eh = Playfield.rect(1280, 720)
|
|
||||||
eq(ew, 640, "expand hands the picture the full cutout width")
|
|
||||||
eq(eh, 432, "and its full height")
|
|
||||||
eq(ex, 320, "at the cutout origin")
|
|
||||||
eq(ey, 72, "on both axes")
|
|
||||||
useSkin("0.25,0.1,0.5,0.6")
|
|
||||||
|
|
||||||
local ew2, eh2, ex2, ey2, act2 = Playfield.push(1280, 720)
|
local ew2, eh2, ex2, ey2, act2 = Playfield.push(1280, 720)
|
||||||
eq(act2, true, "push reports the frame is contained")
|
eq(act2, true, "push reports the frame is contained")
|
||||||
@@ -184,12 +181,29 @@ eq(ew2, pw, "and hands the scene the playfield size")
|
|||||||
eq(Playfield.cutout(ew2, eh2), nil, "inside the frame there is no cutout left")
|
eq(Playfield.cutout(ew2, eh2), nil, "inside the frame there is no cutout left")
|
||||||
eq(select(3, Playfield.rect(ew2, eh2)), pw, "so the playfield is the surface")
|
eq(select(3, Playfield.rect(ew2, eh2)), pw, "so the playfield is the surface")
|
||||||
eq(Chrome.fitScale(ew2, eh2), 3, "and Chrome fits it without re-applying")
|
eq(Chrome.fitScale(ew2, eh2), 3, "and Chrome fits it without re-applying")
|
||||||
eq(select(1, Chrome.fitOrigin(ew2, eh2)), 0, "at a local origin")
|
eq(select(1, Chrome.fitOrigin(ew2, eh2)), 80, "centred on that surface alone")
|
||||||
eq(select(1, Playfield.dimensions()), pw, "screens read the playfield as the display")
|
eq(select(1, Playfield.dimensions()), pw, "screens read the playfield as the display")
|
||||||
Playfield.pop()
|
Playfield.pop()
|
||||||
eq(Playfield.entered, false, "pop leaves the frame")
|
eq(Playfield.entered, false, "pop leaves the frame")
|
||||||
eq(select(1, Playfield.cutout(1280, 720)), 320, "and the cutout is visible again")
|
eq(select(1, Playfield.cutout(1280, 720)), 320, "and the cutout is visible again")
|
||||||
|
|
||||||
|
setWindow(960, 1901)
|
||||||
|
useSkin("0,0,1,0.5", "overlay0_aspect_ratio = 0.5625")
|
||||||
|
local deck = TouchSkin.page()
|
||||||
|
local _, dy, _, dh = TouchSkin.pageBox(deck, 960, 1901)
|
||||||
|
check(dy > 0 and math.abs(dy + dh - 1901) < 1,
|
||||||
|
"a portrait deck taller than the display pins to the lower edge")
|
||||||
|
local hx, hy, hw, hh = Playfield.cutout(960, 1901)
|
||||||
|
eq(hy, 0, "and the screen rect it left flush takes the room above it")
|
||||||
|
eq(hx, 0, "without moving sideways")
|
||||||
|
eq(hw, 960, "or changing width")
|
||||||
|
eq(hh, math.floor(dy + dh * 0.5), "growing by exactly the headroom")
|
||||||
|
|
||||||
|
useSkin("0,0.1,1,0.5", "overlay0_aspect_ratio = 0.5625")
|
||||||
|
check(select(2, Playfield.cutout(960, 1901)) > dy,
|
||||||
|
"a screen rect the author inset from the top keeps that bezel margin")
|
||||||
|
|
||||||
|
setWindow(1280, 720)
|
||||||
useSkin("0.4,0.4,0.1,0.1")
|
useSkin("0.4,0.4,0.1,0.1")
|
||||||
local sx, sy, sw, sh = Playfield.rect(1280, 720)
|
local sx, sy, sw, sh = Playfield.rect(1280, 720)
|
||||||
check(inside(sx, sy, sw, sh, 512, 288, 128, 72),
|
check(inside(sx, sy, sw, sh, 512, 288, 128, 72),
|
||||||
|
|||||||
Reference in New Issue
Block a user