Lunatic: first prototype of map-text saving.

git-svn-id: https://svn.eduke32.com/eduke32@3733 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2013-05-06 19:43:34 +00:00
parent 65a10afbc8
commit 3b65dc3a78
7 changed files with 333 additions and 35 deletions

View file

@ -143,8 +143,9 @@ MISCEDITORDEPS=
## Lunatic devel
ifneq (0,$(LUNATIC))
EDITOROBJS+= $(OBJ)/lunatic_m32.$o $(OBJ)/luaJIT_BC_defs_common.$o
GAMEOBJS+= $(OBJ)/lunatic_game.$o $(OBJ)/luaJIT_BC_defs_common.$o
LUNATIC_COMMON_OBJS = $(OBJ)/luaJIT_BC_defs_common.$o $(OBJ)/luaJIT_BC_engine_maptext.$o
EDITOROBJS+= $(OBJ)/lunatic_m32.$o $(LUNATIC_COMMON_OBJS)
GAMEOBJS+= $(OBJ)/lunatic_game.$o $(LUNATIC_COMMON_OBJS)
GAMEOBJS+= $(OBJ)/../lpeg.$o # TEMP
GAMEOBJS+= $(OBJ)/luaJIT_BC_con_lang.$o \

View file

@ -46,6 +46,11 @@
#include "engine_priv.h"
#ifdef LUNATIC
# include "lunatic.h"
L_State g_engState;
#endif
#define CACHEAGETIME 16
//#define CLASSIC_NONPOW2_YSIZE_WALLS
#define CLASSIC_NONPOW2_YSIZE_SPRITES
@ -8610,6 +8615,18 @@ int32_t initengine(void)
if (!mdinited) mdinit();
#endif
#ifdef LUNATIC
if (L_CreateState(&g_engState, "eng", NULL))
return loadpalette_err("Failed creating engine Lua state!");
{
char *luastr = "_LUNATIC_AUX=true; decl=require('ffi').cdef; require'defs_common'";
if (L_RunString(&g_engState, luastr, 0, -1, "eng"))
return loadpalette_err("Failed setting up engine Lua state");
}
#endif
return 0;
}
@ -10447,6 +10464,10 @@ int32_t loadmaphack(const char *filename)
}
#ifdef NEW_MAP_FORMAT
int32_t (*saveboard_maptext)(const char *filename, const vec3_t *dapos, int16_t daang, int16_t dacursectnum);
#endif
//
// saveboard
//
@ -10455,18 +10476,7 @@ int32_t saveboard(const char *filename, const vec3_t *dapos, int16_t daang, int1
int16_t numsprites, ts;
int32_t i, j, fil, tl;
#ifdef NEW_MAP_FORMAT
// Writing new-format (Lunatic) maps not yet implemented; V9 not available then.
if (numyaxbunches > 0)
return -1;
#endif
if ((fil = Bopen(filename,BO_BINARY|BO_TRUNC|BO_CREAT|BO_WRONLY,BS_IREAD|BS_IWRITE)) == -1)
{
initprintf("Couldn't open \"%s\" for writing: %s\n", filename, strerror(errno));
return(-1);
}
// First, some checking.
for (j=0; j<MAXSPRITES; j++)
{
if ((unsigned)sprite[j].statnum > MAXSTATUS)
@ -10496,6 +10506,19 @@ int32_t saveboard(const char *filename, const vec3_t *dapos, int16_t daang, int1
// and the engine-reported number of sprites 'Numsprites'.
Bassert(numsprites == Numsprites);
#ifdef NEW_MAP_FORMAT
if (numyaxbunches > 0)
return saveboard_maptext(filename, dapos, daang, dacursectnum);
#endif
fil = Bopen(filename, BO_BINARY|BO_TRUNC|BO_CREAT|BO_WRONLY, BS_IREAD|BS_IWRITE);
if (fil == -1)
{
initprintf("Couldn't open \"%s\" for writing: %s\n", filename, strerror(errno));
return -1;
}
// Determine the map version.
#ifdef YAX_ENABLE
if (numyaxbunches > 0)
@ -10649,11 +10672,11 @@ int32_t saveboard(const char *filename, const vec3_t *dapos, int16_t daang, int1
}
Bclose(fil);
return(0);
return 0;
}
Bclose(fil);
return(-1);
return -1;
}

View file

@ -4,6 +4,9 @@
-- environment.
-- See the included license file "BUILDLIC.TXT" for license info.
-- Will be 'true' if running from engine Lua state:
local _LUNATIC_AUX = _LUNATIC_AUX
local ffi = require("ffi")
local ffiC = ffi.C
local bit = require("bit")
@ -19,11 +22,13 @@ if (bit.band(ffiC._DEBUG_LUNATIC, 2)~=0) then
require("jit").off()
end
if (not _LUNATIC_AUX) then
if (bit.band(ffiC._DEBUG_LUNATIC, 8)~=0) then
require("dump").on("+rs")
elseif (bit.band(ffiC._DEBUG_LUNATIC, 4)~=0) then
require("v").on()
end
end
local math = require("math")
local string = require("string")
@ -37,7 +42,7 @@ local setmetatable = setmetatable
local tostring = tostring
local type = type
local decl = decl
local decl = assert(decl)
local getfenv = getfenv
decl "void OSD_Printf(const char *fmt, ...);"
@ -180,6 +185,10 @@ function strip_const(structstr)
return (string.gsub(structstr, "const[^ ]* ", ""));
end
local function maybe_strip_const(str)
return _LUNATIC_AUX and strip_const(str) or str
end
-- NOTE for FFI definitions: we're compiling EDuke32 with -funsigned-char, so
-- we need to take care to declare chars as unsigned whenever it matters, for
-- example if it represents a palette index. (I think it's harmless for stuff
@ -218,9 +227,11 @@ typedef struct {
int16_t sprite, wall, sect;
} hitdata_t;
]],
ffi.typeof(SECTOR_STRUCT), ffi.typeof(WALL_STRUCT),
ffi.typeof(SPRITE_STRUCT))
ffi.typeof(maybe_strip_const(SECTOR_STRUCT)),
ffi.typeof(maybe_strip_const(WALL_STRUCT)),
ffi.typeof(maybe_strip_const(SPRITE_STRUCT)))
if (not _LUNATIC_AUX) then
-- Define the "palette_t" type, which for us has .{r,g,b} fields and a
-- bound-checking array of length 3 overlaid.
local rgbarray_t = require("bcarray").new("uint8_t", 3, "RGB array", "palette_t",
@ -229,11 +240,16 @@ ffi.cdef("typedef union { \
struct { uint8_t r, g, b, f; }; \
$ col; \
} palette_t", rgbarray_t)
assert(ffi.alignof("palette_t")==1)
end
local vec3_ct = ffi.typeof("vec3_t") -- will be metatype'd in geom.lua:
if (not _LUNATIC_AUX) then
require("geom")
local hitdata_ct = ffi.typeof("hitdata_t")
end
decl[[
const int32_t engine_main_arrays_are_static;
@ -311,6 +327,12 @@ const int32_t xdim, ydim;
const int32_t windowx1, windowy1, windowx2, windowy2;
]]
if (_LUNATIC_AUX) then
require "engine_maptext"
return
end
decl[[
int32_t yxaspect;
int32_t viewingrange;

View file

@ -2,6 +2,8 @@
engine_main_arrays_are_static;
engine_v8;
saveboard_maptext;
sector;
wall;
sprite;
@ -78,6 +80,7 @@ gethitickms;
OSD_Printf;
luaJIT_BC_defs_common;
luaJIT_BC_engine_maptext;

View file

@ -2,6 +2,8 @@
engine_main_arrays_are_static;
engine_v8;
saveboard_maptext;
sector;
wall;
sprite;
@ -78,6 +80,7 @@ gethitickms;
OSD_Printf;
luaJIT_BC_defs_common;
luaJIT_BC_engine_maptext;

View file

@ -0,0 +1,246 @@
-- MAPTEXT
-- Lunatic: routines for reading and writing map-text.
local ffi = require("ffi")
local ffiC = ffi.C
local print = print
local tonumber = tonumber
local type = type
local io = require("io")
local string = require("string")
ffi.cdef[[
int32_t (*saveboard_maptext)(const char *filename, const vec3_t *dapos, int16_t daang, int16_t dacursectnum);
]]
--== COMMON ==--
local sector_members = {
-- Mandatory positional members first, [pos]=<name>.
"wallnum",
"ceilingz", "floorz",
"ceilingpicnum", "floorpicnum",
"ceilingshade", "floorshade";
-- If other positional members are to be added, they must be optional
-- for backwards compatibility.
-- Optional key/value members next.
B = { "ceilingbunch", -1 }, b = { "floorbunch", -1 }, -- default: -1
F = "ceilingstat", f = "floorstat", -- default: 0
H = "ceilingheinum", h = "floorheinum",
P = "ceilingpal", p = "floorpal",
X = "ceilingxpanning", x = "floorxpanning",
Y = "ceilingypanning", y = "floorypanning",
v = "visibility",
_ = "filler",
o = "lotag", i = "hitag", e = { "extra", -1 }
}
-- Defines the order in which the members are written out. A space denotes that
-- a newline should appear in the output.
local sector_ord = { mand="1 23 45 67 ", opt="Bb Ff Hh Pp Xx Yy v _ oie" }
local wall_members = {
-- mandatory
"point2", -- special: 0 or 1 in map-text
"x", "y",
"nextwall",
"picnum",
"shade",
"xrepeat", "yrepeat",
"xpanning", "ypanning";
-- optional
f = "cstat",
m = "overpicnum",
p = "pal",
o = "lotag", i = "hitag", e = { "extra", -1 }
}
local wall_ord = { mand="1 23 4 5 6 78 90 ", opt="f m p oie" }
local sprite_members = {
-- mandatory
"x", "y", "z",
"ang",
"sectnum",
"picnum",
"cstat",
"shade",
"xrepeat", "yrepeat",
-- optional
p = "pal",
c = { "clipdist", 32 },
_ = "filler",
x = "xoffset", y = "yoffset",
s = "statnum",
w = { "owner", -1 },
X = "xvel", Y = "yvel", Z = "zvel",
o = "lotag", i = "hitag", e = { "extra", -1 }
}
local sprite_ord = { mand="123 4 5 6 7 8 90 ", opt="p c _ xy s w XYZ oie" }
--== SAVING ==--
local function write_struct(f, struct, members, ord)
-- Write mandatory members first.
local str = ord.mand:gsub(".",
function(s)
local num = (s=="0") and 10 or tonumber(s)
return (s==" ") and "\n" or (struct[members[num]]..",")
end)
f:write("{"..str)
local havesth = false
-- Write optional members next.
str = ord.opt:gsub(".",
function(s)
if (s==" ") then
local ohavesth = havesth
havesth = false
return ohavesth and "\n" or ""
end
local memb = members[s]
local mname = (type(memb)=="table") and memb[1] or memb
local mdefault = (type(memb)=="table") and memb[2] or 0
local val = struct[mname]
if (val~=mdefault) then
havesth = true
return s.."="..val..","
else
return ""
end
end)
f:write(str.."},\n")
end
-- In map-text, instead of saving wall[].point2, we store whether a particular
-- wall is the last one in its loop instead.
local function save_tweak_point2()
local lastloopstart = 0
-- Check first.
for i=0,ffiC.numwalls-1 do
local p2 = ffiC.wall[i].point2
if (not (p2 == i+1 or (p2 ~= i and p2 == lastloopstart))) then
-- If we hit this, the map is seriously corrupted!
print(string.format("INTERNAL ERROR: wall[%d].point2=%d invalid", i, p2))
return true
end
if (p2 ~= i+1) then
lastloopstart = i+1
end
end
-- Do it for real.
lastloopstart = 0
for i=0,ffiC.numwalls-1 do
local wal = ffiC.wall[i]
if (wal.point2 == i+1) then
wal.point2 = 0
else
wal.point2 = 1 -- last point in loop
lastloopstart = i+1
end
end
end
local function save_restore_point2()
local lastloopstart = 0
for i=0,ffiC.numwalls-1 do
local wal = ffiC.wall[i]
local islast = (wal.point2~=0)
if (not islast) then
wal.point2 = i+1
else
wal.point2 = lastloopstart
lastloopstart = i+1
end
end
end
local function saveboard_maptext(filename, pos, ang, cursectnum)
-- First, temporarily tweak wall[].point2.
if (save_tweak_point2()) then
return -1
end
-- We open in binary mode so that newlines get written out as one byte even
-- on Windows.
local f, msg = io.open(ffi.string(filename), "wb")
if (f == nil) then
print(string.format("Couldn't open \"%s\" for writing: %s\n", filename, msg))
save_restore_point2()
return -1
end
-- Write header.
f:write(string.format("--EDuke32 map\n"..
"return {\n"..
"version=10,\n\n"..
"pos={%d,%d,%d},\n"..
"sectnum=%d,\n"..
"ang=%d,\n\n",
pos.x, pos.y, pos.z,
cursectnum,
ang))
-- Sectors.
f:write("sector={\n")
for i=0,ffiC.numsectors-1 do
write_struct(f, ffiC.sector[i], sector_members, sector_ord)
end
f:write("}\n\n")
-- Walls.
f:write("wall={\n")
for i=0,ffiC.numwalls-1 do
write_struct(f, ffiC.wall[i], wall_members, wall_ord)
end
f:write("}\n\n")
-- Sprites.
f:write("sprite={\n")
for i=0,ffiC.MAXSPRITES-1 do
if (ffiC.sprite[i].statnum ~= ffiC.MAXSTATUS) then
write_struct(f, ffiC.sprite[i], sprite_members, sprite_ord)
end
end
f:write("}\n\n")
f:write("}\n");
-- Done.
f:close()
save_restore_point2()
return 0
end
-- Register our Lua functions as callbacks from C.
ffiC.saveboard_maptext = saveboard_maptext

View file

@ -14,7 +14,7 @@
-- message is printed to stderr.
-- Finally, if there is a .finish field in the module, it is run with no args.
-- forxcode example: print sprite numbers with lotag < -1 (interpreting lotag it as signed),
-- forxcode example: print sprite numbers with lotag < -1 (lotag is signed for us),
-- and for each matching sprite also print its lotag and picnum:
-- $ ./findmaps.sh ~/.eduke32/ "sprite: .lotag < -1 :: io. write(', '.. .lotag .. ' ' .. .picnum)"