Initial commit
This commit is contained in:
commit
c9e1982d1c
20
LICENSE
Normal file
20
LICENSE
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Copyright (c) 2025 shylie
|
||||||
|
|
||||||
|
This software is provided ‘as-is’, without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
32
main.lua
Normal file
32
main.lua
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
local tex = love.graphics.newImage("mrmo3x.png")
|
||||||
|
tex:setFilter("nearest", "nearest")
|
||||||
|
|
||||||
|
local function color(layer)
|
||||||
|
if layer < 27 then
|
||||||
|
return layer / 31 / 2.5, layer / 62 / 2.5, 0.1
|
||||||
|
else
|
||||||
|
return 0.05, (layer - 27) / 10 + 0.3, 0.05
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local BIG_BLOCK = love.graphics.newQuad(24 * 9, 24 * 9, 24, 24, tex)
|
||||||
|
|
||||||
|
local z = require("zprite").new(tex, 65536)
|
||||||
|
z._height_scale = 6
|
||||||
|
|
||||||
|
for i = 1, 32 do
|
||||||
|
for j = 1, 32 do
|
||||||
|
local layers = love.math.noise(i * 0.1, j * 0.1) * 20 + 12
|
||||||
|
z:put(i * 24, j * 24, BIG_BLOCK, math.floor(layers) + 1, color)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local angle = 0
|
||||||
|
|
||||||
|
function love.update(dt)
|
||||||
|
angle = math.fmod(angle + dt * 1.2, 2 * math.pi)
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.draw()
|
||||||
|
z:draw(love.graphics.getWidth() / 2, love.graphics.getHeight() / 2 + 32, angle, 0.6, 0.6, 24 * 32 / 2, 24 * 32 / 2)
|
||||||
|
end
|
150
zprite/init.lua
Normal file
150
zprite/init.lua
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
---@class zprite
|
||||||
|
---@field _texture love.Image
|
||||||
|
---@field _instance_vertex_count integer
|
||||||
|
---@field _mesh love.Mesh
|
||||||
|
---@field _instance_mesh love.Mesh
|
||||||
|
---@field _instances {}[]
|
||||||
|
---@field _height_scale number
|
||||||
|
---@field _changed boolean
|
||||||
|
local zprite = {}
|
||||||
|
zprite.__index = zprite
|
||||||
|
|
||||||
|
local ZPRITE_SHADER = love.graphics.newShader([[
|
||||||
|
varying vec4 VsColorOut;
|
||||||
|
|
||||||
|
#ifdef VERTEX
|
||||||
|
attribute vec2 InstancePosition;
|
||||||
|
attribute vec2 InstanceTextureOffset;
|
||||||
|
attribute vec2 InstanceScale;
|
||||||
|
attribute float InstanceLayer;
|
||||||
|
attribute vec4 InstanceColor;
|
||||||
|
|
||||||
|
uniform float HeightScale;
|
||||||
|
|
||||||
|
vec4 position(mat4 transform_projection, vec4 vertex_position)
|
||||||
|
{
|
||||||
|
vertex_position.xy *= InstanceScale;
|
||||||
|
vertex_position.xy += InstancePosition.xy;
|
||||||
|
vertex_position.z = InstanceLayer / 1024;
|
||||||
|
VaryingTexCoord.xy *= InstanceScale;
|
||||||
|
VaryingTexCoord.xy += InstanceTextureOffset;
|
||||||
|
VsColorOut = InstanceColor;
|
||||||
|
return (transform_projection * vertex_position) + vec4(0, (InstanceLayer * HeightScale) / love_ScreenSize.y, 0, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PIXEL
|
||||||
|
vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords)
|
||||||
|
{
|
||||||
|
vec4 texture_color = Texel(tex, texture_coords);
|
||||||
|
return texture_color * color * VsColorOut;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
]])
|
||||||
|
|
||||||
|
local function ZPRITE_DEFAULT_COLORMAP(_)
|
||||||
|
return 1, 1, 1, 1
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param texture love.Image
|
||||||
|
---@param max_instances integer?
|
||||||
|
function zprite.new(texture, max_instances)
|
||||||
|
if not texture then
|
||||||
|
error("texture cannot be nil")
|
||||||
|
end
|
||||||
|
if max_instances and max_instances < 1 then
|
||||||
|
error("max_instances cannot be less than 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(
|
||||||
|
{ { "VertexPosition", "float", 2 }, { "VertexTexCoord", "float", 2 } },
|
||||||
|
vertices,
|
||||||
|
"strip",
|
||||||
|
"static"
|
||||||
|
)
|
||||||
|
obj._mesh:setTexture(texture)
|
||||||
|
obj._instance_mesh = love.graphics.newMesh({
|
||||||
|
{ "InstancePosition", "float", 2 },
|
||||||
|
{ "InstanceTextureOffset", "float", 2 },
|
||||||
|
{ "InstanceScale", "float", 2 },
|
||||||
|
{ "InstanceLayer", "float", 1 },
|
||||||
|
{ "InstanceColor", "float", 4 },
|
||||||
|
}, obj._instance_vertex_count, nil, "dynamic")
|
||||||
|
obj._instances = {}
|
||||||
|
obj._height_scale = 4
|
||||||
|
obj._changed = false
|
||||||
|
|
||||||
|
obj._mesh:attachAttribute("InstancePosition", obj._instance_mesh, "perinstance")
|
||||||
|
obj._mesh:attachAttribute("InstanceTextureOffset", obj._instance_mesh, "perinstance")
|
||||||
|
obj._mesh:attachAttribute("InstanceScale", obj._instance_mesh, "perinstance")
|
||||||
|
obj._mesh:attachAttribute("InstanceLayer", obj._instance_mesh, "perinstance")
|
||||||
|
obj._mesh:attachAttribute("InstanceColor", obj._instance_mesh, "perinstance")
|
||||||
|
|
||||||
|
return obj
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Clear all drawn objects
|
||||||
|
function zprite:clear()
|
||||||
|
-- no need to set _changed to true, as #self._instances will be 0
|
||||||
|
self._instances = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add an 'entity' to be rendered
|
||||||
|
---@param x number
|
||||||
|
---@param y number
|
||||||
|
---@param quad love.Quad
|
||||||
|
---@param layer_count integer
|
||||||
|
---@param color_map function?
|
||||||
|
---@param base_layer integer?
|
||||||
|
function zprite:put(x, y, quad, layer_count, color_map, base_layer)
|
||||||
|
if #self._instances + layer_count > self._instance_vertex_count then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
base_layer = base_layer or 0
|
||||||
|
color_map = color_map or ZPRITE_DEFAULT_COLORMAP
|
||||||
|
|
||||||
|
self._changed = true
|
||||||
|
|
||||||
|
local qx, qy, qw, qh = quad:getViewport()
|
||||||
|
local tw, th = self._texture:getPixelDimensions()
|
||||||
|
|
||||||
|
for i = 1, layer_count do
|
||||||
|
local r, g, b, a = color_map(i)
|
||||||
|
if not a then
|
||||||
|
a = 1
|
||||||
|
end
|
||||||
|
table.insert(self._instances, { x, y, qx / tw, qy / th, qw, qh, i + base_layer, r, g, b, a })
|
||||||
|
end
|
||||||
|
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 zprite:draw(...)
|
||||||
|
love.graphics.setDepthMode("less", true)
|
||||||
|
|
||||||
|
love.graphics.setShader(ZPRITE_SHADER)
|
||||||
|
ZPRITE_SHADER:send("HeightScale", self._height_scale)
|
||||||
|
|
||||||
|
if self._changed then
|
||||||
|
self._instance_mesh:setVertices(self._instances)
|
||||||
|
self._changed = false
|
||||||
|
end
|
||||||
|
|
||||||
|
love.graphics.drawInstanced(self._mesh, #self._instances, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
return zprite
|
Loading…
x
Reference in New Issue
Block a user