Add built-in chunking
This commit is contained in:
parent
cab072b4db
commit
2c0dc1efd3
32
main.lua
32
main.lua
@ -21,30 +21,30 @@ end
|
|||||||
|
|
||||||
local BIG_BLOCK = love.graphics.newQuad(24 * 9, 24 * 9, 24, 24, tex)
|
local BIG_BLOCK = love.graphics.newQuad(24 * 9, 24 * 9, 24, 24, tex)
|
||||||
|
|
||||||
local z = require("zprite").new(tex, 262144)
|
local z = require("zprite").zchunk.new(tex, 384)
|
||||||
z._height_scale = 8
|
z._height_scale = 10
|
||||||
|
|
||||||
for i = 1, 64 do
|
local function update_map()
|
||||||
for j = 1, 64 do
|
for i = -32, 32 do
|
||||||
local layers = love.math.simplexNoise(i * 0.02, j * 0.02) * 38 + 2
|
for j = -32, 32 do
|
||||||
z:put(i * 24, j * 24, BIG_BLOCK, math.floor(layers) + 1, layers < 23 and dirt_color or mountain_color)
|
local layers = love.math.simplexNoise(i * 0.02, j * 0.02) * 28 + 4
|
||||||
|
z:put(i * 24, j * 24, BIG_BLOCK, math.floor(layers) + 1, layers < 23 and dirt_color or mountain_color)
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local co = coroutine.create(update_map)
|
||||||
|
|
||||||
local angle = 0
|
local angle = 0
|
||||||
|
|
||||||
function love.update(dt)
|
function love.update(dt)
|
||||||
angle = math.fmod(angle + dt * 1.2, 2 * math.pi)
|
if coroutine.status(co) == "suspended" then
|
||||||
|
coroutine.resume(co)
|
||||||
|
end
|
||||||
|
angle = math.fmod(angle + dt * 0.8, 2 * math.pi)
|
||||||
end
|
end
|
||||||
|
|
||||||
function love.draw()
|
function love.draw()
|
||||||
z:draw(
|
z:draw(love.graphics.getWidth() / 2, love.graphics.getHeight() / 2 + 128, angle, 0.3, 0.3)
|
||||||
love.graphics.getWidth() / 2,
|
|
||||||
love.graphics.getHeight() / 2 + 64,
|
|
||||||
angle,
|
|
||||||
0.35,
|
|
||||||
0.35,
|
|
||||||
24 * 64 / 2,
|
|
||||||
24 * 64 / 2
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
171
zprite/init.lua
171
zprite/init.lua
@ -1,166 +1,9 @@
|
|||||||
---@class zprite
|
---@type zprite
|
||||||
---@field private _texture love.Image
|
local zprite = require("zprite.zprite")
|
||||||
---@field private _instance_vertex_count integer
|
---@type zchunk
|
||||||
---@field private _mesh love.Mesh
|
local zchunk = require("zprite.zchunk")
|
||||||
---@field private _instance_buffer 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
|
|
||||||
|
|
||||||
local ZPRITE_SHADER = love.graphics.newShader([[
|
return {
|
||||||
varying vec4 VsColorOut;
|
zprite = zprite,
|
||||||
|
zchunk = zchunk,
|
||||||
#ifdef VERTEX
|
|
||||||
layout (location = 3) attribute vec2 InstancePosition;
|
|
||||||
layout (location = 4) attribute vec2 InstanceTextureOffset;
|
|
||||||
layout (location = 5) attribute vec2 InstanceScale;
|
|
||||||
layout (location = 6) attribute float InstanceLayer;
|
|
||||||
layout (location = 7) 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({
|
|
||||||
{ 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 = "InstancePosition", format = "floatvec2", location = 3 },
|
|
||||||
{ name = "InstanceTextureOffset", format = "floatvec2", location = 4 },
|
|
||||||
{ name = "InstanceScale", format = "floatvec2", location = 5 },
|
|
||||||
{ name = "InstanceLayer", format = "float", location = 6 },
|
|
||||||
{ name = "InstanceColor", format = "floatvec4", location = 7 },
|
|
||||||
}, obj._instance_vertex_count, { vertex = true })
|
|
||||||
obj._instances = {}
|
|
||||||
obj._height_scale = 4
|
|
||||||
obj._changed = false
|
|
||||||
|
|
||||||
obj._mesh:attachAttribute(3, obj._instance_buffer, "perinstance")
|
|
||||||
obj._mesh:attachAttribute(4, obj._instance_buffer, "perinstance")
|
|
||||||
obj._mesh:attachAttribute(5, obj._instance_buffer, "perinstance")
|
|
||||||
obj._mesh:attachAttribute(6, obj._instance_buffer, "perinstance")
|
|
||||||
obj._mesh:attachAttribute(7, 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._instances = {}
|
|
||||||
self._top_layer = 0
|
|
||||||
self._count = 0
|
|
||||||
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
|
|
||||||
if not self._instances[i + base_layer] then
|
|
||||||
self._instances[i + base_layer] = {}
|
|
||||||
if i > self._top_layer then
|
|
||||||
self._top_layer = i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
table.insert(self._instances[i], { x, y, qx / tw, qy / th, qw, qh, i + base_layer, r, g, b, a })
|
|
||||||
self._count = self._count + 1
|
|
||||||
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.setShader(ZPRITE_SHADER)
|
|
||||||
ZPRITE_SHADER:send("HeightScale", self._height_scale)
|
|
||||||
|
|
||||||
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]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self._changed = false
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.drawInstanced(self._mesh, self._count, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
return zprite
|
|
||||||
|
112
zprite/zchunk.lua
Normal file
112
zprite/zchunk.lua
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
local zprite = require("zprite.zprite")
|
||||||
|
|
||||||
|
---@class zchunk
|
||||||
|
---@field private _chunks {integer: {z: zprite, x: integer, y: integer}}
|
||||||
|
---@field private _chunk_size integer
|
||||||
|
---@field private _texture love.Image
|
||||||
|
---@field private _height_scale number
|
||||||
|
local zchunk = {}
|
||||||
|
zchunk.__index = zchunk
|
||||||
|
|
||||||
|
---@param texture love.Image
|
||||||
|
---@param chunk_size integer?
|
||||||
|
function zchunk.new(texture, chunk_size)
|
||||||
|
chunk_size = chunk_size or 16
|
||||||
|
if chunk_size < 1 then
|
||||||
|
error("chunk size 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._texture = texture
|
||||||
|
|
||||||
|
obj._height_scale = 4
|
||||||
|
|
||||||
|
return obj
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param x integer
|
||||||
|
---@param y integer
|
||||||
|
---@return integer
|
||||||
|
function zchunk:_chunk_index(x, y)
|
||||||
|
return math.floor(x / self._chunk_size) + math.floor(y / self._chunk_size) * 1e7
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param x integer
|
||||||
|
---@param y integer
|
||||||
|
function zchunk:remove(x, y)
|
||||||
|
local index = self:_chunk_index(x, y)
|
||||||
|
if not self._chunks[index] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self._chunks[index] = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param x integer
|
||||||
|
---@param y integer
|
||||||
|
function zchunk:clear(x, y)
|
||||||
|
local index = self:_chunk_index(x, y)
|
||||||
|
if not self._chunks[index] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self._chunks[index].z:clear()
|
||||||
|
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(integer): number, 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 * 32),
|
||||||
|
x = math.floor(x / self._chunk_size),
|
||||||
|
y = math.floor(y / self._chunk_size),
|
||||||
|
}
|
||||||
|
self._chunks[index].z._height_scale = self._height_scale
|
||||||
|
end
|
||||||
|
self._chunks[index].z:put(x, y, quad, layer_count, color_map, base_layer)
|
||||||
|
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
|
166
zprite/zprite.lua
Normal file
166
zprite/zprite.lua
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
---@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 _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
|
||||||
|
|
||||||
|
local ZPRITE_SHADER = love.graphics.newShader([[
|
||||||
|
varying vec4 VsColorOut;
|
||||||
|
|
||||||
|
#ifdef VERTEX
|
||||||
|
layout (location = 3) attribute vec2 InstancePosition;
|
||||||
|
layout (location = 4) attribute vec2 InstanceTextureOffset;
|
||||||
|
layout (location = 5) attribute vec2 InstanceScale;
|
||||||
|
layout (location = 6) attribute float InstanceLayer;
|
||||||
|
layout (location = 7) 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("must have a texture")
|
||||||
|
end
|
||||||
|
if max_instances and max_instances < 1 then
|
||||||
|
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 = "InstancePosition", format = "floatvec2", location = 3 },
|
||||||
|
{ name = "InstanceTextureOffset", format = "floatvec2", location = 4 },
|
||||||
|
{ name = "InstanceScale", format = "floatvec2", location = 5 },
|
||||||
|
{ name = "InstanceLayer", format = "float", location = 6 },
|
||||||
|
{ name = "InstanceColor", format = "floatvec4", location = 7 },
|
||||||
|
}, obj._instance_vertex_count, { vertex = true })
|
||||||
|
obj._instances = {}
|
||||||
|
obj._height_scale = 4
|
||||||
|
obj._changed = false
|
||||||
|
|
||||||
|
obj._mesh:attachAttribute(3, obj._instance_buffer, "perinstance")
|
||||||
|
obj._mesh:attachAttribute(4, obj._instance_buffer, "perinstance")
|
||||||
|
obj._mesh:attachAttribute(5, obj._instance_buffer, "perinstance")
|
||||||
|
obj._mesh:attachAttribute(6, obj._instance_buffer, "perinstance")
|
||||||
|
obj._mesh:attachAttribute(7, 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._instances = {}
|
||||||
|
self._top_layer = 0
|
||||||
|
self._count = 0
|
||||||
|
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
|
||||||
|
if not self._instances[i + base_layer] then
|
||||||
|
self._instances[i + base_layer] = {}
|
||||||
|
if i > self._top_layer then
|
||||||
|
self._top_layer = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(self._instances[i], { x, y, qx / tw, qy / th, qw, qh, i + base_layer, r, g, b, a })
|
||||||
|
self._count = self._count + 1
|
||||||
|
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.setShader(ZPRITE_SHADER)
|
||||||
|
ZPRITE_SHADER:send("HeightScale", self._height_scale)
|
||||||
|
|
||||||
|
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]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self._changed = false
|
||||||
|
end
|
||||||
|
|
||||||
|
love.graphics.drawInstanced(self._mesh, self._count, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
return zprite
|
Loading…
x
Reference in New Issue
Block a user