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.