You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
love2d-tank/libs/sti/utils.lua

222 lines
4.7 KiB

4 months ago
-- Some utility functions that shouldn't be exposed.
local utils = {}
-- https://github.com/stevedonovan/Penlight/blob/master/lua/pl/path.lua#L286
function utils.format_path(path)
2 months ago
local np_gen1, np_gen2 = "[^SEP]+SEP%.%.SEP?", "SEP+%.?SEP"
local np_pat1, np_pat2 = np_gen1:gsub("SEP", "/"), np_gen2:gsub("SEP", "/")
4 months ago
local k
repeat -- /./ -> /
2 months ago
path, k = path:gsub(np_pat2, "/", 1)
4 months ago
until k == 0
repeat -- A/../ -> (empty)
2 months ago
path, k = path:gsub(np_pat1, "", 1)
4 months ago
until k == 0
2 months ago
if path == "" then
path = "."
end
4 months ago
return path
end
-- Compensation for scale/rotation shift
function utils.compensate(tile, tileX, tileY, tileW, tileH)
local compx = 0
local compy = 0
2 months ago
if tile.sx < 0 then
compx = tileW
end
if tile.sy < 0 then
compy = tileH
end
4 months ago
if tile.r > 0 then
tileX = tileX + tileH - compy
tileY = tileY + tileH + compx - tileW
elseif tile.r < 0 then
tileX = tileX + compy
tileY = tileY - compx + tileH
else
tileX = tileX + compx
tileY = tileY + compy
end
return tileX, tileY
end
-- Cache images in main STI module
function utils.cache_image(sti, path, image)
image = image or love.graphics.newImage(path)
image:setFilter("nearest", "nearest")
sti.cache[path] = image
end
-- We just don't know.
function utils.get_tiles(imageW, tileW, margin, spacing)
2 months ago
imageW = imageW - margin
4 months ago
local n = 0
while imageW >= tileW do
imageW = imageW - tileW
2 months ago
if n ~= 0 then
imageW = imageW - spacing
end
if imageW >= 0 then
n = n + 1
end
4 months ago
end
return n
end
-- Decompress tile layer data
function utils.get_decompressed_data(data)
2 months ago
local ffi = require("ffi")
local d = {}
4 months ago
local decoded = ffi.cast("uint32_t*", data)
for i = 0, data:len() / ffi.sizeof("uint32_t") do
table.insert(d, tonumber(decoded[i]))
end
return d
end
-- Convert a Tiled ellipse object to a LOVE polygon
function utils.convert_ellipse_to_polygon(x, y, w, h, max_segments)
local ceil = math.ceil
2 months ago
local cos = math.cos
local sin = math.sin
4 months ago
local function calc_segments(segments)
local function vdist(a, b)
local c = {
x = a.x - b.x,
y = a.y - b.y,
}
return c.x * c.x + c.y * c.y
end
segments = segments or 64
local vertices = {}
2 months ago
local v = { 1, 2, ceil(segments / 4 - 1), ceil(segments / 4) }
4 months ago
local m
if love and love.physics then
m = love.physics.getMeter()
else
m = 32
end
for _, i in ipairs(v) do
local angle = (i / segments) * math.pi * 2
2 months ago
local px = x + w / 2 + cos(angle) * w / 2
local py = y + h / 2 + sin(angle) * h / 2
4 months ago
table.insert(vertices, { x = px / m, y = py / m })
end
local dist1 = vdist(vertices[1], vertices[2])
local dist2 = vdist(vertices[3], vertices[4])
-- Box2D threshold
if dist1 < 0.0025 or dist2 < 0.0025 then
2 months ago
return calc_segments(segments - 2)
4 months ago
end
return segments
end
local segments = calc_segments(max_segments)
local vertices = {}
table.insert(vertices, { x = x + w / 2, y = y + h / 2 })
for i = 0, segments do
local angle = (i / segments) * math.pi * 2
2 months ago
local px = x + w / 2 + cos(angle) * w / 2
local py = y + h / 2 + sin(angle) * h / 2
4 months ago
table.insert(vertices, { x = px, y = py })
end
return vertices
end
function utils.rotate_vertex(map, vertex, x, y, cos, sin, oy)
if map.orientation == "isometric" then
2 months ago
x, y = utils.convert_isometric_to_screen(map, x, y)
4 months ago
vertex.x, vertex.y = utils.convert_isometric_to_screen(map, vertex.x, vertex.y)
end
vertex.x = vertex.x - x
vertex.y = vertex.y - y
2 months ago
return x + cos * vertex.x - sin * vertex.y, y + sin * vertex.x + cos * vertex.y - (oy or 0)
4 months ago
end
--- Project isometric position to cartesian position
function utils.convert_isometric_to_screen(map, x, y)
2 months ago
local mapW = map.width
local tileW = map.tilewidth
local tileH = map.tileheight
local tileX = x / tileH
local tileY = y / tileH
4 months ago
local offsetX = mapW * tileW / 2
2 months ago
return (tileX - tileY) * tileW / 2 + offsetX, (tileX + tileY) * tileH / 2
4 months ago
end
function utils.hex_to_color(hex)
if hex:sub(1, 1) == "#" then
hex = hex:sub(2)
end
return {
r = tonumber(hex:sub(1, 2), 16) / 255,
g = tonumber(hex:sub(3, 4), 16) / 255,
2 months ago
b = tonumber(hex:sub(5, 6), 16) / 255,
4 months ago
}
end
function utils.pixel_function(_, _, r, g, b, a)
local mask = utils._TC
2 months ago
if r == mask.r and g == mask.g and b == mask.b then
4 months ago
return r, g, b, 0
end
return r, g, b, a
end
function utils.fix_transparent_color(tileset, path)
local image_data = love.image.newImageData(path)
tileset.image = love.graphics.newImage(image_data)
if tileset.transparentcolor then
utils._TC = utils.hex_to_color(tileset.transparentcolor)
image_data:mapPixel(utils.pixel_function)
tileset.image = love.graphics.newImage(image_data)
end
end
function utils.deepCopy(t)
local copy = {}
2 months ago
for k, v in pairs(t) do
4 months ago
if type(v) == "table" then
v = utils.deepCopy(v)
end
copy[k] = v
end
return copy
end
return utils