Lunatic: retire per-sprite tsprite access for per-tile animation callback reg.

Don't yet make this official API though, since there are unresolved issues
with newly created tsprites potentially being fed back to the animation loop.
Add xmath.angvec(), xmath.bangvec(), tspr:set_sectnum(), tspr:setpos().

git-svn-id: https://svn.eduke32.com/eduke32@3937 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2013-07-07 20:59:10 +00:00
parent c243bab0e7
commit 7f2175fcec
10 changed files with 133 additions and 47 deletions

View file

@ -7051,6 +7051,7 @@ static void G_DoEventAnimSprites(int32_t j)
if ((unsigned)ow < MAXSPRITES && spriteext[ow].flags & SPREXT_TSPRACCESS)
{
spriteext[ow].tspr = &tsprite[j];
// XXX: wouldn't screenpeek be more meaningful as current player?
VM_OnEvent(EVENT_ANIMATESPRITES, ow, myconnectindex, -1, 0);
spriteext[ow].tspr = NULL;
}
@ -7884,6 +7885,11 @@ skip:
for (j = spritesortcnt-1; j>=0; j--)
G_DoEventAnimSprites(j);
}
#ifdef LUNATIC
if (G_HaveEvent(EVENT_ANIMATEALLSPRITES))
VM_OnEvent(EVENT_ANIMATEALLSPRITES, -1, -1, -1, 0);
#endif
}

View file

@ -694,7 +694,10 @@ const char *EventNames[MAXEVENTS] =
"EVENT_LOADGAME",
"EVENT_SAVEGAME",
"EVENT_PREGAME",
"EVENT_CHANGEMENU"
"EVENT_CHANGEMENU",
#ifdef LUNATIC
"EVENT_ANIMATEALLSPRITES",
#endif
};
#if !defined LUNATIC

View file

@ -125,6 +125,9 @@ enum GameEvent_t {
EVENT_SAVEGAME,
EVENT_PREGAME,
EVENT_CHANGEMENU,
#ifdef LUNATIC
EVENT_ANIMATEALLSPRITES, // 95
#endif
MAXEVENTS
};

View file

@ -168,6 +168,7 @@ EVENT = {
EVENT_SAVEGAME = 92,
EVENT_PREGAME = 93,
EVENT_CHANGEMENU = 94,
-- EVENT_ANIMATEALLSPRITES = 95, -- internal
}
-- NOTE: negated values are not exported to the ffi.C namespace or CON.
@ -331,7 +332,7 @@ wdata_members =
local SP = function(memb) return "sprite[%s]"..memb end
local ATSP = function(memb) return "atsprite[%s]"..memb end
local ATSP = function(memb) return "_atsprite[%s]"..memb end
local AC = function(memb) return "actor[%s]"..memb end
local SX = function(memb) return "spriteext[%s]"..memb end

View file

@ -1928,8 +1928,31 @@ local g_firstRun = (ffiC.g_elCONSize == 0)
-- Actor functions, saved for actor chaining
local actor_funcs = {}
-- Event functions, saved for event chaining
local event_funcs = {}
-- Per-actor sprite animation callbacks
local animsprite_funcs = {}
local gameactor_internal = gameactor_internal -- included in lunatic.c
local gameevent_internal = gameevent_internal -- included in lunatic.c
local function animate_all_sprites()
for i=0,ffiC.spritesortcnt-1 do
local tspr = ffiC.tsprite[i]
if (tspr.owner < ffiC.MAXSPRITES+0ULL) then
local spr = tspr:getspr()
local animfunc = animsprite_funcs[spr.picnum]
if (animfunc) then
animfunc(tspr)
end
end
end
end
-- gameactor{tilenum [, flags [, strength [, action [, move [, movflags]]]]], func}
-- Every arg may be positional OR key=val (with the name indicated above as key),
-- but not both.
@ -2018,6 +2041,24 @@ local function our_gameactor(args)
end
end
-- Register a potentially passed drawn sprite animation callback function.
-- TODO: allow registering without main actor execution callback.
local animfunc = args.animate
if (animfunc ~= nil) then
if (type(animfunc) ~= "function") then
error("invalid 'animate' argument to gameactor: must be a function", 2)
end
animsprite_funcs[tilenum] = replacep and func
or (chainflags==AF.chain_beg) and chain_func3(animfunc, animsprite_funcs[tilenum])
or (chainflags==AF.chain_end) and chain_func3(animsprite_funcs[tilenum], animfunc)
or assert(false)
-- Register our EVENT_ANIMATEALLSPRITES only now so that it is not
-- called if there are no 'animate' definitions.
gameevent_internal(95, animate_all_sprites) -- EVENT_ANIMATEALLSPRITES
end
-- All good, set the tile bits in initial run and register the actor!
-- XXX: Need to see if some other state living on the C side is clobbered
-- by Lua state recreation.
@ -2040,10 +2081,7 @@ local function our_gameactor(args)
actor_funcs[tilenum] = newfunc
end
-- Event functions, saved for event chaining
local event_funcs = {}
local gameevent_internal = gameevent_internal -- included in lunatic.c
-- gameevent{<event idx or string> [, flags], <event function>}
local function our_gameevent(args)
bcheck.top_level("gameevent")
@ -2313,7 +2351,6 @@ gv = setmtonce(gv_, tmpmt)
-- This will create 'sprite', 'wall', etc. HERE, i.e. in the environment of this chunk
defs_c.create_globals(_G)
-- REMOVE this for release
DBG_ = {}
DBG_.debug = require("debug")

View file

@ -155,6 +155,7 @@ string.format([[
local SPRITE_STRUCT = [[
struct {
// TODO: transparent union with vec3_t pos?
int32_t x, y, z;
]]..bitint_member("UBit16", "cstat")..[[
const int16_t picnum;
@ -597,6 +598,7 @@ ffi.metatype("walltype", walltype_mt)
local spriteext_mt = {
__index = {
-- Enable EVENT_ANIMATESPRITES for this sprite.
-- XXX: unused?
make_animated = function(sx)
sx.flags = bor(sx.flags, 16)
end,
@ -669,22 +671,40 @@ local function get_sprite_idx(spr)
return i
end
-- Methods that are specific to sprites
---=== Methods that are specific to sprites ===---
function spritetype_mt.__index.setpos(spr, pos) -- setsprite() clone
spr.x, spr.y, spr.z = pos.x, pos.y, pos.z
local newsect = updatesector(spr, spr.sectnum)
if (newsect < 0) then
return -1
end
if (spr.sectnum ~= newsect) then
if (newsect >= 0 and spr.sectnum ~= newsect) then
ffiC.changespritesect(get_sprite_idx(spr), newsect)
end
return newsect
end
---=== Methods that are specific to tsprites ===---
function tspritetype_mt.__index.set_sectnum(tspr, sectnum)
check_sector_idx(sectnum)
ffi.cast(spritetype_ptr_ct, tspr).sectnum = sectnum
end
-- TODO: flags (the same as sprite.UPDATE_FLAGS + "provide own sectnum",
-- e.g. for example because it's already there from "hitscan").
function tspritetype_mt.__index.setpos(tspr, pos)
tspr.x, tspr.y, tspr.z = pos.x, pos.y, pos.z
local newsect = updatesector(tspr, tspr.sectnum)
if (newsect >= 0 and tspr.sectnum ~= newsect) then
tspr:set_sectnum(newsect)
end
return newsect
end
-- Methods that are specific to tsprites
function tspritetype_mt.__index.dup(tspr)
if (ffiC.spritesortcnt >= ffiC.MAXSPRITESONSCREEN+0ULL) then
return nil
@ -698,9 +718,11 @@ function tspritetype_mt.__index.dup(tspr)
end
function tspritetype_mt.__index.getspr(tspr)
return sprite[tspr.owner]
check_sprite_idx(tspr.owner)
return ffiC.sprite[tspr.owner]
end
---======---
-- The user of this module can insert additional "spritetype" index
-- methods and register them with "ffi.metatype".
@ -923,7 +945,7 @@ sector = setmtonce({}, sector_mt)
wall = setmtonce({}, wall_mt)
sprite = setmtonce({}, sprite_mt)
spriteext = creategtab(ffiC.spriteext, ffiC.MAXSPRITES, 'spriteext[]')
atsprite = setmtonce({}, atsprite_mt)
_atsprite = setmtonce({}, atsprite_mt)
local function iter_wallsofsec(endwall, w)
w = w+1
@ -1039,7 +1061,7 @@ end
-- returns a hitdata_ct
-- TODO: make v[xyz] be passed as one aggregate, too?
-- Additionally, permit different coordinates? (ang&horiz, ...)
-- TODO: make cliptype optional? What should be the default?
function hitscan(pos, sectnum, vx,vy,vz, cliptype)
check_sector_idx(sectnum)
local vec = vec3_ct(pos.x, pos.y, pos.z)

View file

@ -182,7 +182,7 @@ local function new_initial_codetab()
"local _xmath = require'xmath'",
-- Cache globals into locals.
"local sector, sprite, wall, spriteext, atsprite = sector, sprite, wall, spriteext, atsprite",
"local sector, sprite, wall, spriteext, _atsprite = sector, sprite, wall, spriteext, _atsprite",
"local actor, player, projectile, g_tile = actor, player, projectile, g_tile",
"local gameactor, gameevent, _gv = gameactor, gameevent, gv",
"local updatesector, updatesectorz, cansee = updatesector, updatesectorz, cansee",

View file

@ -418,10 +418,8 @@ gameactor
action = AC.TROOPSTAND,
func = function(i, playeri, dist)
spriteext[i]:make_animated()
sprite[i].pal = math.random(32)
-- sprite[i].ang = bit.band(sprite[i].ang-20, 2047)
-- sprite[i].ang = bit.band(sprite[i].ang-20, 2047)
local spr = sprite[i]
@ -459,7 +457,36 @@ gameactor
actr.movflagsbits:flip(actor.MOVFLAGS.spin)
end
end
end
end,
-- NOTE: the animate callback is not yet documented and thus not official API!
animate = function(tspr)
local tspr2 = tspr:dup()
if (tspr2) then
tspr2.x = tspr2.x + 512*math.cos(gv.totalclock/60)
tspr2.y = tspr2.y + 512*math.sin(gv.totalclock/60)
tspr2.cstatbits:set(CS.TRANS_BITMASK)
end
-- XXX: inserted tsprites have floor shadow in classic! (r_shadow)
-- G_DoSpriteAnimations() is passed as callback to the engine on occasion,
-- in other words, created tsprites may be fed back to G_DoSpriteAnimations()!
-- classic: shows shadow for both "ghost" liztroop and aim "reticle"
-- Polymost: only for "ghost"
-- Polymer: none
local aimv = 256*xmath.bangvec(tspr.ang)
local hit = hitscan(tspr^(16*256), tspr.sectnum, aimv.x, aimv.y, 0, gv.CLIPMASK1)
if (hit.wall >= 0) then
local aimtspr = tspr:dup()
if (aimtspr) then
aimtspr.pal = 2
aimtspr:set_picnum(555)
aimtspr:setpos(hit.pos)
aimtspr:set_sectnum(hit.sect)
end
end
end,
}
gameactor
@ -539,24 +566,6 @@ gameactor
end
}
gameevent
{
"ANIMATESPRITES",
function(aci)
local tspr = atsprite[aci]
if (tspr:getspr().picnum==D.LIZTROOP) then
local tspr2 = tspr:dup()
if (tspr2) then
tspr2.x = tspr2.x + 512*math.cos(gv.totalclock/60)
tspr2.y = tspr2.y + 512*math.sin(gv.totalclock/60)
tspr2.cstatbits:set(CS.TRANS_BITMASK)
end
end
end
}
local function testbit(num, b)
return bit.band(num,b)~=0 and 1 or 0
end

View file

@ -31,14 +31,8 @@ local starPal = con.actorvar(0)
require("end_gamevars")
local function bangvec(bang)
bang = math.floor(bang)
return xmath.vec3(xmath.cosb(bang), xmath.sinb(bang))
end
local function angvec(ang)
return xmath.vec3(math.cos(ang), math.sin(ang))
end
local bangvec = xmath.bangvec
local angvec = xmath.angvec
local D = require("CON.DEFS")

View file

@ -285,6 +285,17 @@ end
---=== MISCELLANEOUS MATH ===---
local intarg = ffi.new("int32_t [1]")
function bangvec(bang)
intarg[0] = bang -- round towards zero
return vec3(cosb(intarg[0]), sinb(intarg[0]))
end
function angvec(ang)
return vec3(cos(ang), sin(ang))
end
local zerovec = vec3()
-- Point rotation. Note the different order of arguments from engine function.
-- XXX: passing mixed vec2/vec3 is problematic. Get rid of vec2?