Redo transparency ordering

This commit is contained in:
shylie 2025-07-23 06:52:56 -04:00
parent 071b00d922
commit ace6a3cea9
2 changed files with 55 additions and 60 deletions

View File

@ -4,7 +4,7 @@ local zprite = require("zprite.zprite")
---@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 _chunk_wrap integer?
---@field private _texture love.Image
---@field private _height_scale number
local zchunk = {}
@ -96,7 +96,7 @@ 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),
z = zprite.new(self._texture, self._chunk_size * self._chunk_size),
}
self._chunks[index].z._height_scale = self._height_scale
end
@ -105,34 +105,19 @@ function zchunk:put(x, y, quad, layer_count, color_map, base_layer)
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
function zchunk:draw(...)
zprite._set_shader(self._height_scale)
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, ...)
for i = 1, self._chunk_height do
for _, chunk in pairs(self._chunks) do
chunk.z:_upload()
if chunk.z._instances[i] then
love.graphics.drawInstanced(chunk.z._meshes[i], #chunk.z._instances[i] / 3, ...)
end
end
end
end

View File

@ -1,13 +1,12 @@
---@class zprite
---@field private _texture love.Image
---@field private _instance_vertex_count integer
---@field private _mesh love.Mesh
---@field private _instance_buffer love.Buffer
---@field private _meshes love.Mesh[]
---@field private _instance_buffers love.Buffer[]
---@field private _instances {integer: {}[]}
---@field private _top_layer integer
---@field private _height_scale number
---@field private _changed boolean
---@field private _count integer
local zprite = {}
zprite.__index = zprite
@ -74,44 +73,26 @@ function zprite.new(texture, max_instances)
error("max_instances must be at least 1")
end
local tw, th = texture:getPixelDimensions()
local vertices = {
{ 0, 0, 0, 0 },
{ 1, 0, 1 / tw, 0 },
{ 0, 1, 0, 1 / th },
{ 1, 1, 1 / tw, 1 / th },
}
local obj = setmetatable({}, zprite)
obj._texture = texture
obj._instance_vertex_count = max_instances or 16384
obj._mesh = love.graphics.newMesh({
{ name = "VertexPosition", format = "floatvec2", location = 0 },
{ name = "VertexTexCoord", format = "floatvec2", location = 1 },
}, vertices, "strip", "static")
obj._mesh:setTexture(texture)
obj._instance_buffer = love.graphics.newBuffer({
{ name = "InstanceData", format = "uint32vec3", location = 3 },
}, obj._instance_vertex_count, { vertex = true })
obj._instance_vertex_count = max_instances or 1024
obj._meshes = {}
obj._instances = {}
obj._instance_buffers = {}
obj._height_scale = 4
obj._changed = false
obj._mesh:attachAttribute(3, obj._instance_buffer, "perinstance")
obj._top_layer = 0
obj._count = 0
return obj
end
--- Clear all drawn objects
function zprite:clear()
-- no need to set _changed to true, as #self._instances will be 0
self._changed = true
self._instances = {}
self._top_layer = 0
self._count = 0
end
--- Add an 'entity' to be rendered
@ -183,8 +164,9 @@ function zprite:put(x, y, quad, layer_count, color_map, base_layer)
local uv_scale = bit.bor(uv, scale)
table.insert(self._instances[i], { pos, uv_scale, layer_rgb })
self._count = self._count + 1
table.insert(self._instances[i], pos)
table.insert(self._instances[i], uv_scale)
table.insert(self._instances[i], layer_rgb)
end
end
@ -192,21 +174,49 @@ end
---@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 zprite:draw(...)
love.graphics.setShader(ZPRITE_SHADER)
ZPRITE_SHADER:send("HeightScale", self._height_scale)
zprite._set_shader(self._height_scale)
self:_upload()
for i = 1, self._top_layer do
if self._instances[i] then
love.graphics.drawInstanced(self._meshes[i], #self._instances[i] / 3, ...)
end
end
end
function zprite._set_shader(height_scale)
love.graphics.setShader(ZPRITE_SHADER)
ZPRITE_SHADER:send("HeightScale", height_scale)
end
function zprite:_upload()
if self._changed then
local current = 1
for i = 1, self._top_layer do
if self._instances[i] then
self._instance_buffer:setArrayData(self._instances[i], 1, current, #self._instances[i])
current = current + #self._instances[i]
if not self._instance_buffers[i] then
local tw, th = self._texture:getPixelDimensions()
local vertices = {
{ 0, 0, 0, 0 },
{ 1, 0, 1 / tw, 0 },
{ 0, 1, 0, 1 / th },
{ 1, 1, 1 / tw, 1 / th },
}
self._meshes[i] = love.graphics.newMesh({
{ name = "VertexPosition", format = "floatvec2", location = 0 },
{ name = "VertexTexCoord", format = "floatvec2", location = 1 },
}, vertices, "strip", "static")
self._meshes[i]:setTexture(self._texture)
self._instance_buffers[i] = love.graphics.newBuffer({
{ name = "InstanceData", format = "uint32vec3", location = 3 },
}, self._instance_vertex_count, { vertex = true })
self._meshes[i]:attachAttribute(3, self._instance_buffers[i], "perinstance")
end
self._instance_buffers[i]:setArrayData(self._instances[i], 1, 1, #self._instances[i] / 3)
end
end
self._changed = false
end
love.graphics.drawInstanced(self._mesh, self._count, ...)
end
return zprite