2013-02-16 18:53:09 +00:00
|
|
|
-- "Extended" math module for Lunatic.
|
|
|
|
|
|
|
|
local ffi = require("ffi")
|
|
|
|
|
|
|
|
local bit = require("bit")
|
|
|
|
local math = require("math")
|
|
|
|
|
2013-02-16 18:53:24 +00:00
|
|
|
local geom = require("geom")
|
|
|
|
|
2013-02-16 18:53:09 +00:00
|
|
|
local assert = assert
|
|
|
|
|
|
|
|
|
|
|
|
module(...)
|
|
|
|
|
|
|
|
|
|
|
|
local BANG2RAD = math.pi/1024
|
|
|
|
local isintab = ffi.new("int16_t [?]", 2048)
|
|
|
|
local dsintab = ffi.new("double [?]", 2048)
|
|
|
|
|
|
|
|
for a=0,511 do
|
|
|
|
local s = math.sin(a*BANG2RAD)
|
|
|
|
isintab[a] = 16384*s
|
|
|
|
dsintab[a] = s
|
|
|
|
end
|
|
|
|
|
|
|
|
isintab[512] = 16384
|
|
|
|
dsintab[512] = 1
|
|
|
|
|
|
|
|
for i=513,1023 do
|
|
|
|
isintab[i] = isintab[1024-i];
|
|
|
|
dsintab[i] = dsintab[1024-i];
|
|
|
|
end
|
|
|
|
|
|
|
|
for i=1024,2047 do
|
|
|
|
isintab[i] = -isintab[i-1024];
|
|
|
|
dsintab[i] = -dsintab[i-1024];
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local band = bit.band
|
|
|
|
|
|
|
|
local function ksc_common(ang)
|
|
|
|
ang = band(ang, 2047)
|
|
|
|
assert(ang < 2048+0ULL) -- might have been passed NaN
|
|
|
|
return ang
|
|
|
|
end
|
|
|
|
|
|
|
|
-- k{sin,cos}: 16384-scaled output, 2048-based angle input
|
|
|
|
function ksin(ang)
|
|
|
|
return isintab[ksc_common(ang)]
|
|
|
|
end
|
|
|
|
|
|
|
|
function kcos(ang)
|
|
|
|
return isintab[ksc_common(ang+512)]
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local sin, cos = math.sin, math.cos
|
|
|
|
|
|
|
|
-- {sin,cos}b: [-1..1] output, 2048-based angle input
|
|
|
|
function sinb(ang)
|
|
|
|
return dsintab[ksc_common(ang)]
|
|
|
|
end
|
|
|
|
|
|
|
|
function cosb(ang)
|
|
|
|
return dsintab[ksc_common(ang+512)]
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- Approximations to 2D and 3D Euclidean distances (also see common.c)
|
|
|
|
local abs = math.abs
|
|
|
|
local arshift = bit.arshift
|
|
|
|
|
|
|
|
local function dist_common(pos1, pos2)
|
|
|
|
local x = abs(pos1.x - pos2.x)
|
|
|
|
local y = abs(pos1.y - pos2.y)
|
|
|
|
if (x < y) then
|
|
|
|
x, y = y, x
|
|
|
|
end
|
|
|
|
return x, y
|
|
|
|
end
|
|
|
|
|
|
|
|
function ldist(pos1, pos2)
|
|
|
|
local x, y = dist_common(pos1, pos2)
|
|
|
|
|
|
|
|
local t = y + arshift(y,1)
|
|
|
|
return x - arshift(x,5) - arshift(x,7) + arshift(t,2) + arshift(t,6)
|
|
|
|
end
|
|
|
|
|
|
|
|
function dist(pos1, pos2)
|
|
|
|
local x, y = dist_common(pos1, pos2)
|
|
|
|
local z = abs(arshift(pos1.z - pos2.z, 4))
|
|
|
|
|
|
|
|
if (x < z) then
|
|
|
|
x, z = z, x
|
|
|
|
end
|
|
|
|
|
|
|
|
local t = y + z
|
|
|
|
return x - arshift(x,4) + arshift(t,2) + arshift(t,3)
|
|
|
|
end
|
2013-02-16 18:53:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
-- Point rotation. Note the different order of arguments from engine function.
|
|
|
|
-- XXX: passing mixed vec2/vec3 is problematic. Get rid of geom.vec2?
|
|
|
|
-- <ang>: BUILD angle (0-2047 based)
|
|
|
|
function rotate(pos, pivot, ang)
|
|
|
|
local p = geom.tovec3(pos)-pivot
|
|
|
|
local c, s = cosb(ang), sinb(ang)
|
|
|
|
p.x = pivot.x + (c*p.x - s*p.y)
|
|
|
|
p.y = pivot.y + (c*p.y + s*p.x)
|
|
|
|
return p
|
|
|
|
end
|