diff --git a/lib/AntiAlias.lua b/lib/AntiAlias.lua index 30f8761..f10c376 100644 --- a/lib/AntiAlias.lua +++ b/lib/AntiAlias.lua @@ -133,7 +133,10 @@ local targets = {} local function targetFor(slot, w, h) local t = targets[slot] if not (t and t.w == w and t.h == h) then - local ok, c = pcall(love.graphics.newCanvas, w, h) + -- dpiscale 1: `w`/`h` are the pass's DISPLAY size in pixels, and the + -- highdpi default would fold the supersample down into a target that + -- is itself density x too big (see Voxel3D.newDepth for the trap) + local ok, c = pcall(love.graphics.newCanvas, w, h, { dpiscale = 1 }) if not (ok and c) then return nil end -- nearest, like the canvas it stands in for: this one is composited a -- canvas pixel to a display pixel, and the smoothing has already happened diff --git a/lib/BattleDOF.lua b/lib/BattleDOF.lua index 1b58ca4..3373774 100644 --- a/lib/BattleDOF.lua +++ b/lib/BattleDOF.lua @@ -98,9 +98,10 @@ end -- would reallocate both every time a battle started or ended. local function getCanvases(w, h) if not ping or cw ~= w or ch ~= h then - local ok, a = pcall(love.graphics.newCanvas, w, h) + -- dpiscale 1: pixel-sized buffers, like TiltShift's (see Voxel3D.newDepth) + local ok, a = pcall(love.graphics.newCanvas, w, h, { dpiscale = 1 }) if not ok then return nil end - local okB, b = pcall(love.graphics.newCanvas, w, h) + local okB, b = pcall(love.graphics.newCanvas, w, h, { dpiscale = 1 }) if not okB then return nil end -- the gaussian's fractional tap offsets need linear filtering a:setFilter("linear", "linear") diff --git a/lib/BattleHud.lua b/lib/BattleHud.lua index 34432e7..e2f3dfd 100644 --- a/lib/BattleHud.lua +++ b/lib/BattleHud.lua @@ -79,7 +79,8 @@ local function getShader() end local function canvasOf(w, h, filter) - local ok, c = pcall(love.graphics.newCanvas, w, h) + -- dpiscale 1: pixel-sized buffers (see Voxel3D.newDepth for the trap) + local ok, c = pcall(love.graphics.newCanvas, w, h, { dpiscale = 1 }) if not ok then return nil end c:setFilter(filter or "linear", filter or "linear") return c diff --git a/lib/ShadowMap.lua b/lib/ShadowMap.lua index 18ceffd..7824471 100644 --- a/lib/ShadowMap.lua +++ b/lib/ShadowMap.lua @@ -186,7 +186,11 @@ end local function getCanvas(res) if canvas == false then return nil end if canvas and canvasRes == res then return canvas end - local ok, c = pcall(love.graphics.newCanvas, res, res) + -- dpiscale 1: `res` is the map's edge in TEXELS, and a highdpi default + -- would cube the memory for texels the filter never asks for (see + -- Voxel3D.newDepth) -- sunTexel = 1/res in the main pass assumes the + -- stored map is exactly res texels across + local ok, c = pcall(love.graphics.newCanvas, res, res, { dpiscale = 1 }) if not (ok and c) then canvas = false return nil diff --git a/lib/TiltShift.lua b/lib/TiltShift.lua index d95c10e..a9852aa 100644 --- a/lib/TiltShift.lua +++ b/lib/TiltShift.lua @@ -85,9 +85,12 @@ end local function getCanvases(w, h) if not ping or cw ~= w or ch ~= h then - local ok, a = pcall(love.graphics.newCanvas, w, h) + -- dpiscale 1: `w`/`h` came off the input canvas in pixels, and a + -- highdpi default would multiply by the display density again (see + -- Voxel3D.newDepth) -- two gaussian passes at 9x the pixels + local ok, a = pcall(love.graphics.newCanvas, w, h, { dpiscale = 1 }) if not ok then return nil end - local okB, b = pcall(love.graphics.newCanvas, w, h) + local okB, b = pcall(love.graphics.newCanvas, w, h, { dpiscale = 1 }) if not okB then return nil end -- the gaussian's fractional tap offsets need linear filtering a:setFilter("linear", "linear") diff --git a/lib/Voxel3D.lua b/lib/Voxel3D.lua index 54ef847..e345b34 100644 --- a/lib/Voxel3D.lua +++ b/lib/Voxel3D.lua @@ -308,8 +308,15 @@ local function newDepth(w, h) if not (love.graphics and love.graphics.newCanvas) then return nil end local c = nil for _, format in ipairs(DEPTH_FORMATS) do + -- dpiscale 1: `w`/`h` are already PIXELS. Left to default, a highdpi + -- surface (iOS, Android -- see conf.lua) multiplies the canvas by the + -- display density AGAIN -- the same trap TerrainAtlas and BattlePics + -- already step around -- and a nominally window-sized buffer comes out + -- density^2 the screen's area (9x at 3x). Everywhere a canvas here is + -- sized from pixel dimensions gets the same option, so no pair of them + -- can disagree about what a coordinate means. local ok, made = pcall(love.graphics.newCanvas, w, h, - { format = format, readable = true }) + { format = format, readable = true, dpiscale = 1 }) if ok and made then c = made break end end if not c then return nil end @@ -640,7 +647,8 @@ function Voxel3D.beginScene(w, h, cx, cy, vw, vh, sky, slot) local name = slot or "world" local slotHeld = slots[name] if not (slotHeld and slotHeld.w == w and slotHeld.h == h) then - local ok, c = pcall(love.graphics.newCanvas, w, h) + -- dpiscale 1, like the depth canvas (see newDepth for the why) + local ok, c = pcall(love.graphics.newCanvas, w, h, { dpiscale = 1 }) if not ok then return false end c:setFilter("nearest", "nearest") if slotHeld then releaseSlot(slotHeld) end @@ -876,7 +884,9 @@ end function Voxel3D.beginWater(paint) if not (active and canvas and held and held.depth) then return nil end if not held.mirror then - local ok, c = pcall(love.graphics.newCanvas, held.w, held.h) + -- dpiscale 1, like the scene canvas it mirrors (see newDepth) + local ok, c = pcall(love.graphics.newCanvas, held.w, held.h, + { dpiscale = 1 }) if not (ok and c) then return nil end pcall(c.setFilter, c, "nearest", "nearest") pcall(c.setWrap, c, "clamp", "clamp")