From 3b65dc3a78200b163cfd6e5749c901bf19003f1f Mon Sep 17 00:00:00 2001 From: helixhorned Date: Mon, 6 May 2013 19:43:34 +0000 Subject: [PATCH] Lunatic: first prototype of map-text saving. git-svn-id: https://svn.eduke32.com/eduke32@3733 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/Makefile | 5 +- polymer/eduke32/build/src/engine.c | 51 +++- .../eduke32/source/lunatic/defs_common.lua | 58 +++-- polymer/eduke32/source/lunatic/dynsymlist | 3 + polymer/eduke32/source/lunatic/dynsymlist_m32 | 3 + .../eduke32/source/lunatic/engine_maptext.lua | 246 ++++++++++++++++++ .../source/lunatic/util/foreachmap.lua | 2 +- 7 files changed, 333 insertions(+), 35 deletions(-) create mode 100644 polymer/eduke32/source/lunatic/engine_maptext.lua diff --git a/polymer/eduke32/Makefile b/polymer/eduke32/Makefile index 9cc92cbc7..56f79475d 100644 --- a/polymer/eduke32/Makefile +++ b/polymer/eduke32/Makefile @@ -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 \ diff --git a/polymer/eduke32/build/src/engine.c b/polymer/eduke32/build/src/engine.c index fd6b4f72e..c609a968e 100644 --- a/polymer/eduke32/build/src/engine.c +++ b/polymer/eduke32/build/src/engine.c @@ -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 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; } diff --git a/polymer/eduke32/source/lunatic/defs_common.lua b/polymer/eduke32/source/lunatic/defs_common.lua index be4e0f2b4..e200a6dae 100644 --- a/polymer/eduke32/source/lunatic/defs_common.lua +++ b/polymer/eduke32/source/lunatic/defs_common.lua @@ -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,10 +22,12 @@ if (bit.band(ffiC._DEBUG_LUNATIC, 2)~=0) then require("jit").off() end -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() +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") @@ -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,22 +227,29 @@ 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))) --- 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", - { "r", "g", "b", "f" }) -ffi.cdef("typedef union { \ - struct { uint8_t r, g, b, f; }; \ - $ col; \ -} palette_t", rgbarray_t) -assert(ffi.alignof("palette_t")==1) +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", + { "r", "g", "b", "f" }) + 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: -require("geom") -local hitdata_ct = ffi.typeof("hitdata_t") + +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; diff --git a/polymer/eduke32/source/lunatic/dynsymlist b/polymer/eduke32/source/lunatic/dynsymlist index 0b85d8581..02d293bd7 100644 --- a/polymer/eduke32/source/lunatic/dynsymlist +++ b/polymer/eduke32/source/lunatic/dynsymlist @@ -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; diff --git a/polymer/eduke32/source/lunatic/dynsymlist_m32 b/polymer/eduke32/source/lunatic/dynsymlist_m32 index 3ca7c73e6..2430e8efe 100644 --- a/polymer/eduke32/source/lunatic/dynsymlist_m32 +++ b/polymer/eduke32/source/lunatic/dynsymlist_m32 @@ -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; diff --git a/polymer/eduke32/source/lunatic/engine_maptext.lua b/polymer/eduke32/source/lunatic/engine_maptext.lua new file mode 100644 index 000000000..6a21fbe90 --- /dev/null +++ b/polymer/eduke32/source/lunatic/engine_maptext.lua @@ -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]=. + "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 diff --git a/polymer/eduke32/source/lunatic/util/foreachmap.lua b/polymer/eduke32/source/lunatic/util/foreachmap.lua index f6009868e..eab7c774c 100755 --- a/polymer/eduke32/source/lunatic/util/foreachmap.lua +++ b/polymer/eduke32/source/lunatic/util/foreachmap.lua @@ -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)"