140 lines
3.4 KiB
Lua
140 lines
3.4 KiB
Lua
local zprite = require("zprite.zprite")
|
|
|
|
---@class zchunk
|
|
---@field private _chunks {integer: {z: zprite, x: integer, y: integer}}
|
|
---@field private _chunk_size integer
|
|
---@field private _chunk_height integer
|
|
---@field private _chunk_wrap integer
|
|
---@field private _texture love.Image
|
|
---@field private _height_scale number
|
|
local zchunk = {}
|
|
zchunk.__index = zchunk
|
|
|
|
---@param texture love.Image
|
|
---@param chunk_size integer?
|
|
---@param chunk_height integer?
|
|
---@param chunk_wrap integer?
|
|
function zchunk.new(texture, chunk_size, chunk_height, chunk_wrap)
|
|
chunk_size = chunk_size or 16
|
|
chunk_height = chunk_height or 32
|
|
if chunk_size < 1 then
|
|
error("chunk size must be at least 1")
|
|
end
|
|
if chunk_height < 1 then
|
|
error("chunk height must be at least 1")
|
|
end
|
|
if chunk_wrap and chunk_wrap < 1 then
|
|
error("chunk wrap must be at least 1")
|
|
end
|
|
if not texture then
|
|
error("must have a texture")
|
|
end
|
|
|
|
local obj = setmetatable({}, zchunk)
|
|
|
|
obj._chunks = {}
|
|
obj._chunk_size = chunk_size
|
|
obj._chunk_height = chunk_height
|
|
obj._chunk_wrap = chunk_wrap
|
|
|
|
obj._texture = texture
|
|
|
|
obj._height_scale = 4
|
|
|
|
return obj
|
|
end
|
|
|
|
---@param x integer
|
|
---@param y integer
|
|
---@return integer
|
|
function zchunk:_chunk_index(x, y)
|
|
local cx = math.floor(x / self._chunk_size)
|
|
local cy = math.floor(y / self._chunk_size)
|
|
if self._chunk_wrap then
|
|
cx = cx % self._chunk_wrap
|
|
cy = cy % self._chunk_wrap
|
|
end
|
|
|
|
return cx + cy * 1e7
|
|
end
|
|
|
|
---@param x integer?
|
|
---@param y integer?
|
|
function zchunk:remove(x, y)
|
|
if not x then
|
|
self._chunks = {}
|
|
else
|
|
local index = self:_chunk_index(x, y)
|
|
self._chunks[index] = nil
|
|
end
|
|
end
|
|
|
|
---@param x integer?
|
|
---@param y integer?
|
|
function zchunk:clear(x, y)
|
|
if not x then
|
|
for _, chunk in pairs(self._chunks) do
|
|
chunk.z:clear()
|
|
end
|
|
else
|
|
local index = self:_chunk_index(x, y)
|
|
if not self._chunks[index] then
|
|
return
|
|
end
|
|
self._chunks[index].z:clear()
|
|
end
|
|
end
|
|
|
|
--- Add an 'entity' to be rendered
|
|
---@param x number
|
|
---@param y number
|
|
---@param quad love.Quad
|
|
---@param layer_count integer
|
|
---@param color_map fun(layer: integer): number, number, number
|
|
---@param base_layer integer?
|
|
function zchunk:put(x, y, quad, layer_count, color_map, base_layer)
|
|
local index = self:_chunk_index(x, y)
|
|
if not self._chunks[index] then
|
|
self._chunks[index] = {
|
|
z = zprite.new(self._texture, self._chunk_size * self._chunk_size * self._chunk_height),
|
|
}
|
|
self._chunks[index].z._height_scale = self._height_scale
|
|
end
|
|
self._chunks[index].z:put(x, y, quad, layer_count, color_map, base_layer)
|
|
self._chunks[index].x = math.floor(x / self._chunk_size)
|
|
self._chunks[index].y = math.floor(y / self._chunk_size)
|
|
end
|
|
|
|
local transform = love.math.newTransform()
|
|
local function sort_fn(a, b)
|
|
local _, ay_rotated = transform:transformPoint(a.x, a.y)
|
|
local _, by_rotated = transform:transformPoint(b.x, b.y)
|
|
|
|
return ay_rotated < by_rotated
|
|
end
|
|
|
|
--- Draw to the screen / current canvas
|
|
---@overload fun(self, x: number, y: number, r: number?, sx: number?, sy: number?, ox: number?, oy: number?, kx: number?, ky: number?)
|
|
---@overload fun(self, transform: love.Transform)
|
|
function zchunk:draw(x, y, r, ...)
|
|
local chunks = {}
|
|
for _, chunk in pairs(self._chunks) do
|
|
table.insert(chunks, chunk)
|
|
end
|
|
|
|
transform:reset()
|
|
if type(x) ~= "number" then
|
|
transform:apply(x)
|
|
else
|
|
transform:rotate(r and r or 0)
|
|
end
|
|
|
|
table.sort(chunks, sort_fn)
|
|
|
|
for _, chunk in ipairs(chunks) do
|
|
chunk.z:draw(x, y, r, ...)
|
|
end
|
|
end
|
|
|
|
return zchunk
|