I wanted a way to reuse a nineslice, so I hacked it together with the existing Lua code in CoreLibs. Haven't done any testing, but it seems to be performant and works well enough for my prototyping
import 'CoreLibs/graphics'
local floor = math.floor
local newRect = playdate.geometry.rect.new
local loadImage = playdate.graphics.image.new
local newImage = playdate.graphics.image.new
local kColorClear = playdate.graphics.kColorClear
local pushContext = playdate.graphics.pushContext
local popContext = playdate.graphics.popContext
local insert = table.insert
playdate.graphics.ImageNineSlice = { }
playdate.graphics.ImageNineSlice.__index = playdate.graphics.ImageNineSlice
function playdate.graphics.ImageNineSlice.new(image, innerX, innerY, innerWidth, innerHeight)
local ns = {
innerRect = nil, -- playdate.geometry.rect
slices = nil, -- table of playdate.graphics.images
cache = nil, -- playdate.graphics.image
cacheWidth = 0,
cacheHeight = 0,
minWidth = 0,
minHeight = 0,
}
playdate.graphics.ImageNineSlice.setImage(ns, image, innerX, innerY, innerWidth, innerHeight)
setmetatable(ns, playdate.graphics.ImageNineSlice)
return ns
end
local _cache = {}
function playdate.graphics.ImageNineSlice:setImage(image, innerX, innerY, innerWidth, innerHeight) -- Other arguments are optional
if innerX ~= nil then
self.innerRect = newRect(innerX, innerY, innerWidth, innerHeight)
end
if _cache[image] == nil then
local w, h = image:getSize()
local innerX = self.innerRect.x
local innerY = self.innerRect.y
local innerWidth = self.innerRect.width
local innerHeight = self.innerRect.height
local leftWidth = innerX
local topHeight = innerY
local rightWidth = w - (innerX + innerWidth)
local bottomHeight = h - (innerY + innerHeight)
self.minWidth = leftWidth + rightWidth
self.minHeight = topHeight + bottomHeight
self.innerRect = newRect(innerX, innerY, innerWidth, innerHeight)
-- cache slices
local rects = {
0, 0, leftWidth, topHeight, -- top left
innerX, 0, innerWidth, topHeight, -- top center
innerX + innerWidth, 0, rightWidth, topHeight, -- top right
0, topHeight, leftWidth, innerHeight, -- middle left
innerX, topHeight, innerWidth, innerHeight, -- middle center
innerX + innerWidth, topHeight, rightWidth, innerHeight, -- middle right
0, topHeight + innerHeight, leftWidth, bottomHeight, -- bottom left
innerX, topHeight + innerHeight, innerWidth, bottomHeight, -- bottom center
innerX + innerWidth, topHeight + innerHeight, rightWidth, bottomHeight, -- bottom right
}
local t = #rects
local slices = {}
local slice
for i = 1, t, 4 do
slice = newImage(rects[i + 2], rects[i + 3], kColorClear)
pushContext(slice) do
image:draw(-rects[i], -rects[i + 1])
end popContext()
insert(slices, slice)
end
_cache[image] = slices
end
self.slices = _cache[image]
end
function playdate.graphics.ImageNineSlice:getSize()
return self.cacheWidth,self.cacheHeight
end
function playdate.graphics.ImageNineSlice:getMinSize()
return self.minWidth,self.minHeight
end
local function prerender(ns, width, height)
ns.cacheWidth = width
ns.cacheHeight = height
local ix,iy,iw,ih = ns.innerRect:unpack()
local mw,mh = ns.minWidth,ns.minHeight
iw = width - mw
ih = height - mh
local slices = ns.slices
local cache = newImage(width,height,kColorClear)
pushContext(cache) do
slices[1]:draw(0,0)
if iw>0 then
slices[2]:drawTiled(ix,0,iw,iy)
end
slices[3]:draw(ix+iw,0)
if ih>0 then
slices[4]:drawTiled(0,iy,ix,ih)
if iw>0 then
slices[5]:drawTiled(ix,iy,iw,ih)
end
slices[6]:drawTiled(ix+iw,iy,width-(ix+iw),ih)
end
slices[7]:draw(0,iy+ih)
if iw>0 then
slices[8]:drawTiled(ix,iy+ih,iw,height-(iy+ih))
end
slices[9]:draw(ix+iw,iy+ih)
end popContext()
ns.cache = cache
end
function playdate.graphics.ImageNineSlice:drawInRect(x, ...)
local y, w, h
if (type(x) == "userdata") then -- check if x is a playdate.geometry.rect object
x, y, w, h = x.x, x.y, x.width, x.height
else
y, w, h = select(1, ...)
end
local w = floor(w)
local h = floor(h)
if w < self.minWidth then w = self.minWidth end
if h < self.minHeight then h = self.minHeight end
if w ~= self.cacheWidth or h ~= self.cacheHeight then
prerender(self, w, h)
end
if self.cache then
self.cache:draw(x,y)
end
end