diff --git a/zchunk.lua b/zchunk.lua index 5943c55..41e7f6f 100644 --- a/zchunk.lua +++ b/zchunk.lua @@ -115,7 +115,7 @@ function zchunk:draw(...) 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, ...) + love.graphics.drawInstanced(chunk.z._meshes[i], #chunk.z._instances[i] / 4, ...) end end end diff --git a/zprite.lua b/zprite.lua index 3c0171e..330fdb9 100644 --- a/zprite.lua +++ b/zprite.lua @@ -16,7 +16,7 @@ local ZPRITE_SHADER = love.graphics.newShader([[ varying vec4 VsColorOut; #ifdef VERTEX -layout (location = 3) attribute uvec3 InstanceData; +layout (location = 3) attribute uvec4 InstanceData; uniform float HeightScale; @@ -34,19 +34,25 @@ vec4 position(mat4 transform_projection, vec4 vertex_position) uint scale_y = bitfieldExtract(InstanceData.y, 26, 6); vec2 scale = vec2(scale_x, scale_y); - uint layer = bitfieldExtract(InstanceData.z, 0, 8); + uint r = bitfieldExtract(InstanceData.z, 0, 8); + uint g = bitfieldExtract(InstanceData.z, 8, 8); + uint b = bitfieldExtract(InstanceData.z, 16, 8); + uint a = bitfieldExtract(InstanceData.z, 24, 8); + vec4 color = vec4(r, g, b, a) / vec4(256, 256, 256, 256); - uint r = bitfieldExtract(InstanceData.z, 8, 8); - uint g = bitfieldExtract(InstanceData.z, 16, 8); - uint b = bitfieldExtract(InstanceData.z, 24, 8); - vec3 color = vec3(r, g, b) / vec3(256, 256, 256); + uint layer = bitfieldExtract(InstanceData.w, 0, 8); + uint offset_x = bitfieldExtract(InstanceData.w, 8, 4); + uint offset_y = bitfieldExtract(InstanceData.w, 12, 4); + vec2 offset = vec2(offset_x, offset_y) - vec2(8, 8); + + vec2 pixel_offset = offset * vec2(layer * HeightScale, layer * HeightScale) / love_ScreenSize.xy; vertex_position.xy *= scale; vertex_position.xy += position; VaryingTexCoord.xy *= scale; VaryingTexCoord.xy += uv; - VsColorOut = vec4(color, 1); - return (transform_projection * vertex_position) + vec4(0, (layer * HeightScale) / love_ScreenSize.y, 0, 0); + VsColorOut = color; + return (transform_projection * vertex_position) + vec4(pixel_offset, 0, 0); } #endif @@ -60,7 +66,11 @@ vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) ]]) local function ZPRITE_DEFAULT_COLORMAP(_) - return 1, 1, 1 + return 1, 1, 1, 1 +end + +local function ZPRITE_DEFAULT_OFFSETMAP(_) + return 0, 2 end ---@param texture love.Image @@ -100,15 +110,15 @@ end ---@param y number ---@param quad love.Quad|fun(layer: integer): love.Quad ---@param layer_count integer ----@param color_map (fun(layer: integer): integer, integer, integer)? ----@param base_layer integer? -function zprite:put(x, y, quad, layer_count, color_map, base_layer) +---@param color_map (fun(layer: integer): number, number, number, number)? +---@param offset_map (fun(layer: integer): integer, integer)? +function zprite:put(x, y, quad, layer_count, color_map, offset_map) 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 + color_map = color_map and color_map or ZPRITE_DEFAULT_COLORMAP + offset_map = offset_map and offset_map or ZPRITE_DEFAULT_OFFSETMAP self._changed = true @@ -117,15 +127,13 @@ function zprite:put(x, y, quad, layer_count, color_map, base_layer) local pos = bit.bor(pos_x, pos_y) for i = 1, layer_count do - if not self._instances[i + base_layer] then - self._instances[i + base_layer] = {} + if not self._instances[i] then + self._instances[i] = {} if i > self._top_layer then self._top_layer = i end end - local layer = bit.band(i + base_layer, 0xFF) - - local r, g, b = color_map(i) + local r, g, b, a = color_map(i) if r > 1 then r = 1 end @@ -144,13 +152,20 @@ function zprite:put(x, y, quad, layer_count, color_map, base_layer) if b < 0 then b = 0 end - local rb = bit.lshift(bit.band(r * 0xFF, 0xFF), 8) - local gb = bit.lshift(bit.band(g * 0xFF, 0xFF), 16) - local bb = bit.lshift(bit.band(b * 0xFF, 0xFF), 24) + if a > 1 then + a = 1 + end + if a < 0 then + a = 0 + end + local rb = bit.lshift(bit.band(r * 0xFF, 0xFF), 0) + local gb = bit.lshift(bit.band(g * 0xFF, 0xFF), 8) + local bb = bit.lshift(bit.band(b * 0xFF, 0xFF), 16) + local ab = bit.lshift(bit.band(a * 0xFF, 0xFF), 24) - local layer_rgb = bit.bor(bit.bor(layer, rb), bit.bor(gb, bb)) + local rgba = bit.bor(rb, gb, bb, ab) - local q = type(quad) == "function" and quad(layer) or quad + local q = type(quad) == "function" and quad(i) or quad local qx, qy, qw, qh = q:getViewport() local tw, th = self._texture:getPixelDimensions() @@ -164,9 +179,18 @@ function zprite:put(x, y, quad, layer_count, color_map, base_layer) local uv_scale = bit.bor(uv, scale) + local offset_x, offset_y = offset_map(i) + local offset_x_b = bit.lshift(bit.band(offset_x - 8, 0xF), 8) + local offset_y_b = bit.lshift(bit.band(offset_y - 8, 0xF), 12) + + local layer = bit.band(i, 0xFF) + + local layer_offset = bit.bor(layer, offset_x_b, offset_y_b) + table.insert(self._instances[i], pos) table.insert(self._instances[i], uv_scale) - table.insert(self._instances[i], layer_rgb) + table.insert(self._instances[i], rgba) + table.insert(self._instances[i], layer_offset) end end @@ -180,7 +204,7 @@ function zprite:draw(...) for i = 1, self._top_layer do if self._instances[i] then - love.graphics.drawInstanced(self._meshes[i], #self._instances[i] / 3, ...) + love.graphics.drawInstanced(self._meshes[i], #self._instances[i] / 4, ...) end end end @@ -208,11 +232,11 @@ function zprite:_upload() }, vertices, "strip", "static") self._meshes[i]:setTexture(self._texture) self._instance_buffers[i] = love.graphics.newBuffer({ - { name = "InstanceData", format = "uint32vec3", location = 3 }, + { name = "InstanceData", format = "uint32vec4", 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) + self._instance_buffers[i]:setArrayData(self._instances[i], 1, 1, #self._instances[i] / 4) end end self._changed = false