Skip to content

Instantly share code, notes, and snippets.

@test3211234
Last active December 8, 2024 23:07
local Magic = {}
-----------------------------------------------------FILTERS--------------------------------------------------
local function mks2013(x)
if x < 0 then
x = -x
end
if x >= 2.5 then
return 0
end
if x >= 1.5 then
return -0.125 * (x - 2.5) * (x - 2.5)
end
if x >= 0.5 then
return 0.25 * (4 * x * x - 11 * x + 7)
end
return 1.0625 - 1.75 * x * x
end
--local function lanczos3(x)
-- if x < 0 then
-- x = -x
-- end
-- if x >= 3.0 then
-- return 0
-- end
-- if x < 1.19209290E-07 then
-- return 1
-- end
-- local xPi = x * math.pi
-- return (math.sin(xPi) / xPi) * math.sin(xPi / 3) / (xPi / 3)
--end
local function toFixedPoint(num)
return math.round(num * (bit32.lshift(1, 14) - 1))
end
local function createFiltersMks(srcSize, destSize, scale)
local scaleInverted = 1 / scale
local scaleClamped = math.min(1.0, scale)
local srcWindow = 2.5 / scaleClamped
local destPixel, srcPixel, srcFirst, srcLast, filterElementSize, floatFilter, fxpFilter, total, pxl, idx, floatVal, filterTotal, filterVal
local leftNotEmpty, rightNotEmpty, filterShift, filterSize
local maxFilterElementSize = math.floor((srcWindow + 1) * 2)
local packedFilter = buffer.create(((maxFilterElementSize + 2) * destSize) * 2)
local packedFilterPtr = 0
for destPixel = 0, destSize - 1 do
srcPixel = (destPixel + 0.5) * scaleInverted
srcFirst = math.max(0, math.floor(srcPixel - srcWindow))
srcLast = math.min(srcSize - 1, math.ceil(srcPixel + srcWindow))
filterElementSize = srcLast - srcFirst + 1
floatFilter = buffer.create(filterElementSize * 4)
fxpFilter = buffer.create(filterElementSize * 2)
total = 0
for pxl = srcFirst, srcLast do
floatVal = mks2013(((pxl + 0.5) - srcPixel) * scaleClamped)
total += floatVal
buffer.writef32(floatFilter, (pxl - srcFirst) * 4, floatVal)
end
filterTotal = 0
for idx = 0, filterElementSize - 1 do
filterVal = buffer.readf32(floatFilter, idx * 4) / total
filterTotal += filterVal
buffer.writei16(fxpFilter, idx * 2, toFixedPoint(filterVal))
end
pcall(function()
buffer.writei16(fxpFilter, bit32.rshift(destSize, 1) * 2, buffer.readi16(fxpFilter, bit32.rshift(destSize, 1) * 2) + toFixedPoint(1 - filterTotal))
end)
leftNotEmpty = 0
while leftNotEmpty < filterElementSize and buffer.readi16(fxpFilter, leftNotEmpty * 2) == 0 do
leftNotEmpty += 1
end
if leftNotEmpty < filterElementSize then
rightNotEmpty = filterElementSize - 1
while rightNotEmpty > 0 and buffer.readi16(fxpFilter, rightNotEmpty * 2) == 0 do
rightNotEmpty -= 1
end
filterShift = srcFirst + leftNotEmpty
filterSize = rightNotEmpty - leftNotEmpty + 1
buffer.writei16(packedFilter, packedFilterPtr * 2, filterShift)
packedFilterPtr += 1
buffer.writei16(packedFilter, packedFilterPtr * 2, filterSize)
packedFilterPtr += 1
for idx = leftNotEmpty, rightNotEmpty do
buffer.writei16(packedFilter, packedFilterPtr * 2, buffer.readi16(fxpFilter, idx * 2))
packedFilterPtr += 1
end
else
buffer.writei16(packedFilter, packedFilterPtr * 2, 0)
packedFilterPtr += 1
buffer.writei16(packedFilter, packedFilterPtr * 2, 0)
packedFilterPtr += 1
end
end
return packedFilter
end
-----------------------------------------------------CONVOLVE-------------------------------------------------------------
local function clampNegative(i)
if i >= 0 then
return i
end
return 0
end
local function clampTo8(i)
if i < 0 then
return 0
end
if i > 255 then
return 255
end
return i
end
local function convolveHor(src, dest, srcW, srcH, destW, filters)
local r, g, b, a
local filterPtr, filterShift, filterSize
local srcPtr, srcY, destX, filterVal
local srcOffset, destOffset = 0, 0
for srcY = 0, srcH - 1 do
filterPtr = 0
for destX = 0, destW - 1 do
filterShift = buffer.readi16(filters, filterPtr * 2)
filterPtr += 1
filterSize = buffer.readi16(filters, filterPtr * 2)
filterPtr += 1
srcPtr = math.modf(srcOffset + (filterShift * 4))
r, g, b, a = 0, 0, 0, 0
for filterSize = filterSize, 1, -1 do
filterVal = buffer.readi16(filters, filterPtr * 2)
filterPtr += 1
a = math.modf(a + filterVal * buffer.readu8(src, srcPtr + 3))
b = math.modf(b + filterVal * buffer.readu8(src, srcPtr + 2))
g = math.modf(g + filterVal * buffer.readu8(src, srcPtr + 1))
r = math.modf(r + filterVal * buffer.readu8(src, srcPtr))
srcPtr = math.modf(srcPtr + 4)
end
buffer.writeu16(dest, destOffset * 2 + 6, clampNegative(bit32.rshift(a, 7)))
buffer.writeu16(dest, destOffset * 2 + 4, clampNegative(bit32.rshift(b, 7)))
buffer.writeu16(dest, destOffset * 2 + 2, clampNegative(bit32.rshift(g, 7)))
buffer.writeu16(dest, destOffset * 2, clampNegative(bit32.rshift(r, 7)))
destOffset = math.modf(destOffset + srcH * 4)
end
destOffset = math.modf((srcY + 1) * 4)
srcOffset = math.modf((srcY + 1) * srcW * 4)
end
end
local function convolveVert(src, dest, srcW, srcH, destW, filters)
local r, g, b, a
local filterPtr, filterShift, filterSize
local srcPtr, srcY, destX, filterVal
local srcOffset, destOffset = 0, 0
for srcY = 0, srcH - 1 do
filterPtr = 0
for destX = 0, destW - 1 do
filterShift = buffer.readi16(filters, filterPtr * 2)
filterPtr += 1
filterSize = buffer.readi16(filters, filterPtr * 2)
filterPtr += 1
srcPtr = math.modf(srcOffset + (filterShift * 4))
r, g, b, a = 0, 0, 0 ,0
for filterSize = filterSize, 1, -1 do
filterVal = buffer.readi16(filters, filterPtr * 2)
filterPtr += 1
a = math.modf(a + filterVal * buffer.readu16(src, srcPtr * 2 + 6))
b = math.modf(b + filterVal * buffer.readu16(src, srcPtr * 2 + 4))
g = math.modf(g + filterVal * buffer.readu16(src, srcPtr * 2 + 2))
r = math.modf(r + filterVal * buffer.readu16(src, srcPtr * 2))
srcPtr = math.modf(srcPtr + 4)
end
r = bit32.rshift(r, 7)
g = bit32.rshift(g, 7)
b = bit32.rshift(b, 7)
a = bit32.rshift(a, 7)
buffer.writeu8(dest, destOffset + 3, clampTo8(bit32.rshift(a + bit32.lshift(1, 13), 14)))
buffer.writeu8(dest, destOffset + 2, clampTo8(bit32.rshift(b + bit32.lshift(1, 13), 14)))
buffer.writeu8(dest, destOffset + 1, clampTo8(bit32.rshift(g + bit32.lshift(1, 13), 14)))
buffer.writeu8(dest, destOffset, clampTo8(bit32.rshift(r + bit32.lshift(1, 13), 14)))
destOffset = math.modf(destOffset + srcH * 4)
end
destOffset = math.modf((srcY + 1) * 4)
srcOffset = math.modf((srcY + 1) * srcW * 4)
end
end
------------------------------------------ FOR ALPHA IMAGES, NOT FOR CAT -----------------------------------------------------
local function convolveHorWithPre(src, dest, srcW, srcH, destW, filters)
local r, g, b, a, alpha
local filterPtr, filterShift, filterSize
local srcPtr, srcY, destX, filterVal
local srcOffset, destOffset = 0, 0
for srcY = 0, srcH - 1 do
filterPtr = 0
for destX = 0, destW - 1 do
filterShift = buffer.readi16(filters, filterPtr * 2)
filterPtr += 1
filterSize = buffer.readi16(filters, filterPtr * 2)
filterPtr += 1
srcPtr = math.modf(srcOffset + (filterShift * 4))
r, g, b, a = 0, 0, 0, 0
for filterSize = filterSize, 1, -1 do
filterVal = buffer.readi16(filters, filterPtr * 2)
filterPtr += 1
alpha = buffer.readu8(src, srcPtr + 3)
a = math.modf(a + filterVal * alpha)
b = math.modf(b + filterVal * buffer.readu8(src, srcPtr + 2) * alpha)
g = math.modf(g + filterVal * buffer.readu8(src, srcPtr + 1) * alpha)
r = math.modf(r + filterVal * buffer.readu8(src, srcPtr) * alpha)
srcPtr = math.modf(srcPtr + 4)
end
b = math.modf(b / 255)
g = math.modf(g / 255)
r = math.modf(r / 255)
buffer.writeu16(dest, destOffset * 2 + 6, clampNegative(bit32.rshift(a, 7)))
buffer.writeu16(dest, destOffset * 2 + 4, clampNegative(bit32.rshift(b, 7)))
buffer.writeu16(dest, destOffset * 2 + 2, clampNegative(bit32.rshift(g, 7)))
buffer.writeu16(dest, destOffset * 2, clampNegative(bit32.rshift(r, 7)))
destOffset = math.modf(destOffset + srcH * 4)
end
destOffset = math.modf((srcY + 1) * 4)
srcOffset = math.modf((srcY + 1) * srcW * 4)
end
end
local function convolveVertWithPre(src, dest, srcW, srcH, destW, filters)
local r, g, b, a
local filterPtr, filterShift, filterSize
local srcPtr, srcY, destX, filterVal
local srcOffset, destOffset = 0, 0
for srcY = 0, srcH - 1 do
filterPtr = 0
for destX = 0, destW - 1 do
filterShift = buffer.readi16(filters, filterPtr * 2)
filterPtr += 1
filterSize = buffer.readi16(filters, filterPtr * 2)
filterPtr += 1
srcPtr = math.modf(srcOffset + (filterShift * 4))
r, g, b, a = 0, 0, 0, 0
for filterSize = filterSize, 1, -1 do
filterVal = buffer.readi16(filters, filterPtr * 2)
filterPtr += 1
a = math.modf(a + filterVal * buffer.readu16(src, srcPtr * 2 + 6))
b = math.modf(b + filterVal * buffer.readu16(src, srcPtr * 2 + 4))
g = math.modf(g + filterVal * buffer.readu16(src, srcPtr * 2 + 2))
r = math.modf(r + filterVal * buffer.readu16(src, srcPtr * 2))
srcPtr = math.modf(srcPtr + 4)
end
r = bit32.rshift(r, 7)
g = bit32.rshift(g, 7)
b = bit32.rshift(b, 7)
a = bit32.rshift(a, 7)
a = clampTo8(bit32.rshift(a + bit32.lshift(1, 13), 14))
if a > 0 then
r = math.modf(r * 255 / a)
g = math.modf(g * 255 / a)
b = math.modf(b * 255 / a)
end
buffer.writeu8(dest, destOffset + 3, a)
buffer.writeu8(dest, destOffset + 2, clampTo8(bit32.rshift(b + bit32.lshift(1, 13), 14)))
buffer.writeu8(dest, destOffset + 1, clampTo8(bit32.rshift(g + bit32.lshift(1, 13), 14)))
buffer.writeu8(dest, destOffset, clampTo8(bit32.rshift(r + bit32.lshift(1, 13), 14)))
destOffset = math.modf(destOffset + srcH * 4)
end
destOffset = math.modf((srcY + 1) * 4)
srcOffset = math.modf((srcY + 1) * srcW * 4)
end
end
-------------------------------------MAIN FUNCTION---------------------------------------------------------------------
local function resetAlpha(dst, width, height)
local ptr, len = 3, math.modf(width * height * 4)
while ptr < len do
buffer.writeu8(dst, ptr, 0xFF)
ptr = math.modf(ptr + 4)
end
end
local function hasAlpha(src, width, height)
local ptr, len = 3, math.modf(width * height * 4)
while ptr < len do
if buffer.readu8(src, ptr) ~= 255 then
return true
end
ptr = math.modf(ptr + 4)
end
return false
end
function Magic:resize(src, width, height, toWidth, toHeight)
local scaleX = toWidth / width
local scaleY = toHeight / height
local dest = buffer.create(toWidth * toHeight * 4)
local filtersX = createFiltersMks(width, toWidth, scaleX)
local filtersY = createFiltersMks(height, toHeight, scaleY)
local tmp = buffer.create(toWidth * height * 4 * 2)
if hasAlpha(src, width, height) then
convolveHorWithPre(src, tmp, width, height, toWidth, filtersX)
convolveVertWithPre(tmp, dest, height, toWidth, toHeight, filtersY)
else
convolveHor(src, tmp, width, height, toWidth, filtersX)
convolveVert(tmp, dest, height, toWidth, toHeight, filtersY)
resetAlpha(dest, toWidth, toHeight)
end
return dest
end
return Magic
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment