Yeah. Bilinear filtering alone can't scale down further than half the original size without these issues, because then it skips pixels and causes aliasing.
I guess OpenGL doesn't do anything beyond bilinear filtering (edit: see Nelvin's reply below). I see that issue here as well.
You can perhaps use a canvas to pre-render the images, halving them until the desired resolution is between half the current size and the current size. Then you can scale them properly.
Due to the method used, it's best if the image sizes are powers of two, so that halving doesn't ever get you decimals. Or at least that they can be halved as many times as the minimum size requires (for example, if you're not going to scale down to something less than 1/32, then having the image size be a multiple of 16 suffices).
Code: Select all
-- targetScaleRatio is the desired scale ratio at runtime
local targetScaleRatio = 0.2
-- This resolution must be at least half the size of the biggest image.
local canvasX, canvasY = 400, 400
-- This is going to be intensive.
local function prepareImages(images)
for i = 1, #images do
images[i]:setFilter("linear", "linear")
end
local neededScale = targetScaleRatio
if neededScale < 0.5 then
local canvas = love.graphics.newCanvas(canvasX, canvasY)
love.graphics.setColor(1,1,1,1)
love.graphics.setBlendMode("replace", "premultiplied")
while neededScale < 0.5 do
for i = 1, #images do
love.graphics.setCanvas(canvas)
love.graphics.draw(images[i], 0, 0, 0, 0.5)
love.graphics.setCanvas()
local data = canvas:newImageData()
local w, h = images[i]:getWidth()/2, images[i]:getHeight()/2
local newImg = love.image.newImageData(w, h)
images[i]:release()
newImg:paste(data, 0,0,0,0,w,h)
data:release()
images[i] = love.graphics.newImage(newImg)
newImg:release()
end
neededScale = neededScale * 2
end
canvas:release()
love.graphics.setBlendMode("alpha", "alphamultiply")
end
return neededScale
end
function love.load()
heart = love.graphics.newImage("heart.png")
-- Prepare images for preprocessing
local imgs = {heart}
-- Returns the new scale factor we must use, (always between 0.5 and 1)
scale = prepareImages(imgs)
-- Recover preprocessed images
heart = imgs[1]
love.graphics.setBackgroundColor(217,217,217)
end
function love.draw()
love.graphics.draw(heart,30,30,0,scale,scale)
end
function love.keypressed(k) if k == "escape" then love.event.quit() end end
It would also be possible to do the halving on the ImageData directly, but things would start getting uglier. However it may end up being faster, not sure.