You can always use a wrapper that keeps track of the matrix.
Code: Select all
local lgorigin = love.graphics.origin
local lgscale = love.graphics.scale
local lgrotate = love.graphics.rotate
local lgshear = love.graphics.shear
local lgtranslate = love.graphics.translate
-- The implicit third row is always 0, 0, 1
local matrix = {1,0,0,
0,1,0}
local function getMatrix(t)
if t == nil then
-- Return a copy
return {matrix[ 1], matrix[ 2], matrix[ 3],
matrix[ 4], matrix[ 5], matrix[ 6]}
end
-- Assign the elements (enables reusing tables)
-- (unrolled loop)
t[1] = matrix[1]; t[2] = matrix[2]; t[3] = matrix[3]
t[4] = matrix[4]; t[5] = matrix[5]; t[6] = matrix[6]
return t
end
local function origin()
matrix[1] = 1 matrix[2] = 0 matrix[3] = 0
matrix[4] = 0 matrix[5] = 1 matrix[6] = 0
lgorigin()
end
local function scale(x, y)
matrix[1] = matrix[1] * x; matrix[2] = matrix[2] * y
matrix[4] = matrix[4] * x; matrix[5] = matrix[5] * y
lgscale(x, y)
end
local function rotate(a)
local c, s = math.cos(a), math.sin(a)
matrix[1], matrix[2] = matrix[1]*c + matrix[2]*s, matrix[1]*-s + matrix[2]*c
matrix[4], matrix[5] = matrix[4]*c + matrix[5]*s, matrix[4]*-s + matrix[5]*c
lgrotate(a)
end
local function shear(x, y)
matrix[1], matrix[2] = matrix[1] + matrix[2]*y, matrix[1]*x + matrix[2]
matrix[4], matrix[5] = matrix[4] + matrix[5]*y, matrix[4]*x + matrix[5]
lgshear(x, y)
end
local function translate(x, y)
matrix[3] = matrix[3] + matrix[1]*x + matrix[2]*y
matrix[6] = matrix[6] + matrix[4]*x + matrix[5]*y
lgtranslate(x, y)
end
local function xform(matrix, x, y)
return matrix[1]*x + matrix[2]*y + matrix[3], matrix[4]*x + matrix[5]*y + matrix[6]
end
local function xformBack(matrix, x, y)
x, y = x - matrix[3], y - matrix[6]
local det = matrix[1] * matrix[5] - matrix[2] * matrix[4]
if det ~= 0 then
return (matrix[5] * x - matrix[2] * y) / det,
(matrix[1] * y - matrix[4] * x) / det
end
-- The transform is 1D or 0D
return x, y
end
return {getMatrix=getMatrix, xform = xform, xformBack = xformBack, origin=origin,
scale=scale, rotate=rotate, shear=shear, translate=translate}
Inverting the matrix is left as an exercise to the reader
Removed the unnecessary generic matrix calculations from the above, leaving only the strictly necessary part, and used a 2D matrix to add the backward transform, now called xformBack.
Example:
Code: Select all
local xform = require('xform')
local matrix
function love.draw()
xform.origin()
love.graphics.setColor(255,255,255)
xform.translate(400,300)
xform.rotate(0.3)
xform.scale(0.7, 1.1)
xform.translate(42, 86)
xform.rotate(0.5)
xform.shear(1.7, 1.3)
matrix = xform.getMatrix()
love.graphics.rectangle("fill", 5, 9, 53, 31)
xform.origin()
love.graphics.setColor(255,0,0)
local x, y = xform.xform(matrix, 5, 9)
love.graphics.rectangle("fill", x-1, y-1, 3, 3)
x, y = xform.xform(matrix, 5+52, 9)
love.graphics.rectangle("fill", x-1, y-1, 3, 3)
x, y = xform.xform(matrix, 5, 9+30)
love.graphics.rectangle("fill", x-1, y-1, 3, 3)
x, y = xform.xform(matrix, 5+52, 9+30)
love.graphics.rectangle("fill", x-1, y-1, 3, 3)
x, y = xform.xformBack(matrix, xform.xform(matrix, 5, 3))
love.graphics.print(string.format("%.17g\t%.17g\t%s", x, y, "<- should be 5, 3"))
end
Remember to always call xform.origin() at the beginning of love.draw() to reset the matrix, because the default love.run calls love.graphics.origin() internally right before calling love.draw().
Edit: Modified so you can also do this hack if you want:
Code: Select all
local xform = require 'xform'
do
local lg = love.graphics
lg.translate = xform.translate
lg.rotate = xform.rotate
lg.scale = xform.scale
lg.shear = xform.shear
lg.origin = xform.origin
end
so that your program can access any transformation function transparently, and you don't need to call xform.origin() manually at the start.
Edit2: Simplified and added backwards transform.