Skip to content

Instantly share code, notes, and snippets.

@flamendless
Forked from 1bardesign/main.lua
Created Nov 13, 2018
Embed
What would you like to do?
recolour.lua
--[[
example use
]]
local recolour = require("recolour")
--we want to recolour this asset image
local to_recolour = love.image.newImageData("path/to/image.png")
--using this palette image
local palette = love.image.newImageData("path/to/palette.png")
--using this palette (first non-source palette)
local palette_number = 1
--get the recoloured image data
local recoloured = recolour(to_recolour, palette, palette_number)
--load into an image so we can render it
local image = love.graphics.newImage(recoloured)
--now free to render it as normal using lg.draw or whatever!
--[[
(math helpers required)
(recommend having stuff like this in some central math.lua)
]]
--clamp v to range [lo, hi]
function math.clamp(v, lo, hi)
return math.max(lo, math.min(v, hi))
end
--round v to nearest whole
function math.round(v)
return math.floor(v + 0.5)
end
--(required bitops)
local bit = require("bit")
local band, bor, lshift = bit.band, bit.bor, bit.lshift
--rgb hex -> r g b a (full alpha)
function math.getColorRGBHex(rgb)
local r = rshift(band(rgb, 0x00ff0000), 16) / 255.0
local g = rshift(band(rgb, 0x0000ff00), 8) / 255.0
local b = rshift(band(rgb, 0x000000ff), 0) / 255.0
local a = 1.0
return r, g, b, a
end
--r g b -> rgb hex (no alpha stored)
function math.colorToRGBHex(r, g, b)
local br = lshift(band(0xff, r * 255), 16)
local bg = lshift(band(0xff, g * 255), 8)
local bb = lshift(band(0xff, b * 255), 0)
return bor( br, bg, bb )
end
--[[
recolouring an asset based on an input palette
asset_data imagedata to recolour (in "source colours")
palette_data imagedata of palette
organised in vertical columns
first column = "input" palette
other columns = "output" palettes
palette_number which palette to use (0 for no recolour)
any colours not found in the palette will NOT be recoloured
this allows recolouring hair and skin and armour as separate
passes, without needing a super complicated palette
]]
local function recolour(asset_data, palette_data, palette_number)
--load
local data = asset_data:clone()
--recolour only if needed
palette_number = math.round(math.clamp(palette_number, 0, palette_data:getWidth() - 1))
if palette_number ~= 0 then
--build mapping
local pixel_mapping = {}
for i = 0, palette_data:getHeight() - 1 do
local in_rgb = math.colorToRGBHex(palette_data:getPixel(0, i))
local out_rgb = math.colorToRGBHex(palette_data:getPixel(palette_number, i))
pixel_mapping[in_rgb] = out_rgb
end
--apply mapping
data:mapPixel(function(x, y, r, g, b, a)
--(don't need to remap totally transparent pixels)
if a ~= 0 then
local mapped = pixel_mapping[math.colorToRGBHex(r, g, b)]
if mapped ~= nil then
r, g, b = math.getColorRGBHex(mapped)
end
--(keep alpha the same)
end
return r, g, b, a
end)
end
return data
end
return recolour
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment