mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-15 15:51:17 +02:00
initial commit
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
local ImageWriter = {}
|
||||
|
||||
local SHADES = {
|
||||
{ 1, 1, 1, 1 },
|
||||
{ 2 / 3, 2 / 3, 2 / 3, 1 },
|
||||
{ 1 / 3, 1 / 3, 1 / 3, 1 },
|
||||
{ 0, 0, 0, 1 },
|
||||
}
|
||||
|
||||
local function assertDimensions(raw, width, height, bits)
|
||||
assert(width % 8 == 0 and height % 8 == 0,
|
||||
("%dbpp dimensions must be tile-aligned: %dx%d")
|
||||
:format(bits, width, height))
|
||||
local expected = width * height * bits / 8
|
||||
assert(#raw == expected,
|
||||
("%dbpp payload is %d bytes, expected %d")
|
||||
:format(bits, #raw, expected))
|
||||
end
|
||||
|
||||
function ImageWriter.decode2bpp(raw, width, height, transparent)
|
||||
assertDimensions(raw, width, height, 2)
|
||||
local image = love.image.newImageData(width, height)
|
||||
local tilesPerRow = width / 8
|
||||
for tile = 0, #raw / 16 - 1 do
|
||||
local tileX = tile % tilesPerRow * 8
|
||||
local tileY = math.floor(tile / tilesPerRow) * 8
|
||||
for y = 0, 7 do
|
||||
local low = raw[tile * 16 + y * 2 + 1]
|
||||
local high = raw[tile * 16 + y * 2 + 2]
|
||||
for x = 0, 7 do
|
||||
local divisor = 2 ^ (7 - x)
|
||||
local shade = math.floor(high / divisor) % 2 * 2
|
||||
+ math.floor(low / divisor) % 2
|
||||
local color = SHADES[shade + 1]
|
||||
local alpha = color[4]
|
||||
if transparent and shade == 0 then alpha = 0 end
|
||||
image:setPixel(tileX + x, tileY + y,
|
||||
color[1], color[2], color[3], alpha)
|
||||
end
|
||||
end
|
||||
end
|
||||
return image
|
||||
end
|
||||
|
||||
function ImageWriter.decode1bpp(raw, width, height, transparent)
|
||||
assertDimensions(raw, width, height, 1)
|
||||
local image = love.image.newImageData(width, height)
|
||||
local tilesPerRow = width / 8
|
||||
for tile = 0, #raw / 8 - 1 do
|
||||
local tileX = tile % tilesPerRow * 8
|
||||
local tileY = math.floor(tile / tilesPerRow) * 8
|
||||
for y = 0, 7 do
|
||||
local row = raw[tile * 8 + y + 1]
|
||||
for x = 0, 7 do
|
||||
local filled = math.floor(row / 2 ^ (7 - x)) % 2 ~= 0
|
||||
local value = filled and 0 or 1
|
||||
local alpha = 1
|
||||
if transparent and not filled then alpha = 0 end
|
||||
image:setPixel(tileX + x, tileY + y,
|
||||
value, value, value, alpha)
|
||||
end
|
||||
end
|
||||
end
|
||||
return image
|
||||
end
|
||||
|
||||
function ImageWriter.blank(width, height, r, g, b, a)
|
||||
local image = love.image.newImageData(width, height)
|
||||
image:mapPixel(function() return r or 0, g or 0, b or 0, a or 0 end)
|
||||
return image
|
||||
end
|
||||
|
||||
function ImageWriter.blit(target, source, targetX, targetY,
|
||||
sourceX, sourceY, width, height, flipX)
|
||||
sourceX, sourceY = sourceX or 0, sourceY or 0
|
||||
width, height = width or source:getWidth(), height or source:getHeight()
|
||||
for y = 0, height - 1 do
|
||||
for x = 0, width - 1 do
|
||||
local sampleX = flipX and sourceX + width - 1 - x or sourceX + x
|
||||
target:setPixel(targetX + x, targetY + y,
|
||||
source:getPixel(sampleX, sourceY + y))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ImageWriter.matteColor0(image)
|
||||
local width, height = image:getDimensions()
|
||||
local queueX, queueY, head = {}, {}, 1
|
||||
local seen = {}
|
||||
local function add(x, y)
|
||||
local key = y * width + x
|
||||
if seen[key] then return end
|
||||
local r, g, b, a = image:getPixel(x, y)
|
||||
if r == 1 and g == 1 and b == 1 and a == 1 then
|
||||
seen[key] = true
|
||||
queueX[#queueX + 1], queueY[#queueY + 1] = x, y
|
||||
end
|
||||
end
|
||||
for x = 0, width - 1 do add(x, 0); add(x, height - 1) end
|
||||
for y = 0, height - 1 do add(0, y); add(width - 1, y) end
|
||||
while head <= #queueX do
|
||||
local x, y = queueX[head], queueY[head]
|
||||
head = head + 1
|
||||
image:setPixel(x, y, 1, 1, 1, 0)
|
||||
if x > 0 then add(x - 1, y) end
|
||||
if x + 1 < width then add(x + 1, y) end
|
||||
if y > 0 then add(x, y - 1) end
|
||||
if y + 1 < height then add(x, y + 1) end
|
||||
end
|
||||
return image
|
||||
end
|
||||
|
||||
function ImageWriter.columnsToRows(raw, tilesWide, tilesHigh, bytesPerTile)
|
||||
bytesPerTile = bytesPerTile or 16
|
||||
local out = {}
|
||||
for y = 0, tilesHigh - 1 do
|
||||
for x = 0, tilesWide - 1 do
|
||||
local source = (x * tilesHigh + y) * bytesPerTile
|
||||
local target = (y * tilesWide + x) * bytesPerTile
|
||||
for offset = 1, bytesPerTile do
|
||||
out[target + offset] = raw[source + offset]
|
||||
end
|
||||
end
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
function ImageWriter.save(image, path)
|
||||
local parent = path:match("^(.*)/[^/]+$")
|
||||
if parent then
|
||||
local ok, err = love.filesystem.createDirectory(parent)
|
||||
if not ok then error("could not create " .. parent .. ": " .. tostring(err)) end
|
||||
end
|
||||
local ok, fileData = pcall(image.encode, image, "png")
|
||||
if not ok then error("could not encode " .. path .. ": " .. tostring(fileData)) end
|
||||
local written, writeError = love.filesystem.write(path, fileData)
|
||||
if not written then
|
||||
error("could not write " .. path .. ": " .. tostring(writeError))
|
||||
end
|
||||
return fileData
|
||||
end
|
||||
|
||||
return ImageWriter
|
||||
Reference in New Issue
Block a user