mirror of
https://github.com/DrBeef/Raze.git
synced 2024-11-15 08:52:00 +00:00
Lunatic: add 'engine' module, currently allowing to create custom shade tables.
Available in the game and editor. Provide test/shadexfog.lua, containing a function to creating a set of 32 shade tables corresponding to different shades of the same fog palookup table, together with some tests and convenience functions. Also, - Add gv.LUNATIC_CLIENT{,_EDUKE32,_MAPSTER32} - Add LUNATIC_FIRST_TIME in the global env for the game - defs_m32.lua: add reload() convenience function - Failed attempt at recreating the base shade table. It is NOT a linear ramp of the base palette colors to (0,0,0). That is, it's not created by build/util/transpal.exe! git-svn-id: https://svn.eduke32.com/eduke32@4236 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
75f5449e9a
commit
13c125db02
11 changed files with 408 additions and 9 deletions
|
@ -144,7 +144,7 @@ MISCEDITORDEPS=
|
|||
|
||||
## Lunatic devel
|
||||
ifneq (0,$(LUNATIC))
|
||||
LUNATIC_COMMON_OBJS = $(OBJ)/luaJIT_BC_defs_common.$o $(OBJ)/luaJIT_BC_engine_maptext.$o
|
||||
LUNATIC_COMMON_OBJS = $(OBJ)/luaJIT_BC_defs_common.$o $(OBJ)/luaJIT_BC_engine_maptext.$o $(OBJ)/luaJIT_BC_engine.$o
|
||||
EDITOROBJS+= $(OBJ)/lunatic_m32.$o $(LUNATIC_COMMON_OBJS)
|
||||
GAMEOBJS+= $(OBJ)/lunatic_game.$o $(LUNATIC_COMMON_OBJS)
|
||||
|
||||
|
|
|
@ -14285,6 +14285,36 @@ void rotatesprite_(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum,
|
|||
}
|
||||
}
|
||||
|
||||
static int32_t palookup_isdefault(int32_t palnum) // KEEPINSYNC engine.lua
|
||||
{
|
||||
return (palookup[palnum] == NULL || (palnum!=0 && palookup[palnum] == palookup[0]));
|
||||
}
|
||||
|
||||
static void maybe_alloc_palookup(int32_t palnum)
|
||||
{
|
||||
if (palookup_isdefault(palnum))
|
||||
{
|
||||
alloc_palookup(palnum);
|
||||
if (palookup[palnum] == NULL)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LUNATIC
|
||||
int32_t setpalookup(int32_t palnum, const uint8_t *shtab)
|
||||
{
|
||||
if (numshades != 32)
|
||||
return -1;
|
||||
|
||||
if (shtab != NULL)
|
||||
{
|
||||
maybe_alloc_palookup(palnum);
|
||||
Bmemcpy(palookup[palnum], shtab, 256*numshades);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// makepalookup
|
||||
|
@ -14319,12 +14349,7 @@ void makepalookup(int32_t palnum, const char *remapbuf, int8_t r, int8_t g, int8
|
|||
remapbuf = idmap;
|
||||
}
|
||||
|
||||
if (palookup[palnum] == NULL || (palnum!=0 && palookup[palnum] == palookup[0]))
|
||||
{
|
||||
alloc_palookup(palnum);
|
||||
if (palookup[palnum] == NULL)
|
||||
exit(1);
|
||||
}
|
||||
maybe_alloc_palookup(palnum);
|
||||
|
||||
if (dastat == 0) return;
|
||||
if ((r|g|b|63) != 63) return;
|
||||
|
|
|
@ -10745,6 +10745,8 @@ static void G_Startup(void)
|
|||
Gv_FinalizeWeaponDefaults();
|
||||
G_PostCreateGameState();
|
||||
#ifdef LUNATIC
|
||||
// NOTE: This is only effective for CON-defined EVENT_INIT. See EVENT_INIT
|
||||
// not in defs.ilua.
|
||||
VM_OnEvent(EVENT_INIT, -1, -1, -1, 0);
|
||||
#endif
|
||||
if (g_netServer || ud.multimode > 1) G_CheckGametype();
|
||||
|
|
|
@ -65,6 +65,15 @@ end
|
|||
|
||||
lprivate.decl = decl
|
||||
|
||||
ffi.cdef[[
|
||||
enum {
|
||||
LUNATIC_CLIENT_MAPSTER32 = 0,
|
||||
LUNATIC_CLIENT_EDUKE32 = 1,
|
||||
|
||||
LUNATIC_CLIENT = LUNATIC_CLIENT_EDUKE32
|
||||
}
|
||||
]]
|
||||
|
||||
-- Load the definitions common to the game's and editor's Lua interface.
|
||||
local defs_c = require("defs_common")
|
||||
local cansee = defs_c.cansee
|
||||
|
@ -608,6 +617,7 @@ int32_t (*El_RestoreGamevars)(const char *savecode);
|
|||
const char *s_buildRev;
|
||||
const char *g_sizes_of_what[];
|
||||
int32_t g_sizes_of[];
|
||||
int32_t g_elFirstTime;
|
||||
int32_t g_elCallDepth;
|
||||
int32_t block_deletesprite;
|
||||
const char **g_elModules;
|
||||
|
@ -1570,6 +1580,7 @@ local allowed_modules = {
|
|||
},
|
||||
|
||||
randgen = randgen,
|
||||
engine = require("engine"),
|
||||
stat = require("stat"),
|
||||
bitar = require("bitar"),
|
||||
xmath = require("xmath"),
|
||||
|
@ -2186,6 +2197,8 @@ G_.actor = actor
|
|||
G_.projectile = projectile
|
||||
G_.g_tile = g_tile
|
||||
|
||||
G_.LUNATIC_FIRST_TIME = (ffiC.g_elFirstTime ~= 0)
|
||||
|
||||
-- A table that can be used for temporary data when debugging from the OSD.
|
||||
G_.d = {}
|
||||
|
||||
|
@ -2552,4 +2565,6 @@ if (not g_firstRun) then
|
|||
|
||||
i = i+1
|
||||
end
|
||||
|
||||
ffiC.g_elFirstTime = 0
|
||||
end
|
||||
|
|
|
@ -4,6 +4,15 @@
|
|||
local ffi = require("ffi")
|
||||
local ffiC = ffi.C
|
||||
|
||||
ffi.cdef[[
|
||||
enum {
|
||||
LUNATIC_CLIENT_MAPSTER32 = 0,
|
||||
LUNATIC_CLIENT_EDUKE32 = 1,
|
||||
|
||||
LUNATIC_CLIENT = LUNATIC_CLIENT_MAPSTER32
|
||||
}
|
||||
]]
|
||||
|
||||
--== First, load the definitions common to the game's and editor's Lua interface.
|
||||
decl = ffi.cdef
|
||||
local defs_c = require("defs_common")
|
||||
|
@ -11,6 +20,8 @@ defs_c.finish_spritetype({})
|
|||
|
||||
defs_c.create_globals(_G)
|
||||
|
||||
-- TODO: provide access to only a subset, restict access to ffiC?
|
||||
gv = ffiC
|
||||
|
||||
--== Mapster32-specific initialization
|
||||
|
||||
|
@ -32,4 +43,13 @@ while (true) do
|
|||
initp = 0
|
||||
end
|
||||
|
||||
-- Helper functions
|
||||
local package = package
|
||||
local require = require
|
||||
|
||||
function reload(modname)
|
||||
package.loaded[modname] = nil
|
||||
return require(modname)
|
||||
end
|
||||
|
||||
--print('Lua load path: '..package.path)
|
||||
|
|
|
@ -66,6 +66,11 @@ clipmovex;
|
|||
rotatesprite_;
|
||||
setaspect;
|
||||
|
||||
getclosestcol;
|
||||
palookup;
|
||||
palette;
|
||||
setpalookup;
|
||||
|
||||
kopen4load;
|
||||
kfilelength;
|
||||
kclose;
|
||||
|
@ -91,6 +96,7 @@ crc32once;
|
|||
|
||||
luaJIT_BC_defs_common;
|
||||
luaJIT_BC_engine_maptext;
|
||||
luaJIT_BC_engine;
|
||||
|
||||
g_argv;
|
||||
|
||||
|
@ -108,6 +114,7 @@ El_RestoreGamevars;
|
|||
s_buildRev;
|
||||
g_sizes_of_what;
|
||||
g_sizes_of;
|
||||
g_elFirstTime;
|
||||
g_elCallDepth;
|
||||
block_deletesprite;
|
||||
g_RETURN;
|
||||
|
|
|
@ -66,6 +66,11 @@ clipmovex;
|
|||
rotatesprite_;
|
||||
setaspect;
|
||||
|
||||
getclosestcol;
|
||||
palookup;
|
||||
palette;
|
||||
setpalookup;
|
||||
|
||||
kopen4load;
|
||||
kfilelength;
|
||||
kclose;
|
||||
|
@ -87,6 +92,7 @@ crc32once;
|
|||
|
||||
luaJIT_BC_defs_common;
|
||||
luaJIT_BC_engine_maptext;
|
||||
luaJIT_BC_engine;
|
||||
|
||||
g_argv;
|
||||
|
||||
|
|
117
polymer/eduke32/source/lunatic/engine.lua
Normal file
117
polymer/eduke32/source/lunatic/engine.lua
Normal file
|
@ -0,0 +1,117 @@
|
|||
|
||||
local ffi = require("ffi")
|
||||
local C = ffi.C
|
||||
|
||||
local bcarray = require("bcarray")
|
||||
|
||||
local error = error
|
||||
local type = type
|
||||
|
||||
local decl = assert(decl) -- comes from above (defs.ilua or defs_m32.lua)
|
||||
|
||||
local ismapster32 = (C.LUNATIC_CLIENT == C.LUNATIC_CLIENT_MAPSTER32)
|
||||
|
||||
----------
|
||||
|
||||
decl[[
|
||||
int32_t getclosestcol(int32_t r, int32_t g, int32_t b);
|
||||
char *palookup[256]; // MAXPALOOKUPS
|
||||
uint8_t palette[768];
|
||||
|
||||
int32_t setpalookup(int32_t palnum, const uint8_t *shtab);
|
||||
]]
|
||||
|
||||
----------
|
||||
|
||||
-- The API table
|
||||
local engine = {}
|
||||
|
||||
local pal256_t = bcarray.new("uint8_t", 256, "shade table 256-tuple")
|
||||
-- The shade table type, effectively a bound-checked uint8_t [32][256]:
|
||||
local shtab_t = bcarray.new(pal256_t, 32, "shade table")
|
||||
local SIZEOF_SHTAB = ffi.sizeof(shtab_t)
|
||||
|
||||
local RESERVEDPALS = 8 -- KEEPINSYNC build.h: assure that ours is >= theirs
|
||||
engine.RESERVEDPALS = RESERVEDPALS
|
||||
|
||||
local function check_palidx(i)
|
||||
if (type(i) ~= "number" or not (i >= 0 and i <= 255-RESERVEDPALS)) then
|
||||
error("invalid argument #1: palette index must be in the range [0 .. "..255-RESERVEDPALS.."]", 3)
|
||||
end
|
||||
end
|
||||
|
||||
local function err_uncommon_shade_table(ret)
|
||||
if (ret == -1) then
|
||||
error("loaded engine shade tables don't have 32 gradients of shade", 3)
|
||||
end
|
||||
end
|
||||
|
||||
local function palookup_isdefault(palnum) -- KEEPINSYNC engine.c
|
||||
return (C.palookup[palnum] == nil or (palnum ~= 0 and C.palookup[palnum] == C.palookup[0]))
|
||||
end
|
||||
|
||||
function engine.shadetab()
|
||||
return shtab_t()
|
||||
end
|
||||
|
||||
function engine.getshadetab(palidx)
|
||||
check_palidx(palidx)
|
||||
if (palookup_isdefault(palidx)) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local ret = C.setpalookup(palidx, nil)
|
||||
err_uncommon_shade_table(ret)
|
||||
|
||||
local sht = shtab_t()
|
||||
ffi.copy(sht, C.palookup[palidx], SIZEOF_SHTAB)
|
||||
return sht
|
||||
end
|
||||
|
||||
function engine.setshadetab(palidx, shtab)
|
||||
if (not ismapster32 and C.g_elFirstTime == 0) then
|
||||
error("setshadetab() may be run only while LUNATIC_FIRST_TIME is true", 2)
|
||||
end
|
||||
|
||||
check_palidx(palidx)
|
||||
if (not ffi.istype(shtab_t, shtab_t)) then
|
||||
error("invalid argument #2: must be a shade table obtained by shadetab()", 2)
|
||||
end
|
||||
|
||||
if (not ismapster32 and not palookup_isdefault(palidx)) then
|
||||
error("attempt to override already defined shade table", 2)
|
||||
end
|
||||
|
||||
local ret = C.setpalookup(palidx, ffi.cast("uint8_t *", shtab))
|
||||
err_uncommon_shade_table(ret)
|
||||
end
|
||||
|
||||
|
||||
local function check_colcomp(a)
|
||||
if (type(a) ~= "number" or not (a >= 0 and a <= 63)) then
|
||||
error("color component must be in the range [0 .. 63]", 3)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- TODO: other base palettes?
|
||||
function engine.getrgb(colidx)
|
||||
if (type(colidx) ~= "number" or not (colidx >= 0 and colidx <= 255)) then
|
||||
error("color index must be in the range [0 .. 255]", 2)
|
||||
end
|
||||
|
||||
local rgbptr = C.palette + 3*colidx
|
||||
return rgbptr[0], rgbptr[1], rgbptr[2]
|
||||
end
|
||||
|
||||
-- TODO: flag whether fullbrights are OK
|
||||
function engine.nearcolor(r, g, b)
|
||||
check_colcomp(r)
|
||||
check_colcomp(g)
|
||||
check_colcomp(b)
|
||||
return C.getclosestcol(r, g, b)
|
||||
end
|
||||
|
||||
|
||||
-- Done!
|
||||
return engine
|
|
@ -37,6 +37,9 @@ int32_t g_elSessionVar[8]; // MAXSESSIONVARS, KEEPINSYNC con_lang.lua
|
|||
// Set to 1 on error in event.
|
||||
int32_t g_elEventError;
|
||||
|
||||
// Will be set to 0 after the first time that user Lua modules are run.
|
||||
int32_t g_elFirstTime = 1;
|
||||
|
||||
int32_t g_elCallDepth = 0;
|
||||
int32_t g_RETURN;
|
||||
|
||||
|
|
|
@ -170,6 +170,9 @@ gameevent
|
|||
|
||||
-- sprite.picnum may happen as a thinko/typo kind of error (spr.picnum was meant)
|
||||
checkfail("local pic = sprite.picnum", "invalid access to static data")
|
||||
|
||||
checkfail("require('engine').setshadetab(200, nil)",
|
||||
"setshadetab() may be run only while LUNATIC_FIRST_TIME is true")
|
||||
end
|
||||
}
|
||||
|
||||
|
@ -327,8 +330,6 @@ gameevent
|
|||
-- NOTE: setting colors partially is bad! E.g. after an item is
|
||||
-- picked up, col[0] and col[1] remain and tint everything greenish.
|
||||
if (DBG_ ~= nil) then
|
||||
-- XXX (unrelated to these lines): issuing tinting sometimes makes
|
||||
-- it flicker in the GL modes.
|
||||
ps._pals[2] = 20
|
||||
ps._pals.f = 30
|
||||
end
|
||||
|
@ -888,3 +889,7 @@ do
|
|||
printf('Time for %d runs: getangle: %.03f ms, math.atan2: %.03f ms', N, t1, t2)
|
||||
print('----------')
|
||||
end
|
||||
|
||||
if (LUNATIC_FIRST_TIME) then
|
||||
require("test.shadexfog").test_create0()
|
||||
end
|
||||
|
|
199
polymer/eduke32/source/lunatic/test/shadexfog.lua
Normal file
199
polymer/eduke32/source/lunatic/test/shadexfog.lua
Normal file
|
@ -0,0 +1,199 @@
|
|||
--[[
|
||||
Usage: in Mapster32,
|
||||
> lua "shadexfog=reload'shadexfog'"
|
||||
-- for example
|
||||
> lua "shadexfog.create(100, 63,63,63)"
|
||||
> lua "shadexfog.translate(100, 2)"
|
||||
In EDuke32, simply pass this module at the command line.
|
||||
--]]
|
||||
|
||||
local error = error
|
||||
|
||||
local math = require("math")
|
||||
local min, max = math.min, math.max
|
||||
|
||||
local sector, wall, sprite = sector, wall, sprite
|
||||
|
||||
local engine = require("engine")
|
||||
local gv = gv
|
||||
|
||||
----------
|
||||
|
||||
local shadexfog = {}
|
||||
|
||||
-- Create 32 palookups corrensponding to different *shade levels* of a fog
|
||||
-- palookup, called a "shade-x-fog" palookup set in the following.
|
||||
--
|
||||
-- Pals <tartpalnum> .. <startpalnum>+31 will be taken.
|
||||
-- <fogr>, <fogg>, <fogb>: intensities of the fog color, [0 ..63]
|
||||
function shadexfog.create(startpalnum, fogr, fogg, fogb)
|
||||
local MAXPALNUM = 255-31-engine.RESERVEDPALS
|
||||
if (not (startpalnum >= 1 and startpalnum <= MAXPALNUM)) then
|
||||
error("invalid startpalnum, max="..MAXPALNUM, 2)
|
||||
end
|
||||
|
||||
local basesht = engine.getshadetab(0)
|
||||
|
||||
-- Encode the shade in different pal numbers! The shade tables are
|
||||
-- constructed with a fog in their place.
|
||||
for dummyshade=1,31 do
|
||||
local sht = engine.shadetab()
|
||||
|
||||
for f=0,31 do
|
||||
for i=0,255 do
|
||||
local r, g, b = engine.getrgb(basesht[dummyshade][i])
|
||||
|
||||
local nr, ng, nb =
|
||||
(r*(32-f) + fogr*f) / 32,
|
||||
(g*(32-f) + fogg*f) / 32,
|
||||
(b*(32-f) + fogb*f) / 32
|
||||
|
||||
sht[f][i] = engine.nearcolor(nr, ng, nb)
|
||||
end
|
||||
end
|
||||
|
||||
engine.setshadetab(startpalnum + dummyshade, sht)
|
||||
end
|
||||
end
|
||||
|
||||
local function trans(what, startpalnum, fogintensity)
|
||||
local shade = min(max(what.shade, 0), 31)
|
||||
what.pal = startpalnum + shade
|
||||
what.shade = fogintensity
|
||||
end
|
||||
|
||||
-- shadexfog.translate(startpalnum, fogintensity [, vis])
|
||||
--
|
||||
-- Translate the whole map for use with a shade-x-fog palookup set.
|
||||
-- .pal becomes the <startpalnum> + former .shade
|
||||
-- .shade becomes the <fogintensity> [0 .. 31]
|
||||
-- If <vis> is passed, set all sector's visibility to that value.
|
||||
--
|
||||
-- Notes:
|
||||
-- - works only a single time (TODO: autodetection if already applied)
|
||||
-- - if shades < 0 or > 31 present, loss of information
|
||||
function shadexfog.translate(startpalnum, fogintensity, vis)
|
||||
for i=0,gv.numsectors-1 do
|
||||
trans(sector[i].ceiling, startpalnum, fogintensity)
|
||||
trans(sector[i].floor, startpalnum, fogintensity)
|
||||
if (vis) then
|
||||
sector[i].visibility = vis
|
||||
end
|
||||
end
|
||||
|
||||
for i=0,gv.numwalls-1 do
|
||||
trans(wall[i], startpalnum, fogintensity)
|
||||
end
|
||||
end
|
||||
|
||||
if (gv.LUNATIC_CLIENT == gv.LUNATIC_CLIENT_EDUKE32 and LUNATIC_FIRST_TIME) then
|
||||
shadexfog.create(100, 63,63,63)
|
||||
print("created shadexfog palookups")
|
||||
end
|
||||
|
||||
---------- BASE SHADE TABLE TESTS ----------
|
||||
|
||||
-- Basic test of whether for a color index i corresponding to a color (r,g,b),
|
||||
-- getclosestcol() returns a color index ii corresponding to the same color.
|
||||
-- (In the Duke3D palette, there are duplicates, so the requirement i==ii is
|
||||
-- too strict.)
|
||||
function shadexfog.test_nearcolor()
|
||||
for i=0,255 do
|
||||
local r, g, b = engine.getrgb(i)
|
||||
local ii = engine.nearcolor(r, g, b)
|
||||
local rr, gg, bb = engine.getrgb(ii)
|
||||
|
||||
if (r~=rr or g~=gg or b~=bb) then
|
||||
printf("diff %d: %d,%d,%d %d,%d,%d", i, r,g,b, rr,gg,bb)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Change the .pal member of all sector ceilings/floors, walls and sprites to
|
||||
-- <pal>.
|
||||
function shadexfog.challpal(palnum)
|
||||
for i=0,gv.numsectors-1 do
|
||||
sector[i].ceilingpal = palnum
|
||||
sector[i].floorpal = palnum
|
||||
end
|
||||
for i=0,gv.numwalls-1 do
|
||||
wall[i].pal = palnum
|
||||
end
|
||||
for i in sprite.all() do
|
||||
sprite[i].pal = palnum
|
||||
end
|
||||
end
|
||||
|
||||
-- Create our version of the base shade table (palookup 0)
|
||||
--
|
||||
-- NOTE: Nope, the base shade table is NOT created by applying a linear ramp to
|
||||
-- the base palette colors!!!
|
||||
local function create_base_shtab(basesht)
|
||||
local basesht = basesht or engine.getshadetab(0)
|
||||
|
||||
local sht = engine.shadetab()
|
||||
sht[0] = basesht[0]
|
||||
for sh=1,31 do
|
||||
for i=0,255-16 do
|
||||
-- NOTE that this fails, see BASESHT_0_NOT_IDENTITY:
|
||||
-- assert(basesht[0][i] == i)
|
||||
local r, g, b = engine.getrgb(i)
|
||||
local f = 1
|
||||
r = ((32-f*sh+0.5)*r)/32
|
||||
g = ((32-f*sh+0.5)*g)/32
|
||||
b = ((32-f*sh+0.5)*b)/32
|
||||
r, g, b = max(0,r), max(0,g), max(0,b) -- if f is > 1
|
||||
sht[sh][i] = engine.nearcolor(r, g, b)
|
||||
end
|
||||
|
||||
for i=255-16+1,255 do
|
||||
-- fullbrights
|
||||
sht[sh][i] = basesht[0][i]
|
||||
end
|
||||
end
|
||||
|
||||
return sht
|
||||
end
|
||||
|
||||
-- Create our (failed) version of the base shade table at set it to palookup
|
||||
-- number <palnum>.
|
||||
function shadexfog.create0(palnum)
|
||||
local sht0 = create_base_shtab()
|
||||
engine.setshadetab(palnum, sht0)
|
||||
end
|
||||
|
||||
function shadexfog.test_create0()
|
||||
local basesht = engine.getshadetab(0)
|
||||
|
||||
for i=0,255 do
|
||||
if (basesht[0][i] ~= i) then
|
||||
-- BASESHT_0_NOT_IDENTITY
|
||||
printf("Base shade table at index %d: %d", i, basesht[0][i])
|
||||
end
|
||||
end
|
||||
|
||||
local sht = create_base_shtab(basesht)
|
||||
|
||||
local ok = true
|
||||
for sh=1,31 do
|
||||
for i=0,255 do
|
||||
local ouri, origi = sht[sh][i], basesht[sh][i]
|
||||
-- if (sht[sh][i] ~= basesht[sh][i]) then
|
||||
if (math.abs(ouri - origi) > 1) then
|
||||
printf("Constructed shade table DIFFERS AT shade %d index %d: orig %d ours %d",
|
||||
sh, i, basesht[sh][i], sht[sh][i])
|
||||
ok = false
|
||||
goto out
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
::out::
|
||||
if (ok) then
|
||||
printf("Constructed shade table IDENTICAL WITH original one")
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
return shadexfog
|
||||
end
|
Loading…
Reference in a new issue