love.math.gammaToLinear

Available since LÖVE 0.9.1
This function is not supported in earlier versions.

Converts a color from gamma-space (sRGB) to linear-space (RGB). This is useful when doing gamma-correct rendering using colors created based on what they look like on-screen.

Read more about gamma-correct rendering here, here, and here.

O.png Gamma-correct rendering is an advanced topic and it's easy to get color-spaces mixed up. If you're not sure whether you need this, you might want to avoid it.  


Function

Synopsis

lr, lg, lb = love.math.gammaToLinear( r, g, b )

Arguments

number r
The red channel of the sRGB color to convert.
number g
The green channel of the sRGB color to convert.
number b
The blue channel of the sRGB color to convert.

Returns

number lr
The red channel of the converted color in linear RGB space.
number lg
The green channel of the converted color in linear RGB space.
number lb
The blue channel of the converted color in linear RGB space.

Notes

An alpha value can be passed into the function as a fourth argument, but it will be returned unchanged because alpha is always linear.

Function

Synopsis

lr, lg, lb = love.math.gammaToLinear( color )

Arguments

table color
An array with the red, green, and blue channels of the sRGB color to convert.

Returns

number lr
The red channel of the converted color in linear RGB space.
number lg
The green channel of the converted color in linear RGB space.
number lb
The blue channel of the converted color in linear RGB space.

Function

Synopsis

lc = love.math.gammaToLinear( c )

Arguments

number c
The value of a color channel in sRGB space to convert.

Returns

number lc
The value of the color channel in linear RGB space.

Notes

Gamma-space sRGB has more precision in the lower end than linear RGB. Using this function to convert from sRGB to RGB can result in non-integer color values, which get truncated to integers and lose precision when used with other functions such as love.graphics.setColor.

Examples

Gamma-correct rendering using colored circles

function love.load()
    -- Enable the sRGB mode for the window. This converts from linear RGB to gamma-space sRGB when
    -- things are drawn to the screen (but blending calculations are done in linear RGB space.)
    -- Computer monitors display in the sRGB color space.
    love.window.setMode(800, 600, {srgb=true, fsaa=4})

    -- If sRGB mode for the screen isn't supported, the flag will be false.
    local _, _, flags = love.window.getMode()
    gammacorrect = flags.srgb

    -- Here we have a red-ish color with 50% opacity. I chose the color values here based on what it looked like
    -- on-screen, and because computer monitors display in the sRGB color space, this color is in the sRGB color space.
    color1 = {187, 54, 100, 128}

    if gammacorrect then
        -- If the window is in srgb mode, it converts from linear RGB to sRGB when drawing. This means we need to
        -- convert the sRGB-space color to linear RGB space.
        color1 = {love.math.gammaToLinear(color1)}
    end

    -- We want this color to be halfway between white and black (with 50% opacity as well).
    -- If the window is in srgb mode, it expects linear-space colors and does blending that way, so this will work
    -- out fine. If the window isn't in srgb mode, the color won't be halfway between white and black because
    -- the values drawn to the screen aren't treated as linear-space RGB and converted to sRGB.
    -- We could use love.math.linearToGamma in that case, but blending would still be wrong.
    color2 = {128, 128, 128, 128}
end

-- Draw two overlapping circles with additive blending, using the colors above.
function love.draw()
    love.graphics.setBlendMode("additive")
    
    love.graphics.setColor(color1)
    love.graphics.circle("fill", 300, 300, 200)

    love.graphics.setColor(color2)
    love.graphics.circle("fill", 500, 300, 200)
end

Pre-multiply an image's alpha with its RGB values in linear RGB space

local function PremultiplyLinearPixel(x, y, r, g, b, a)
   r = r * a / 255
   g = g * a / 255
   b = b * a / 255
   return r, g, b, a
end

local function PremultiplyGammaPixel(x, y, r, g, b, a)
   r, g, b = love.math.gammaToLinear(r, g, b)
   r = r * a / 255
   g = g * a / 255
   b = b * a / 255
   r, g, b = love.math.linearToGamma(r, g, b)
   return r, g, b, a
end

-- Loads an image and pre-multiplies its RGB values with its alpha, for use with the 'premultiplied' alpha blend mode.
-- The multiplication correctly accounts for the color-space of the image.
function NewPremultipliedImage(filepath, format)
    local imagedata = love.image.newImageData(filepath)

    local mapfunction = format == "srgb" and PremultiplyGammaPixel or PremultiplyLinearPixel
    imagedata:mapPixel(mapfunction)

    return love.graphics.newImage(imagedata, format)
end

-- This assumes gamma-correct rendering (with the sRGB window flag) is being done.
image = NewPremultipliedImage("pig.png", "srgb")

See Also

Other Languages