From 885036a6a38f52218527a2bc0ff637f0f48d69e9 Mon Sep 17 00:00:00 2001 From: helixhorned Date: Fri, 28 Jun 2013 14:07:41 +0000 Subject: [PATCH] Lunatic: retire 'geom' module, putting vector types into xmath. git-svn-id: https://svn.eduke32.com/eduke32@3909 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/Makefile | 1 - polymer/eduke32/source/lunatic/control.lua | 43 ++-- polymer/eduke32/source/lunatic/defs.ilua | 2 - .../eduke32/source/lunatic/defs_common.lua | 4 +- polymer/eduke32/source/lunatic/dynsymlist | 1 - polymer/eduke32/source/lunatic/geom.lua | 208 ----------------- polymer/eduke32/source/lunatic/lunacon.lua | 13 +- .../eduke32/source/lunatic/m32/compinside.lua | 4 +- .../eduke32/source/lunatic/m32/randwalk.lua | 6 +- polymer/eduke32/source/lunatic/test.elua | 10 +- .../source/lunatic/test/test_dists.lua | 5 +- .../eduke32/source/lunatic/test/test_geom.lua | 10 +- polymer/eduke32/source/lunatic/xmath.lua | 215 +++++++++++++++++- 13 files changed, 257 insertions(+), 265 deletions(-) delete mode 100644 polymer/eduke32/source/lunatic/geom.lua diff --git a/polymer/eduke32/Makefile b/polymer/eduke32/Makefile index afe30ecbe..d2cf10bfe 100644 --- a/polymer/eduke32/Makefile +++ b/polymer/eduke32/Makefile @@ -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 \ diff --git a/polymer/eduke32/source/lunatic/control.lua b/polymer/eduke32/source/lunatic/control.lua index 9df5a351b..9a0c85626 100644 --- a/polymer/eduke32/source/lunatic/control.lua +++ b/polymer/eduke32/source/lunatic/control.lua @@ -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 diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index 289f4c643..878df0df3 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -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"), diff --git a/polymer/eduke32/source/lunatic/defs_common.lua b/polymer/eduke32/source/lunatic/defs_common.lua index c12787f15..ec07d7a53 100644 --- a/polymer/eduke32/source/lunatic/defs_common.lua +++ b/polymer/eduke32/source/lunatic/defs_common.lua @@ -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") diff --git a/polymer/eduke32/source/lunatic/dynsymlist b/polymer/eduke32/source/lunatic/dynsymlist index ea9140c0c..46d8ba56e 100644 --- a/polymer/eduke32/source/lunatic/dynsymlist +++ b/polymer/eduke32/source/lunatic/dynsymlist @@ -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; diff --git a/polymer/eduke32/source/lunatic/geom.lua b/polymer/eduke32/source/lunatic/geom.lua deleted file mode 100644 index de4d9ba71..000000000 --- a/polymer/eduke32/source/lunatic/geom.lua +++ /dev/null @@ -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 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(), 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 , nil --- if retpoint_p evaluates to a non-true value, coefficients cv and cw such that --- 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 diff --git a/polymer/eduke32/source/lunatic/lunacon.lua b/polymer/eduke32/source/lunatic/lunacon.lua index 8784c3061..2d92cfb15 100644 --- a/polymer/eduke32/source/lunatic/lunacon.lua +++ b/polymer/eduke32/source/lunatic/lunacon.lua @@ -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 diff --git a/polymer/eduke32/source/lunatic/m32/compinside.lua b/polymer/eduke32/source/lunatic/m32/compinside.lua index 84c30ee53..63dca9ca1 100644 --- a/polymer/eduke32/source/lunatic/m32/compinside.lua +++ b/polymer/eduke32/source/lunatic/m32/compinside.lua @@ -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 diff --git a/polymer/eduke32/source/lunatic/m32/randwalk.lua b/polymer/eduke32/source/lunatic/m32/randwalk.lua index 5b36688fd..506e52543 100644 --- a/polymer/eduke32/source/lunatic/m32/randwalk.lua +++ b/polymer/eduke32/source/lunatic/m32/randwalk.lua @@ -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) diff --git a/polymer/eduke32/source/lunatic/test.elua b/polymer/eduke32/source/lunatic/test.elua index 851d620cd..1c0b3bc26 100644 --- a/polymer/eduke32/source/lunatic/test.elua +++ b/polymer/eduke32/source/lunatic/test.elua @@ -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 } diff --git a/polymer/eduke32/source/lunatic/test/test_dists.lua b/polymer/eduke32/source/lunatic/test/test_dists.lua index dc3ec5b96..7ed3d9520 100755 --- a/polymer/eduke32/source/lunatic/test/test_dists.lua +++ b/polymer/eduke32/source/lunatic/test/test_dists.lua @@ -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 diff --git a/polymer/eduke32/source/lunatic/test/test_geom.lua b/polymer/eduke32/source/lunatic/test/test_geom.lua index f4d861ddd..2112e2ecf 100755 --- a/polymer/eduke32/source/lunatic/test/test_geom.lua +++ b/polymer/eduke32/source/lunatic/test/test_geom.lua @@ -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 diff --git a/polymer/eduke32/source/lunatic/xmath.lua b/polymer/eduke32/source/lunatic/xmath.lua index 83823241a..6181350a7 100644 --- a/polymer/eduke32/source/lunatic/xmath.lua +++ b/polymer/eduke32/source/lunatic/xmath.lua @@ -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 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(), 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? -- : 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 , nil +-- if retpoint_p evaluates to a non-true value, coefficients cv and cw such that +-- 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