Lunatic: retire 'geom' module, putting vector types into xmath.

git-svn-id: https://svn.eduke32.com/eduke32@3909 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2013-06-28 14:07:41 +00:00
parent 7cb94070e1
commit 885036a6a3
13 changed files with 257 additions and 265 deletions

View file

@ -151,7 +151,6 @@ ifneq (0,$(LUNATIC))
GAMEOBJS+= $(OBJ)/../lpeg.a # TEMP
GAMEOBJS+= $(OBJ)/luaJIT_BC_con_lang.$o \
$(OBJ)/luaJIT_BC_lunacon.$o \
$(OBJ)/luaJIT_BC_geom.$o \
$(OBJ)/luaJIT_BC_randgen.$o \
$(OBJ)/luaJIT_BC_stat.$o \
$(OBJ)/luaJIT_BC_bitar.$o \

View file

@ -13,7 +13,6 @@ local io = require("io")
local math = require("math")
local table = require("table")
local geom = require("geom")
local bcheck = require("bcheck")
local con_lang = require("con_lang")
@ -447,6 +446,8 @@ end
local xmath = require("xmath")
local abs = math.abs
local dist, ldist = xmath.dist, xmath.ldist
local vec3, ivec3 = xmath.vec3, xmath.ivec3
local rotate = xmath.rotate
local function A_FP_ManhattanDist(ps, spr)
local distvec = ps.pos - spr^(28*256)
@ -473,15 +474,15 @@ end
local FN_DISTFUNC = {
d2 = function(s1, s2, d)
return (xmath.ldist(s1, s2) < d)
return (ldist(s1, s2) < d)
end,
d3 = function(s1, s2, d)
return (xmath.dist(s1, s2) < d)
return (dist(s1, s2) < d)
end,
z = function(s1, s2, d, zd)
return (xmath.ldist(s1, s2) < d and abs(s1.z-s2.z) < zd)
return (ldist(s1, s2) < d and abs(s1.z-s2.z) < zd)
end,
}
@ -790,10 +791,10 @@ end
-- switch statement support
function _switch(swtab, testval, aci,pli,dist)
function _switch(swtab, testval, aci,pli,dst)
local func = swtab[testval] or swtab.default
if (func) then
func(aci, pli, dist)
func(aci, pli, dst)
end
end
@ -931,7 +932,7 @@ function _A_DoGuts(i, gutstile, n)
end
for i=n,1, -1 do
local pos = geom.vec3(spr.x+krandand(255)-128, spr.y+krandand(255)-128, z-krandand(8191))
local pos = vec3(spr.x+krandand(255)-128, spr.y+krandand(255)-128, z-krandand(8191))
local j = insertsprite{ gutstile, pos, spr.sectnum, i, 5, shade=-32, xrepeat=xsz, yrepeat=ysz,
ang=krandand(2047), xvel=48+krandand(31), zvel=-512-krandand(2047) }
local newspr = sprite[j]
@ -954,7 +955,7 @@ function _debris(i, dtile, n)
for j=n-1,0, -1 do
local isblimpscrap = (ispic(spr.picnum, "BLIMP") and ispic(dtile, "SCRAP1"))
local picofs = isblimpscrap and 0 or krandand(3)
local pos = spr + geom.vec3(krandand(255)-128, krandand(255)-128, -(8*256)-krandand(8191))
local pos = spr + vec3(krandand(255)-128, krandand(255)-128, -(8*256)-krandand(8191))
local jj = insertsprite{ dtile+picofs, pos, spr.sectnum, i, 5,
shade=spr.shade, xrepeat=32+krandand(15), yrepeat=32+krandand(15),
ang=krandand(2047), xvel=32+krandand(127), zvel=-krandand(2047) }
@ -1270,7 +1271,7 @@ end
-- d is a distance
function _awayfromwall(spr, d)
local vec2 = geom.vec2
local vec2 = xmath.vec2
local vecs = { vec2(d,d), vec2(-d,-d), vec2(d,-d), vec2(-d,d) }
for i=1,4 do
if (not inside(vecs[i]+spr, spr.sectnum)) then
@ -1372,14 +1373,14 @@ end
-- CON "hitscan" command
function _hitscan(x, y, z, sectnum, vx, vy, vz, cliptype)
local srcv = geom.ivec3(x, y, z)
local srcv = ivec3(x, y, z)
local hit = hitscan(srcv, sectnum, vx, vy, vz, cliptype)
return hit.sect, hit.wall, hit.sprite, hit.pos.x, hit.pos.y, hit.pos.z
end
-- CON "neartag" command
function _neartag(x, y, z, sectnum, ang, range, tagsearch)
local pos = geom.ivec3(x, y, z)
local pos = ivec3(x, y, z)
local near = neartag(pos, sectnum, ang, range, tagsearch)
return near.sector, near.wall, near.sprite, near.dist
end
@ -1387,7 +1388,7 @@ end
-- CON "getzrange" command
function _getzrange(x, y, z, sectnum, walldist, clipmask)
check_sector_idx(sectnum)
local ipos = geom.ivec3(x, y, z)
local ipos = ivec3(x, y, z)
local hit = sector[sectnum]:zrangeat(ipos, walldist, clipmask)
-- return: ceilz, ceilhit, florz, florhit
return hit.c.z, hit.c.num + (hit.c.spritep and 49152 or 16384),
@ -1397,16 +1398,16 @@ end
-- CON "clipmove" and "clipmovenoslide" commands
function _clipmovex(x, y, z, sectnum, xv, yv, wd, cd, fd, clipmask, noslidep)
check_sector_idx(sectnum)
local ipos = geom.ivec3(x, y, z)
local ipos = ivec3(x, y, z)
local sect = ffi.new("int16_t [1]")
local ret = ffiC.clipmovex(ipos, sect, xv, yv, wd, cd, fd, clipmask, noslidep)
-- Return: clipmovex() return value; updated x, y, sectnum
return ret, ipos.x, ipos.y, sect[0]
end
function _sleepcheck(aci, dist)
function _sleepcheck(aci, dst)
local acs = actor[aci]
if (dist > MAXSLEEPDIST and acs.timetosleep == 0) then
if (dst > MAXSLEEPDIST and acs.timetosleep == 0) then
acs.timetosleep = SLEEPTIME
end
end
@ -1419,7 +1420,7 @@ end
function _movesprite(spritenum, x, y, z, cliptype)
check_sprite_idx(spritenum)
local vel = geom.ivec3(x, y, z)
local vel = ivec3(x, y, z)
return ffiC.A_MoveSprite(spritenum, vel, cliptype)
end
@ -1438,8 +1439,8 @@ local function A_CheckHitSprite(spr, angadd)
return hit.sprite, math.sqrt(dx*dx+dy*dy) -- TODO: use "ldist" approximation for authenticity
end
function _canshoottarget(dist, aci)
if (dist > 1024) then
function _canshoottarget(dst, aci)
if (dst > 1024) then
local spr = sprite[aci]
local hitspr, hitdist = A_CheckHitSprite(spr, 0)
@ -1513,9 +1514,9 @@ function _hypot(a, b)
end
function _rotatepoint(pivotx, pivoty, posx, posy, ang)
local pos = geom.ivec3(posx, posy)
local pivot = geom.ivec3(pivotx, pivoty)
pos = xmath.rotate(pos, pivot, ang):toivec3()
local pos = ivec3(posx, posy)
local pivot = ivec3(pivotx, pivoty)
pos = rotate(pos, pivot, ang):toivec3()
return pos.x, pos.y
end

View file

@ -326,7 +326,6 @@ struct {
local WEAPONDATA_STRUCT = "struct {"..table.concat(con_lang.wdata_members, ';').."; }"
local randgen = require("randgen")
local geom = require("geom")
local ma_rand = randgen.new(true) -- initialize to "random" (time-based) seed
local ma_count = nil
@ -1427,7 +1426,6 @@ local allowed_modules = {
},
randgen = randgen,
geom = geom,
stat = require("stat"),
bitar = require("bitar"),
xmath = require("xmath"),

View file

@ -246,10 +246,10 @@ if (not _LUNATIC_AUX) then
assert(ffi.alignof("palette_t")==1)
end
local vec3_ct = ffi.typeof("vec3_t") -- will be metatype'd in geom.lua:
local vec3_ct = ffi.typeof("vec3_t") -- will be metatype'd in xmath.lua:
if (not _LUNATIC_AUX) then
require("geom")
require("xmath")
end
local hitdata_ct = ffi.typeof("hitdata_t")

View file

@ -165,7 +165,6 @@ g_logoFlags;
luaJIT_BC_lunacon;
luaJIT_BC_con_lang;
luaJIT_BC_geom;
luaJIT_BC_randgen;
luaJIT_BC_stat;
luaJIT_BC_bitar;

View file

@ -1,208 +0,0 @@
-- Geometry module for Lunatic.
local require = require
local ffi = require("ffi")
local math = require("math")
local abs = math.abs
local sqrt = math.sqrt
local type = type
local error = error
module(...)
-- The integer 3-vector can be useful for calculations expecting integer
-- values, e.g. geom.ivec3(x, y, z) is a reasonable way to round a vec3. It can
-- also be used as the RHS to the vec2/vec3 arithmetic methods.
-- NOTE: We must have a typedef with that exact name, because for Lunatic
-- (i.e. not stand-alone), the type was already declared in defs_common.lua.
ffi.cdef "typedef struct { int32_t x, y, z; } vec3_t;"
local ivec3_t = ffi.typeof("vec3_t")
local dvec2_t = ffi.typeof("struct { double x, y; }")
local dvec3_t = ffi.typeof("struct { double x, y, z; }")
local vec2_mt = {
__add = function(a, b) return dvec2_t(a.x+b.x, a.y+b.y) end,
__sub = function(a, b) return dvec2_t(a.x-b.x, a.y-b.y) end,
__unm = function(a) return dvec2_t(-a.x, -a.y) end,
__mul = function(a,b)
if (type(a)=="number") then
return dvec2_t(a*b.x, a*b.y)
end
if (type(b)~="number") then
error("number expected in vec2 multiplication", 2)
end
return dvec2_t(a.x*b, a.y*b)
end,
__div = function(a,b)
if (type(b)~="number") then
error("number expected in vec2 division", 2)
end
return dvec2_t(a.x/b, a.y/b)
end,
__tostring = function(a) return "vec2("..a.x..", "..a.y..")" end,
__index = {
lensq = function(a) return a.x*a.x + a.y*a.y end,
mhlen = function(a) return abs(a.x)+abs(a.y) end,
},
}
local arshift = require("bit").arshift
-- The vec3 metatable is shared between the integer- and double-based 3-vector
-- types. However, some operations are slightly different.
local vec3_mt = {
-- Arithmetic operations. Note that they always return a dvec3.
__add = function(a, b) return dvec3_t(a.x+b.x, a.y+b.y, a.z+b.z) end,
__sub = function(a, b) return dvec3_t(a.x-b.x, a.y-b.y, a.z-b.z) end,
__unm = function(a) return dvec3_t(-a.x, -a.y, -a.z) end,
__mul = function(a,b)
if (type(a)=="number") then
return dvec3_t(a*b.x, a*b.y, a*b.z)
end
if (type(b)~="number") then
error("number expected in vec3 multiplication", 2)
end
return dvec3_t(a.x*b, a.y*b, a.z*b)
end,
__div = function(a,b)
if (type(b)~="number") then
error("number expected in vec3 division", 2)
end
return dvec3_t(a.x/b, a.y/b, a.z/b)
end,
-- '^' is the "translate upwards" operator, returns same-typed vector.
__pow = function(v, zofs)
return v:_ctor(v.x, v.y, v.z-zofs)
end,
-- XXX: Rewrite using _serialize internal API instead.
__tostring = function(a)
return (a:_isi() and "i" or "").."vec3("..a.x..", "..a.y..", "..a.z..")"
end,
__index = {
-- Euclidean 3D length.
len = function(a) return sqrt(a.x*a.x + a.y*a.y + a.z*a.z) end,
-- Euclidean 3D squared length.
lensq = function(a) return a.x*a.x + a.y*a.y + a.z*a.z end,
-- Euclidean 2D length.
len2 = function(a) return sqrt(a.x*a.x + a.y*a.y) end,
-- Euclidean 2D squared length.
len2sq = function(a) return a.x*a.x + a.y*a.y end,
-- Manhattan-distance 3D length:
mhlen = function(a) return abs(a.x)+abs(a.y)+abs(a.z) end,
toivec3 = function(v) return ivec3_t(v.x, v.y, v.z) end,
-- BUILD-coordinate (z scaled by 16) <-> uniform conversions.
touniform = function(v)
return v:_isi()
and v:_ctor(v.x, v.y, arshift(v.z, 4))
or v:_ctor(v.x, v.y, v.z/16)
end,
tobuild = function(v) return v:_ctor(v.x, v.y, 16*v.z) end,
-- PRIVATE methods --
-- Get the type constructor for this vector.
_ctor = function(v, ...)
return v:_isi() and ivec3_t(...) or dvec3_t(...)
end,
-- Is <v> integer vec3? INTERNAL.
_isi = function(v)
return ffi.istype(ivec3_t, v)
end,
},
}
ffi.metatype(dvec2_t, vec2_mt)
ffi.metatype(dvec3_t, vec3_mt)
ffi.metatype(ivec3_t, vec3_mt)
-- VEC2 user data constructor.
-- * vec2([x [, y]]), assuming that x and y are numbers. Vacant positions are
-- assumed to be 0.
-- * vec2(<compound>), <compound> can be anything indexable with "x" and "y"
function vec2(...)
local x, y = ...
if (type(x)=="number" or x==nil) then
return dvec2_t(...)
else
return dvec2_t(x.x, x.y)
end
end
-- VEC3 user data constructor.
-- Analogous to VEC2.
function vec3(...)
local x, y, z = ...
if (type(x)=="number" or x==nil) then
return dvec3_t(...)
else
return dvec3_t(x.x, x.y, x.z)
end
end
-- IVEC3 user data constructor.
function ivec3(...)
local x, y, z = ...
if (type(x)=="number" or x==nil) then
return ivec3_t(...)
else
return ivec3_t(x.x, x.y, x.z)
end
end
-- Two-element vector cross product.
-- Anti-commutative, distributive.
local function cross2(v, w)
return v.y*w.x - v.x*w.y
end
-- Finds the intersection point of two lines given by
-- point a and vector v
-- and
-- point b and vector w
--
-- Returns:
-- if <TODO>, nil
-- if retpoint_p evaluates to a non-true value, coefficients cv and cw such that <TODO>
-- else, the intersection point
function intersect(a,v, b,w, retpoint_p)
local vxw = cross2(v,w)
if (vxw ~= 0) then
local btoa = vec2(a) - vec2(b)
local cv, cw = cross2(w, btoa)/vxw, cross2(v, btoa)/vxw
if (retpoint_p) then
return vec2(a) + cv*vec2(v)
else
return cv, cw
end
end
-- return nil if v and w parallel (or either of them is a point), or if
-- they contain NaNs
end

View file

@ -179,7 +179,7 @@ local function new_initial_codetab()
-- Requires.
"local require=require",
"local _con, _bit, _math = require'con', require'bit', require'math'",
"local _xmath, _geom = require'xmath', require'geom'",
"local _xmath = require'xmath'",
-- Cache globals into locals.
"local sector, sprite, wall, spriteext, atsprite = sector, sprite, wall, spriteext, atsprite",
@ -205,7 +205,7 @@ local function new_initial_codetab()
"local _V,_A=_V,_A",
-- Static ivec3s so that no allocations need to be made.
"local _IVEC = { _geom.ivec3(), _geom.ivec3() }",
"local _IVEC = { _xmath.ivec3(), _xmath.ivec3() }",
"local function _IV(num, x, y, z)",
" local v=_IVEC[num]; v.x=x; v.y=y; v.z=z; return v;",
"end",
@ -561,7 +561,7 @@ local function parse_number(pos, numstr)
if (hex and #hex>8 and hex:sub(1,#hex-8):match("^[fF]$")) then
-- Too many hex digits, but they're all Fs.
pwarnprintf(pos, "number %s truncated to 32 bits", numstr)
num = bit.band(num, 0xffffffff)
num = bit.tobit(num)
else
perrprintf(pos, "number %s out of the range of a 32-bit integer", numstr)
-- Be careful not to write bound checks like
@ -572,7 +572,7 @@ local function parse_number(pos, numstr)
if (not hex and g_warn["number-conversion"]) then
pwarnprintf(pos, "number %s converted to a negative one", numstr)
end
num = bit.band(num, 0xffffffff)
num = bit.tobit(num)
end
-- printf("numstr:%s, num=%d (0x%s) '%s', resnum=%d (0x%s)",
@ -1807,8 +1807,9 @@ local function GetOrSetPerxvarCmd(Setp, Actorp)
local gv = g_gamevar[perxvarname]
if (gv and bit.band(gv.flags, GVFLAG.PERX_MASK)~=EXPECTED_PERX_BIT) then
-- [gs]set*var for wrong gamevar type. See if it's a getactorvar,
-- in which case we may only warn and get the global gamevar
-- (TODO_MP) instead.
-- in which case we may only warn and access that instead. Note
-- that accesses of player gamevars with actor indices are usually
-- meaningless.
local warnp = not Setp and Actorp and not g_warn["error-bad-getactorvar"]
local xprintf = warnp and warnprintf or errprintf

View file

@ -6,7 +6,7 @@ local sector = sector
local inside = inside
local math = require("math")
local geom = require("geom")
local xmath = require("xmath")
local stat = require("stat")
local function resetseed()
@ -39,7 +39,7 @@ local function getpoints(n, min, max)
for i=1,n do
local x = math.random(min.x, max.x)
local y= math.random(min.y, max.y)
posns[i] = geom.vec2(x, y)
posns[i] = xmath.vec2(x, y)
sects[i] = math.random(0, ffiC.numsectors-1)
end

View file

@ -4,7 +4,7 @@
local ffi = require "ffi"
local ffiC = ffi.C
local geom = require "geom"
local xmath = require "xmath"
local stat = require "stat"
@ -33,7 +33,7 @@ function randwalk(N, spritenum, minlen, maxlen, randofs, funci, logfn)
local times = {}
local successp = {}
local pos = geom.vec3(sprite[spritenum])
local pos = xmath.vec3(sprite[spritenum])
local sectnum = sprite[spritenum].sectnum
for i=1,N do
@ -51,7 +51,7 @@ function randwalk(N, spritenum, minlen, maxlen, randofs, funci, logfn)
local len = math.random(minlen, maxlen)
local ax, ay, az = len*math.cos(ang), len*math.sin(ang), 0
--]]
local newpos = pos + geom.ivec3(ax,ay,az)
local newpos = pos + xmath.ivec3(ax,ay,az)
local t = ffiC.gethitickms()
local newsect = updatesectorfunc(newpos, sectnum)

View file

@ -256,7 +256,7 @@ gameevent
end
}
local geom = require "geom"
local xmath = require "xmath"
gameevent
{
@ -351,12 +351,12 @@ gameevent
"must be called from top level")
-- Test vec3 + wall. Pseudo wall member 'z' will be accessed.
local mpos = geom.vec3()
local mpos = xmath.vec3()
for i=0,gv.numwalls-1 do
mpos = mpos + wall[i]
end
mpos = mpos/gv.numwalls
local impos = geom.ivec3(mpos)^20 -- test ivec3 with dvec3 arg, test '^' op
local impos = xmath.ivec3(mpos)^20 -- test ivec3 with dvec3 arg, test '^' op
assert(impos.z == -20)
printf("Map center point: (%d,%f)", mpos.x, impos.y)
end
@ -381,11 +381,11 @@ gameactor
local r = math.random
local d = 20
-- NOTE: __add metamethod is called because of the RHS:
local v = spr + geom.vec3(r(-d,d), r(-d,d))
local v = spr + xmath.vec3(r(-d,d), r(-d,d))
spr:setpos(v)
-- Test vec3 constructor with cdata.
local tempvec = geom.vec3(player[0].pos)
local tempvec = xmath.vec3(player[0].pos)
end
}

View file

@ -4,7 +4,6 @@ local ffi = require "ffi"
local math = require "math"
local os = require "os"
local geom = require "geom"
local xmath = require "xmath"
local ldist = xmath.ldist
@ -64,8 +63,8 @@ t = os.clock()
-- from control.lua (the CON version of rotatepoint)
local function _rotatepoint(pivotx, pivoty, posx, posy, ang)
local pos = geom.ivec3(posx, posy)
local pivot = geom.ivec3(pivotx, pivoty)
local pos = xmath.ivec3(posx, posy)
local pivot = xmath.ivec3(pivotx, pivoty)
pos = xmath.rotate(pos, pivot, ang):toivec3()
return pos.x, pos.y
end

View file

@ -2,7 +2,7 @@
local os = require("os")
local geom = require("geom")
local xmath = require("xmath")
local N = os.exit and (arg[1] and tostring(arg[1])) or 1e6
@ -19,7 +19,7 @@ if (os.exit) then
local math = require("math")
randvec = function()
return geom.vec2(math.random(), math.random())
return xmath.vec2(math.random(), math.random())
end
print("Running stand-alone. ourname: "..tostring(ourname))
@ -30,7 +30,7 @@ else
-- NOTE: factoring out the inner s:getdbl() into a separate function
-- reduces performance seriously (about an order of magnitude!)
randvec = function()
return geom.vec2(s:getdbl(), s:getdbl())
return xmath.vec2(s:getdbl(), s:getdbl())
end
-- Test optional arguments from our_require().
@ -62,9 +62,9 @@ end
local t3 = os.clock()
local v = geom.vec2(0, 0)
local v = xmath.vec2(0, 0)
for i=1,N do
local intersp = geom.intersect(A[i],V[i], B[i],W[i], true)
local intersp = xmath.intersect(A[i],V[i], B[i],W[i], true)
if (intersp ~= nil) then
v = v + intersp
end

View file

@ -5,14 +5,19 @@ local ffi = require("ffi")
local bit = require("bit")
local math = require("math")
local geom = require("geom")
local arshift = bit.arshift
local abs, sqrt = math.abs, math.sqrt
local assert = assert
local error = error
local type = type
module(...)
---=== TRIGONOMETRY ===---
local BANG2RAD = math.pi/1024
local isintab = ffi.new("int16_t [?]", 2048)
local dsintab = ffi.new("double [?]", 2048)
@ -67,9 +72,8 @@ function cosb(ang)
end
-- Approximations to 2D and 3D Euclidean distances (also see common.c)
local abs = math.abs
local arshift = bit.arshift
---=== Approximations to 2D and 3D Euclidean distances ===---
-- (also see common.c)
local function dist_common(pos1, pos2)
local x = abs(pos1.x - pos2.x)
@ -100,14 +104,213 @@ function dist(pos1, pos2)
end
---=== VECTOR TYPES ===---
-- The integer 3-vector can be useful for calculations expecting integer
-- values, e.g. ivec3(x, y, z) is a reasonable way to round a vec3. It can also
-- be used as the RHS to the vec2/vec3 arithmetic methods.
-- NOTE: We must have a typedef with that exact name, because for Lunatic
-- (i.e. not stand-alone), the type was already declared in defs_common.lua.
ffi.cdef "typedef struct { int32_t x, y, z; } vec3_t;"
local ivec3_t = ffi.typeof("vec3_t")
local dvec2_t = ffi.typeof("struct { double x, y; }")
local dvec3_t = ffi.typeof("struct { double x, y, z; }")
local vec2_mt = {
__add = function(a, b) return dvec2_t(a.x+b.x, a.y+b.y) end,
__sub = function(a, b) return dvec2_t(a.x-b.x, a.y-b.y) end,
__unm = function(a) return dvec2_t(-a.x, -a.y) end,
__mul = function(a,b)
if (type(a)=="number") then
return dvec2_t(a*b.x, a*b.y)
end
if (type(b)~="number") then
error("number expected in vec2 multiplication", 2)
end
return dvec2_t(a.x*b, a.y*b)
end,
__div = function(a,b)
if (type(b)~="number") then
error("number expected in vec2 division", 2)
end
return dvec2_t(a.x/b, a.y/b)
end,
__tostring = function(a) return "vec2("..a.x..", "..a.y..")" end,
__index = {
lensq = function(a) return a.x*a.x + a.y*a.y end,
mhlen = function(a) return abs(a.x)+abs(a.y) end,
},
}
-- The vec3 metatable is shared between the integer- and double-based 3-vector
-- types. However, some operations are slightly different.
local vec3_mt = {
-- Arithmetic operations. Note that they always return a dvec3.
__add = function(a, b) return dvec3_t(a.x+b.x, a.y+b.y, a.z+b.z) end,
__sub = function(a, b) return dvec3_t(a.x-b.x, a.y-b.y, a.z-b.z) end,
__unm = function(a) return dvec3_t(-a.x, -a.y, -a.z) end,
__mul = function(a,b)
if (type(a)=="number") then
return dvec3_t(a*b.x, a*b.y, a*b.z)
end
if (type(b)~="number") then
error("number expected in vec3 multiplication", 2)
end
return dvec3_t(a.x*b, a.y*b, a.z*b)
end,
__div = function(a,b)
if (type(b)~="number") then
error("number expected in vec3 division", 2)
end
return dvec3_t(a.x/b, a.y/b, a.z/b)
end,
-- '^' is the "translate upwards" operator, returns same-typed vector.
__pow = function(v, zofs)
return v:_ctor(v.x, v.y, v.z-zofs)
end,
-- XXX: Rewrite using _serialize internal API instead.
__tostring = function(a)
return (a:_isi() and "i" or "").."vec3("..a.x..", "..a.y..", "..a.z..")"
end,
__index = {
-- Euclidean 3D length.
len = function(a) return sqrt(a.x*a.x + a.y*a.y + a.z*a.z) end,
-- Euclidean 3D squared length.
lensq = function(a) return a.x*a.x + a.y*a.y + a.z*a.z end,
-- Euclidean 2D length.
len2 = function(a) return sqrt(a.x*a.x + a.y*a.y) end,
-- Euclidean 2D squared length.
len2sq = function(a) return a.x*a.x + a.y*a.y end,
-- Manhattan-distance 3D length:
mhlen = function(a) return abs(a.x)+abs(a.y)+abs(a.z) end,
toivec3 = function(v) return ivec3_t(v.x, v.y, v.z) end,
-- BUILD-coordinate (z scaled by 16) <-> uniform conversions.
touniform = function(v)
return v:_isi()
and v:_ctor(v.x, v.y, arshift(v.z, 4))
or v:_ctor(v.x, v.y, v.z/16)
end,
tobuild = function(v) return v:_ctor(v.x, v.y, 16*v.z) end,
-- TODO: v:rotate()?
-- PRIVATE methods --
-- Get the type constructor for this vector.
_ctor = function(v, ...)
return v:_isi() and ivec3_t(...) or dvec3_t(...)
end,
-- Is <v> integer vec3? INTERNAL.
_isi = function(v)
return ffi.istype(ivec3_t, v)
end,
},
}
ffi.metatype(dvec2_t, vec2_mt)
ffi.metatype(dvec3_t, vec3_mt)
ffi.metatype(ivec3_t, vec3_mt)
-- VEC2 user data constructor.
-- * vec2([x [, y]]), assuming that x and y are numbers. Vacant positions are
-- assumed to be 0.
-- * vec2(<compound>), <compound> can be anything indexable with "x" and "y"
function vec2(...)
local x, y = ...
if (type(x)=="number" or x==nil) then
return dvec2_t(...)
else
return dvec2_t(x.x, x.y)
end
end
-- VEC3 user data constructor.
-- Analogous to VEC2.
function vec3(...)
local x, y, z = ...
if (type(x)=="number" or x==nil) then
return dvec3_t(...)
else
return dvec3_t(x.x, x.y, x.z)
end
end
-- IVEC3 user data constructor.
function ivec3(...)
local x, y, z = ...
if (type(x)=="number" or x==nil) then
return ivec3_t(...)
else
return ivec3_t(x.x, x.y, x.z)
end
end
---=== MISCELLANEOUS MATH ===---
-- Point rotation. Note the different order of arguments from engine function.
-- XXX: passing mixed vec2/vec3 is problematic. Get rid of geom.vec2?
-- XXX: passing mixed vec2/vec3 is problematic. Get rid of vec2?
-- <ang>: BUILD angle (0-2047 based)
function rotate(pos, pivot, ang)
local p = geom.vec3(pos)-pivot
local p = vec3(pos)-pivot
local c, s = cosb(ang), sinb(ang)
local x, y = p.x, p.y
p.x = pivot.x + (c*x - s*y)
p.y = pivot.y + (c*y + s*x)
return p
end
-- Two-element vector cross product.
-- Anti-commutative, distributive.
local function cross2(v, w)
return v.y*w.x - v.x*w.y
end
-- Finds the intersection point of two lines given by
-- point a and vector v
-- and
-- point b and vector w
--
-- Returns:
-- if <TODO>, nil
-- if retpoint_p evaluates to a non-true value, coefficients cv and cw such that <TODO>
-- else, the intersection point
function intersect(a,v, b,w, retpoint_p)
local vxw = cross2(v,w)
if (vxw ~= 0) then
local btoa = vec2(a) - vec2(b)
local cv, cw = cross2(w, btoa)/vxw, cross2(v, btoa)/vxw
if (retpoint_p) then
return vec2(a) + cv*vec2(v)
else
return cv, cw
end
end
-- return nil if v and w parallel (or either of them is a point), or if
-- they contain NaNs
end