Compare commits

...

7 Commits

@ -1,5 +1,6 @@
The following files:
* camera.lua
* signal.lua
* timer.lua

@ -34,6 +34,24 @@ end
local function lt(a, b) return a < b end
local function _insertionsort(array, lo, hi, less)
for i = lo+1,hi do
local k = lo
local v = array[i]
for j = i,lo+1,-1 do
local el = array[j-1]
if less(v, el) then
array[j] = el
else
k = j
break
end
end
array[k] = v
end
end
--- Sort array using Insertion Sort - O(n^2).
--
-- Provides the most basic sorting algorithm around.
@ -46,19 +64,7 @@ local function lt(a, b) return a < b end
-- less than its second argument,
-- false otherwise.
function algo.insertionsort(array, less)
less = less or lt
for i = 2,#array do
local val = array[i]
local j = i
while j > 1 and less(val, array[j-1]) do
array[j] = array[j-1]
j = j - 1
end
array[j] = val
end
_insertionsort(array, 1, #array, less or lt)
end
--- Binary search last element where
@ -133,4 +139,74 @@ function algo.bsearchr(array, what, less)
return lo + ofs
end
local function merge(array, lo, mid, hi, less, workspace)
local i, j, k
i = 1
-- Copy first half of array to auxiliary array
for j = lo,mid do
workspace[i] = array[j]
i = i + 1
end
i = 1
j = mid + 1
k = lo
while k < j and j <= hi do
local v = array[j]
local el = workspace[i]
if less(v, el) then
array[k] = v
j = j + 1
else
array[k] = el
i = i + 1
end
k = k + 1
end
-- Copy back any remaining elements of first half
for k = k,j-1 do
array[k] = workspace[i]
i = i + 1
end
end
local function mergesort(array, lo, hi, less, workspace)
if hi - lo < 72 then
_insertionsort(array, lo, hi, less)
else
local mid = floor((lo + hi)/2)
mergesort(array, lo, mid, less, workspace)
mergesort(array, mid + 1, hi, less, workspace)
merge(array, lo, mid, hi, less, workspace)
end
end
--- Array stable sort, uses Merge Sort - O(n*log(n)).
--
-- Algorithm is a slightly altered version of stable_sort(),
-- posted on Lua-L by Steve Fisher on 02 May 2013 22:10:50
-- https://lua-users.org/lists/lua-l/2013-05/msg00038.html
--
-- This implementation uses an auxiliary buffer of size O(n/2).
--
-- @tparam table array Array to be sorted.
-- @tparam[opt=operator <] function less comparison function, takes 2 arguments,
-- returns true if its first argument is
-- less than its second argument,
-- false otherwise.
-- @tparam[opt={}] table use an existing workspace buffer instead of allocating one.
function algo.stablesort(array, less, workspace)
local n = #array
less = less or lt
workspace = workspace or {}
workspace[floor((n+1)/2)] = array[1] -- preallocate some room
mergesort(array, 1, n, less, workspace)
end
return algo

@ -0,0 +1,175 @@
--- Camera management class.
--
-- This is a reworked implementation of the original camera module
-- from the hump library (https://github.com/vrld/hump).
-- See README.ACKNOWLEDGEMENT for detailed information.
--
-- @module gear.camera
-- @copyright 2010-2013 Matthias Richter
-- @copyright 2022 The DoubleFourteen Code Forge
-- @author Matthias Richter, Lorenzo Cogotti
local Camera = { smooth = {} }
Camera.__index = Camera
function Camera.smooth.none()
return function (dx, dy) return dx, dy end
end
function Camera.smooth.linear(speed)
if type(speed) ~= 'number' then
error("Invalid parameter: speed = "..tostring(speed))
end
local getDelta = love.timer.getDelta
local min = math.min
local sqrt = math.sqrt
return function (dx,dy, s)
-- normalize direction
local d = sqrt(dx*dx + dy*dy)
local dts = min((s or speed) * getDelta(), d) -- prevent overshooting the goal
if d > 0 then
dx,dy = dx/d, dy/d
end
return dx*dts, dy*dts
end
end
function Camera.smooth.damped(stiffness)
if type(stiffness) ~= 'number' then
error("Invalid parameter: stiffness = "..tostring(stiffness))
end
local getDelta = love.timer.getDelta
return function (dx,dy, s)
local dts = (s or stiffness) * getDelta()
return dx*dts, dy*dts
end
end
function Camera:new(args)
self = setmetatable(args or {}, self)
self.x = self.x or love.graphics.getWidth()/2
self.y = self.y or love.graphics.getHeight()/2
self.rot = self.rot or 0
self.scale = self.scale or 1
self.smoother = self.smoother or self.smooth.none() -- for locking, see below
return self
end
function Camera:move(dx, dy)
self.x, self.y = self.x + dx, self.y + dy
end
function Camera:zoom(mul)
self.scale = self.scale * mul
end
function Camera:attach(x,y,w,h, noclip)
x, y = x or 0, y or 0
w, h = w or love.graphics.getWidth(), h or love.graphics.getHeight()
self._sx,self._sy,self._sw,self._sh = love.graphics.getScissor()
if not noclip then
love.graphics.setScissor(x, y, w, h)
end
local cx, cy = x + w/2, y + h/2
love.graphics.push()
love.graphics.translate(cx, cy)
love.graphics.scale(self.scale)
love.graphics.rotate(self.rot)
love.graphics.translate(-self.x, -self.y)
end
function Camera:detach()
love.graphics.pop()
love.graphics.setScissor(self._sx,self._sy,self._sw,self._sh)
end
local cos, sin = math.cos, math.sin
-- world coordinates to Camera coordinates
function Camera:tocamera(x,y, ox,oy,w,h)
ox, oy = ox or 0, oy or 0
w, h = w or love.graphics.getWidth(), h or love.graphics.getHeight()
-- x,y = ((x,y) - (self.x, self.y)):rotated(self.rot) * self.scale + center
local c, s = cos(self.rot), sin(self.rot)
x, y = x - self.x, y - self.y
x, y = c*x - s*y, s*x + c*y
return x*self.scale + w/2 + ox, y*self.scale + h/2 + oy
end
-- Camera coordinates to world coordinates
function Camera:toworld(x,y, ox,oy,w,h)
ox, oy = ox or 0, oy or 0
w, h = w or love.graphics.getWidth(), h or love.graphics.getHeight()
-- x,y = (((x,y) - center) / self.scale):rotated(-self.rot) + (self.x,self.y)
local c,s = cos(-self.rot), sin(-self.rot)
x,y = (x - w/2 - ox) / self.scale, (y - h/2 - oy) / self.scale
x,y = c*x - s*y, s*x + c*y
return x+self.x, y+self.y
end
function Camera:mousepos(ox,oy,w,h)
local mx, my = love.mouse.getPosition()
return self:toworld(mx,my, ox,oy,w,h)
end
-- Camera scrolling utilities
function Camera:lockx(x, smoother, ...)
local dx, dy = (smoother or self.smoother)(x - self.x, self.y, ...)
self.x = self.x + dx
end
function Camera:locky(y, smoother, ...)
local dx, dy = (smoother or self.smoother)(self.x, y - self.y, ...)
self.y = self.y + dy
end
function Camera:lockpos(x,y, smoother, ...)
return self:move((smoother or self.smoother)(x - self.x, y - self.y, ...))
end
function Camera:lockwindow(x, y, xmin, xmax, ymin, ymax, smoother, ...)
-- Figure out displacement in Camera coordinates
x, y = self:tocamera(x,y)
local dx, dy = 0,0
if x < xmin then
dx = x - xmin
elseif x > xmax then
dx = x - xmax
end
if y < ymin then
dy = y - ymin
elseif y > ymax then
dy = y - ymax
end
-- Transform displacement to movement in world coordinates
local c, s = cos(-self.rot), sin(-self.rot)
dx, dy = (c*dx - s*dy) / self.scale, (s*dx + c*dy) / self.scale
-- Move
self:move((smoother or self.smoother)(dx,dy,...))
end
return Camera

@ -0,0 +1,58 @@
--- Utility functions to manipulate colors.
--
-- Colors are represented as RGB or RGBA, each channel
-- with values in range [0, 1].
--
-- @module gear.color
-- @copyright 2023 The DoubleFourteen Code Forge
-- @author Lorenzo Cogotti
local Color = {}
--- Darken RGB color by the specified amount.
--
-- @number r red channel
-- @number g green channel
-- @number b blue channel
-- @number amount darken factor, must be in [0,1] range.
function Color.darken(r, g, b, amount)
r = r * (1 - amount)
g = g * (1 - amount)
b = b * (1 - amount)
return r, g, b
end
--- Lighten RGB color by the specified amount.
--
-- @number r red channel
-- @number g green channel
-- @number b blue channel
-- @number amount lightening factor, must be in [0,1] range.
function Color.lighten(r, g, b, amount)
r = r + (1 - r) * amount
g = g + (1 - g) * amount
b = b + (1 - b) * amount
return r, g, b
end
--- Given two RGB colors, calculate fade by the specified amount.
--
-- @number cr first color, red channel
-- @number cg first color, green channel
-- @number cb first color, blue channel
-- @number ar second color, red channel
-- @number ag second color, green channel
-- @number ab second color, blue channel
-- @number amount fading factor, must be in [0,1] range.
function Color.fade(cr, cg, cb, ar, ag, ab, amount)
cr = cr + (ar - cr) * amount
cg = cg + (ag - cg) * amount
cb = cb + (ab - cb) * amount
return cr, cg, cb
end
return Color

@ -1,4 +1,4 @@
--- Timer utilities.
--- Signal utilities.
--
-- This is a reworked implementation of the original signal module
-- from the hump library (https://github.com/vrld/hump).
@ -7,7 +7,7 @@
-- It offers functionality to register for and publish signals.
-- Implements the Observer pattern.
--
-- @module gear.timer
-- @module gear.signal
-- @copyright 2010-2013 Matthias Richter
-- @copyright 2022 The DoubleFourteen Code Forge
-- @author Matthias Richter, Lorenzo Cogotti
@ -21,6 +21,11 @@ Signal.__index = function(self, key)
end)()
end
function Signal:new()
return setmetatable({}, self)
end
function Signal:register(s, f)
self[s][f] = f
return f
@ -46,38 +51,39 @@ function Signal:clear(...)
end
end
function Signal:emitPattern(p, ...)
function Signal:emitpattern(p, ...)
for s in pairs(self) do
if s:match(p) then self:emit(s, ...) end
end
end
function Signal:registerPattern(p, f)
function Signal:registerpattern(p, f)
for s in pairs(self) do
if s:match(p) then self:register(s, f) end
end
return f
end
function Signal:removePattern(p, ...)
function Signal:removepattern(p, ...)
for s in pairs(self) do
if s:match(p) then self:remove(s, ...) end
end
end
function Signal:clearPattern(p)
function Signal:clearpattern(p)
for s in pairs(self) do
if s:match(p) then self[s] = {} end
end
end
-- instancing
function Signal.new()
return setmetatable({}, Signal)
function Signal:clearall()
for s in pairs(self) do
self[s] = {}
end
end
-- default instance
local default = Signal.new()
local default = Signal:new()
-- module forwards calls to default instance
local module = {}

@ -194,8 +194,11 @@ __index = function(tweens, key)
end})
-- Timer instancing
function Timer.new()
return setmetatable({functions = {}, tween = Timer.tween}, Timer)
function Timer:new(args)
self = setmetatable(args or {}, self)
self.functions = {}
return self
end
return Timer

@ -10,6 +10,7 @@
local min, max = math.min, math.max
local sin, cos = math.sin, math.cos
local abs = math.abs
local atan2 = math.atan2
local sqrt = math.sqrt
local vec = {}
@ -172,28 +173,32 @@ function vec.dist3(x1,y1,z1, x2,y2,z2)
return sqrt(dx*dx + dy*dy + dz*dz)
end
--- Rotate point (px,py) around (ox,oy) by the provided
--- Rotate vector (vx,vy) around (ox,oy) by the provided
-- sine and cosine.
--
-- This function should only be used for (valuable)
-- optimization purposes.
function vec.rotatesincos(px,py, sina,cosa, ox,oy)
return ox + cosa*px - sina*py,
oy + sina*px + cosa*py
function vec.rotatesincos(vx,vy, sina,cosa, ox,oy)
return ox + cosa*vx - sina*vy,
oy + sina*vx + cosa*vy
end
--- Rotate point (px,py) around (ox,oy) about rot radians.
function vec.rotatepoint(px,py, rot, ox,oy)
--- Rotate vector (vx,vy) around (ox,oy) about rot radians.
function vec.rotate(vx,vy, rot, ox,oy)
ox = ox or 0
oy = oy or 0
local sina,cosa = sin(rot),cos(rot)
-- vec.rotatesincos(px,py, sina,cosa, ox,oy)
return ox + cosa*px - sina*py,
oy + sina*px + cosa*py
return ox + cosa*vx - sina*vy,
oy + sina*vx + cosa*vy
end
function vec.angle(x,y) return atan2(y,x) end
function vec.angleto(x1,y1, x2,y2) return atan2(y1,x1) - atan2(y2,x2) end
--- Transform world coordinates to screen coordinates.
--
-- @param x (number) World coordinate X.

Loading…
Cancel
Save