---- Texture atlas complement for the Simple Tiled Implementation -- @copyright 2022 -- @author Eduardo Hernández coz.eduardo.hernandez@gmail.com -- @license MIT/X11 local module = {} --- Create a texture atlas -- @param files Array with filenames -- @param sort If "size" will sort by size, or if "id" will sort by id -- @param ids Array with ids of each file -- @param pow2 If true, will force a power of 2 size function module.Atlas( files, sort, ids, pow2 ) local function Node(x, y, w, h) return {x = x, y = y, w = w, h = h} end local function nextpow2( n ) local res = 1 while res <= n do res = res * 2 end return res end local function loadImgs() local images = {} for i = 1, #files do images[i] = {} --images[i].name = files[i] if ids then images[i].id = ids[i] end images[i].img = love.graphics.newImage( files[i] ) images[i].w = images[i].img:getWidth() images[i].h = images[i].img:getHeight() images[i].area = images[i].w * images[i].h end if sort == "size" or sort == "id" then table.sort( images, function( a, b ) return ( a.area > b.area ) end ) end return images end --TODO: understand this func local function add(root, id, w, h) if root.left or root.right then if root.left then local node = add(root.left, id, w, h) if node then return node end end if root.right then local node = add(root.right, id, w, h) if node then return node end end return nil end if w > root.w or h > root.h then return nil end local _w, _h = root.w - w, root.h - h if _w <= _h then root.left = Node(root.x + w, root.y, _w, h) root.right = Node(root.x, root.y + h, root.w, _h) else root.left = Node(root.x, root.y + h, w, _h) root.right = Node(root.x + w, root.y, _w, root.h) end root.w = w root.h = h root.id = id return root end local function unmap(root) if not root then return {} end local tree = {} if root.id then tree[root.id] = {} tree[root.id].x, tree[root.id].y = root.x, root.y end local left = unmap(root.left) local right = unmap(root.right) for k, v in pairs(left) do tree[k] = {} tree[k].x, tree[k].y = v.x, v.y end for k, v in pairs(right) do tree[k] = {} tree[k].x, tree[k].y = v.x, v.y end return tree end local function bake() local images = loadImgs() local root = {} local w, h = images[1].w, images[1].h if pow2 then if w % 1 == 0 then w = nextpow2(w) end if h % 1 == 0 then h = nextpow2(h) end end repeat local node root = Node(0, 0, w, h) for i = 1, #images do node = add(root, i, images[i].w, images[i].h) if not node then break end end if not node then if h <= w then if pow2 then h = h * 2 else h = h + 1 end else if pow2 then w = w * 2 else w = w + 1 end end else break end until false local limits = love.graphics.getSystemLimits() if w > limits.texturesize or h > limits.texturesize then return "Resulting texture is too large for this system" end local coords = unmap(root) local map = love.graphics.newCanvas(w, h) love.graphics.setCanvas( map ) -- love.graphics.clear() for i = 1, #images do love.graphics.draw(images[i].img, coords[i].x, coords[i].y) if ids then coords[i].id = images[i].id end end love.graphics.setCanvas() if sort == "ids" then table.sort( coords, function( a, b ) return ( a.id < b.id ) end ) end return { image = map, coords = coords } end return bake() end return module