Davidobot / love.js

LÖVE ported to the web using Emscripten, updated to the latest Emscripten and LÖVE (v11.5)
MIT License
569 stars 26 forks source link

Canvas PixelFormat uses rgba4 instead of rgba8 #92

Open Yolwoocle opened 1 month ago

Yolwoocle commented 1 month ago

Creating a canvas uses rgb4 by default instead of rgb8 as specified by the wiki. If you try to force it to create a Canvas using rgba8, it returns the following error:

The rgba8 canvas format is not supported by your graphics drivers.

Weirdly enough, srgba8, the gamma-correct version of rgba8, seems to be supported. Although this is not supported by all graphics cards so it's not a workaround that will work for everything.

This is mentioned by #55.

Workaround

This workaround seems to work for me for now. Weirdly enough, srgba8, which is gamma corrected rgba8, seems to be supported by love.js on most devices, but rgba8 isn't. Even though I didn't see any noticeable changes, but please note that srgba8 is supposed to change the colors rendered on screen.

local old_newCanvas = love.graphics.newCanvas
function love.graphics.newCanvas(width, height, settings)
    settings = settings or {}

    if not settings.format then
        -- Fallback chain for supported Canvas formats
        local supportedCanvasFormats = love.graphics.getCanvasFormats()
        local fallbackChain = {
            -- It's possible to include other formats if necessary, as long as they have 4 components: 
            -- https://love2d.org/wiki/PixelFormat
            -- I don't know much about the specifics of these formats, please adapt to what works best for you.  
            -- Note that this does not take into account if `t.gammacorrect = true` is set in `love.conf`, please implement it yourself if needed.
            "rgba8",
            "srgba8",
            "rgb10a2",
            "rgb5a1",
            "rgba4",
            "normal"
        }
        local format = fallbackChain[1]
        local i = 1
        while i <= #fallbackChain and not supportedCanvasFormats[format] do
            i = i + 1
            format = fallbackChain[i]
        end
        if i == #fallbackChain + 1 then
            error("No valid canvas format is supported by the system")
        end

        settings.format = format
    end

    return old_newCanvas(width, height, settings)
end

Examples

image

Source code:

function love.conf(t)
    t.window.width = 1200
    t.window.height = 800
end

local image = love.graphics.newImage("parrot.jpg")
local canvas = love.graphics.newCanvas(600, 600, {
    format = "normal",
})
local a = 0.0
function love.update(dt)
    a = a + dt
end

function love.draw()
    love.graphics.setCanvas(canvas)
    love.graphics.clear(0, 0, 0, 1)
    love.graphics.draw(image, math.cos(a) * 30, math.sin(a) * 30)
    love.graphics.setCanvas()

    love.graphics.clear(0, 0, 0, 1)
    love.graphics.draw(canvas, 0, 0)

    love.graphics.print(tostring(canvas:getFormat()), 40, 40)
end

Source code:

function love.conf(t)
    t.window.width = 1200
    t.window.height = 800
end

local image = love.graphics.newImage("parrot.jpg")
local canvas = love.graphics.newCanvas(600, 600, {
    format = "normal",
})
local canvas2 = love.graphics.newCanvas(600, 600, {
    format = "srgba8",
})
local a = 0.0
function love.update(dt)
    a = a + dt
end

function love.draw()
    love.graphics.setCanvas(canvas)
    love.graphics.clear(0, 0, 0, 1)
    love.graphics.draw(image, math.cos(a) * 30, math.sin(a) * 30)
    love.graphics.setCanvas()

    love.graphics.setCanvas(canvas2)
    love.graphics.clear(0, 0, 0, 1)
    love.graphics.draw(image, math.cos(a) * 30, math.sin(a) * 30)
    love.graphics.setCanvas()

    love.graphics.clear(0, 0, 0, 1)
    love.graphics.draw(canvas, 0, 0)
    love.graphics.draw(canvas2, 600, 0)

    love.graphics.print(tostring(canvas:getFormat()), 40, 40)
    love.graphics.print(tostring(canvas2:getFormat()), 640, 40)
end

It's possible to see what formats are supported using this snippet of code in love.draw:

local y = 0
local canvasformats = love.graphics.getCanvasFormats()
for formatname, formatsupported in pairs(canvasformats) do
    local str = string.format("Supports format '%s': %s", formatname, tostring(formatsupported))
    love.graphics.print(str, 10, y)
    y = y + 20
end

The image I'm using: parrot

ChicknTurtle commented 1 month ago

So that's why my canvas was looking weird... I was drawing a background to a very small canvas

ChicknTurtle commented 4 weeks ago

Here it says no support for rgba8 for canvases, but there is for images https://davidobot.net/lovejs/features_c/