From a40d564e71d2b5a35f1a20a5e1e6255d19e6fcba Mon Sep 17 00:00:00 2001 From: ZILtoid1991 Date: Sun, 1 Oct 2023 20:26:18 +0200 Subject: [PATCH] Final work on scripting before next release --- assets/test4.lua | 50 ++++++++++-- dub.sdl | 9 +++ .../src/pixelperfectengine/scripting/lua.d | 27 +++++-- .../src/pixelperfectengine/scripting/lualib.d | 78 ++++++++++++------- .../src/pixelperfectengine/system/timer.d | 2 + test4/app.d | 32 ++++++-- 6 files changed, 153 insertions(+), 45 deletions(-) diff --git a/assets/test4.lua b/assets/test4.lua index f52a9413..a71cd001 100644 --- a/assets/test4.lua +++ b/assets/test4.lua @@ -1,12 +1,50 @@ +Globalstate = 0 +Titlescreen = true + +--Script entry point +function Main(luastate) + Globalstate = luastate + local sprtLayer = getLayer(16) + addSprite(sprtLayer, getBitmapResource("Titlescreen"), 0, 0, 0, 0, 0, 255, 1024, 1024, 0) +end --Horrible tone generator, using the engine's own RNG -function OnNextNote() +function OnNextNote_Title() + local r = rng_Seed() + local audioModule = getAudioModule(0) + --Melody 1 + midiCMD(audioModule, 0x40803c00 + ((r % 18) * 256), 0xFFFF0000, 0x00000000, 0x00000000) + r = rng_Seed() + --Melody 2 + midiCMD(audioModule, 0x40813000 + ((r % 20) * 256), 0xFFFF0000, 0x00000000, 0x00000000) + r = rng_Seed() + --Bass + if (r % 12) > 5 then + r = rng_Seed() + midiCMD(audioModule, 0x40821600 + ((r % 12) * 256), 0xFFFF0000, 0x00000000, 0x00000000) + end + --Rhythm + r = rng_Seed() + --Cymbals + if (r % 20) == 0 then + midiCMD(audioModule, 0x40836000, 0xFFFF0000, 0x00000000, 0x00000000) + else + midiCMD(audioModule, 0x40846000, 0xFFFF0000, 0x00000000, 0x00000000) + end + --Kick + if (r % 7) == 0 then + midiCMD(audioModule, 0x40852000, 0xFFFF0000, 0x00000000, 0x00000000) + end + --Snare + if (r % 9) == 0 then + midiCMD(audioModule, 0x40856000, 0xFFFF0000, 0x00000000, 0x00000000) + end + if Titlescreen then + timer_register(Globalstate, 250, "OnNextNote_Title") + end end -function NextBus() - +function ToSelection() + Titlescreen = false end -function PrevBus() - -end \ No newline at end of file diff --git a/dub.sdl b/dub.sdl index 3edac183..ea87f6e1 100644 --- a/dub.sdl +++ b/dub.sdl @@ -72,6 +72,15 @@ subPackage { sourcePaths "./test3/" importPaths "./test3/" } +/* subPackage { + name "test4" + dependency "pixelperfectengine" version="*" + targetType "executable" + targetPath "./bin-$ARCH-$PLATFORM/" + lflags "/PDB:.\\bin-$ARCH-$PLATFORM\\pixelperfectengine_test4.pdb" platform="windows" + sourcePaths "./test4/" + importPaths "./test4/" +} */ subPackage { name "test5" dependency "pixelperfectengine" version="*" diff --git a/pixelperfectengine/src/pixelperfectengine/scripting/lua.d b/pixelperfectengine/src/pixelperfectengine/scripting/lua.d index 34b710fc..dd01296d 100644 --- a/pixelperfectengine/src/pixelperfectengine/scripting/lua.d +++ b/pixelperfectengine/src/pixelperfectengine/scripting/lua.d @@ -136,17 +136,18 @@ extern(C) public int registerDFunction(alias Func)(lua_State* state) nothrow return 1; } } + /** - * Registers a D delegate to be called from Lua. + * Registers a D member function to be called from Lua. * Code is modified from MrcSnm's example found in the HipremeEngine. * Params: * state = The Lua state to handle the data from the Lua side of things. * Template params: * Func = The function to be registered. - * Note: When calling a D delegate from Lua, the first parameter is always a light user data - * containing the class instance that the delegate should be executed on. + * Note: When calling a D member function from Lua, the first parameter is always a light user data + * containing the class instance that the member function should be executed on. */ -extern (C) public int registerDDelegate(alias Func)(lua_State* state) nothrow +extern (C) public int registerDMemberFunc(alias Func)(lua_State* state) nothrow if(isSomeFunction!(Func)) { import std.traits:Parameters, ReturnType; alias ClassType = __traits(parent, Func); @@ -156,6 +157,10 @@ extern (C) public int registerDDelegate(alias Func)(lua_State* state) nothrow ClassType c; try { c = luaGetFromIndex!ClassType(state, stackCounter); + if (c is null) { + luaL_error(state, "Wrong lightweight userdata was passed to member function!"); + return 1; + } foreach_reverse(ref param; params) { stackCounter--; param = luaGetFromIndex!(typeof(param))(state, stackCounter); @@ -260,6 +265,14 @@ public struct LuaVar { public this(T)(T val) @safe pure nothrow { static if (is(T == void*) || is(T == LuaTable*)) { dataPtr = val; + } else static if (is(T == class) || is(T == interface)) { + void __workaround() @system pure nothrow { + dataPtr = cast(void*)val; + } + void _workaround() @trusted pure nothrow { + __workaround(); + } + _workaround(); } else static if (isIntegral!T || isBoolean!T) { dataInt = val; } else static if (isFloatingPoint!T) { @@ -499,6 +512,7 @@ public class LuaScript { throw new LuaException(LUA_ERRMEM, "Memory error!"); } registerLibForScripting(state); + /* lua_register(state, "getLuaState", ®isterDFunction!(function void*(){return this.getLuaState_internal();})); */ } ///Automatically deallocates the lua_State variable. ~this() { @@ -508,13 +522,16 @@ public class LuaScript { public lua_State* getState() @nogc nothrow pure { return state; } + /* protected void* getLuaState_internal() @nogc nothrow { + return cast(void*)state; + } */ /** * Executes the main function of the scipt. * Returns: A LuaVar variable with the appropriate return value if there was any. * Throws: A LuaException if the execution ran into an error, or the function isn't found. */ public LuaVar runMain() { - return callLuaFunc!(LuaVar)(state, "main"); + return callLuaFunc!(LuaVar)(state, "Main", cast(void*)state); } extern(C) private static const(char*) reader(lua_State* st, void* data, size_t* size) nothrow { diff --git a/pixelperfectengine/src/pixelperfectengine/scripting/lualib.d b/pixelperfectengine/src/pixelperfectengine/scripting/lualib.d index d3733755..53f446e8 100644 --- a/pixelperfectengine/src/pixelperfectengine/scripting/lualib.d +++ b/pixelperfectengine/src/pixelperfectengine/scripting/lualib.d @@ -31,22 +31,24 @@ public void registerLibForScripting(lua_State* state) { lua_register(state, "setLayerRenderingMode", ®isterDFunction!setLayerRenderingMode); lua_register(state, "scrollLayer", ®isterDFunction!(scrollLayer)); lua_register(state, "relScrollLayer", ®isterDFunction!(relScrollLayer)); - lua_register(state, "getLayerScrollX", ®isterDDelegate!(Layer.getSX)); - lua_register(state, "getLayerScrollY", ®isterDDelegate!(Layer.getSY)); + lua_register(state, "getLayerScrollX", ®isterDMemberFunc!(Layer.getSX)); + lua_register(state, "getLayerScrollY", ®isterDMemberFunc!(Layer.getSY)); + lua_register(state, "addTile", ®isterDMemberFunc!(ITileLayer.addTile)); + //lua_register(state, "setTileMaterial", ®isterDFunction!(setTileMaterial)); lua_register(state, "readMapping", ®isterDFunction!readMapping); lua_register(state, "tileByPixel", ®isterDFunction!tileByPixel); lua_register(state, "writeMapping", ®isterDFunction!writeMapping); - lua_register(state, "getTileWidth", ®isterDDelegate!(ITileLayer.getTileWidth)); - lua_register(state, "getTileHeight", ®isterDDelegate!(ITileLayer.getTileHeight)); - lua_register(state, "getMapWidth", ®isterDDelegate!(ITileLayer.getMX)); - lua_register(state, "getMapHeight", ®isterDDelegate!(ITileLayer.getMY)); - lua_register(state, "getTileWidth", ®isterDDelegate!(ITileLayer.getTX)); - lua_register(state, "getTileHeight", ®isterDDelegate!(ITileLayer.getTY)); - lua_register(state, "clearTilemap", ®isterDDelegate!(ITileLayer.clearTilemap)); - lua_register(state, "addTile", ®isterDDelegate!(ITileLayer.addTile)); - lua_register(state, "getTile", ®isterDDelegate!(ITileLayer.getTile)); - lua_register(state, "removeTile", ®isterDDelegate!(ITileLayer.removeTile)); + lua_register(state, "getTileWidth", ®isterDMemberFunc!(ITileLayer.getTileWidth)); + lua_register(state, "getTileHeight", ®isterDMemberFunc!(ITileLayer.getTileHeight)); + lua_register(state, "getMapWidth", ®isterDMemberFunc!(ITileLayer.getMX)); + lua_register(state, "getMapHeight", ®isterDMemberFunc!(ITileLayer.getMY)); + lua_register(state, "getTileWidth", ®isterDMemberFunc!(ITileLayer.getTX)); + lua_register(state, "getTileHeight", ®isterDMemberFunc!(ITileLayer.getTY)); + lua_register(state, "clearTilemap", ®isterDMemberFunc!(ITileLayer.clearTilemap)); + lua_register(state, "addTile", ®isterDMemberFunc!(ITileLayer.addTile)); + lua_register(state, "getTile", ®isterDMemberFunc!(ITileLayer.getTile)); + lua_register(state, "removeTile", ®isterDMemberFunc!(ITileLayer.removeTile)); lua_register(state, "ttl_setA", ®isterDFunction!ttl_setA); lua_register(state, "ttl_setB", ®isterDFunction!ttl_setB); @@ -63,23 +65,33 @@ public void registerLibForScripting(lua_State* state) { lua_register(state, "moveSprite", ®isterDFunction!(moveSprite)); lua_register(state, "relMoveSprite", ®isterDFunction!(relMoveSprite)); - lua_register(state, "getSpriteCoordinate", ®isterDDelegate!(ISpriteLayer.getSpriteCoordinate)); + lua_register(state, "getSpriteCoordinate", ®isterDMemberFunc!(ISpriteLayer.getSpriteCoordinate)); lua_register(state, "setSpriteSlice", ®isterDFunction!setSpriteSlice); - lua_register(state, "getSpriteSlice", ®isterDDelegate!(ISpriteLayer.getSlice)); - lua_register(state, "addSprite", ®isterDDelegate!(ISpriteLayer.addSprite)); - lua_register(state, "removeSprite", ®isterDDelegate!(ISpriteLayer.removeSprite)); - lua_register(state, "getPaletteID", ®isterDDelegate!(ISpriteLayer.getPaletteID)); - lua_register(state, "setPaletteID", ®isterDDelegate!(ISpriteLayer.setPaletteID)); - lua_register(state, "scaleSpriteHoriz", ®isterDDelegate!(ISpriteLayer.scaleSpriteHoriz)); - lua_register(state, "scaleSpriteVert", ®isterDDelegate!(ISpriteLayer.scaleSpriteVert)); - lua_register(state, "getScaleSpriteHoriz", ®isterDDelegate!(ISpriteLayer.getScaleSpriteHoriz)); - lua_register(state, "getScaleSpriteVert", ®isterDDelegate!(ISpriteLayer.getScaleSpriteVert)); + lua_register(state, "getSpriteSlice", ®isterDMemberFunc!(ISpriteLayer.getSlice)); + lua_register(state, "addSprite", ®isterDMemberFunc!(ISpriteLayer.addSprite)); + lua_register(state, "removeSprite", ®isterDMemberFunc!(ISpriteLayer.removeSprite)); + lua_register(state, "getPaletteID", ®isterDMemberFunc!(ISpriteLayer.getPaletteID)); + lua_register(state, "setPaletteID", ®isterDMemberFunc!(ISpriteLayer.setPaletteID)); + lua_register(state, "scaleSpriteHoriz", ®isterDMemberFunc!(ISpriteLayer.scaleSpriteHoriz)); + lua_register(state, "scaleSpriteVert", ®isterDMemberFunc!(ISpriteLayer.scaleSpriteVert)); + lua_register(state, "getScaleSpriteHoriz", ®isterDMemberFunc!(ISpriteLayer.getScaleSpriteHoriz)); + lua_register(state, "getScaleSpriteVert", ®isterDMemberFunc!(ISpriteLayer.getScaleSpriteVert)); - lua_register(state, "getBitmapWidth", ®isterDDelegate!(ABitmap.width)); - lua_register(state, "getBitmapHeight", ®isterDDelegate!(ABitmap.height)); + lua_register(state, "getBitmapWidth", ®isterDMemberFunc!(ABitmap.width)); + lua_register(state, "getBitmapHeight", ®isterDMemberFunc!(ABitmap.height)); + + lua_register(state, "getBitmapResource", ®isterDFunction!getBitmapResource); + lua_register(state, "loadBitmapResource", ®isterDFunction!loadBitmapResource); lua_register(state, "getAudioModule", ®isterDFunction!getAudioModule); lua_register(state, "midiCMD", ®isterDFunction!midiCMD); + + lua_register(state, "rng_Seed", ®isterDFunction!rng_Seed); + lua_register(state, "rng_Dice", ®isterDFunction!rng_Dice); + + lua_register(state, "timer_resume", ®isterDFunction!timer_resume); + lua_register(state, "timer_suspend", ®isterDFunction!timer_suspend); + lua_register(state, "timer_register", ®isterDFunction!timer_register); } package void scrollLayer(Layer l, LuaVar x, LuaVar y) { l.scroll(cast(int)x, cast(int)y); @@ -335,7 +347,7 @@ package int loadBitmapResource(string path, string resID, int paletteOffset) { } return 0; } -package int setTileMaterial(int layerID, int tileID, string resID, int paletteSh) { +/* package int setTileMaterial(int layerID, int tileID, string resID, int paletteSh) { ITileLayer itl = cast(ITileLayer)mainRaster.layerMap[layerID]; if (itl !is null) { try { @@ -347,11 +359,21 @@ package int setTileMaterial(int layerID, int tileID, string resID, int paletteSh } else { return 1; } -} +} */ -package ulong rngSeed() @nogc nothrow { +package ulong rng_Seed() @nogc nothrow { return rng.seed(); } -package ulong rngDice(uint s) @nogc nothrow { +package ulong rng_Dice(uint s) @nogc nothrow { return rng.dice(s); +} + +package void timer_suspend() { + timer.suspendTimer; +} +package void timer_resume() { + timer.resumeTimer; +} +package void timer_register(void* state, uint ms, string func) { + timer.register(delegate void(Duration){callLuaFunc!void(cast(lua_State*)state, func);}, msecs(ms)); } \ No newline at end of file diff --git a/pixelperfectengine/src/pixelperfectengine/system/timer.d b/pixelperfectengine/src/pixelperfectengine/system/timer.d index 21f01cea..ef19421c 100644 --- a/pixelperfectengine/src/pixelperfectengine/system/timer.d +++ b/pixelperfectengine/src/pixelperfectengine/system/timer.d @@ -95,6 +95,7 @@ public class CoarseTimer { timeSuspend = MonoTime.currTime; } } + alias suspend = suspendTimer; /** * Resumes timer and shifts all entries by given time delta. */ @@ -109,4 +110,5 @@ public class CoarseTimer { } } } + alias resume = resumeTimer; } diff --git a/test4/app.d b/test4/app.d index 26a9b931..0d6d55bc 100644 --- a/test4/app.d +++ b/test4/app.d @@ -36,6 +36,9 @@ import pixelperfectengine.audio.base.midiseq; //MIDI sequencer import pixelperfectengine.map.mapformat; //Other imports that might be important. Uncomment any you feel you'll need. /* import pixelperfectengine.system.common; */ +import pixelperfectengine.scripting.lua; +import pixelperfectengine.scripting.globals; + ///Our main function, needed for the program to operate. ///You can add `string[] args` if your either really need or really want. @@ -86,8 +89,8 @@ public class GameApp : SystemEventListener, InputListener { ///Contains pointer to the game field, so we can easily interact with it. SpriteLayer gameField; ///Contains the random number generator and its state. - RandomNumberGenerator rng; - ConfigurationProfile cfg; + //RandomNumberGenerator rng; + //ConfigurationProfile cfg; //Audio related stuff goes here. //Note: some of the audio stuff is preliminary. It works, but cannot handle certain cases, such as sample rate mismatches, or device disconnection. //Sequencer is untested as of now due to a lack of time and manpower. @@ -114,23 +117,40 @@ public class GameApp : SystemEventListener, InputListener { textLayer.paletteOffset = 512; //Sets the palette offset to 512. You might want to change this to the value to the place where you loaded your GUI palette textLayer.masterVal = 127; //Sets the master value for the alpha blending, making this layer semi-transparent initially. - cfg = new ConfigurationProfile(); //Creates and loads the configuration profile. + //cfg = new ConfigurationProfile(); //Creates and loads the configuration profile. //Comment the next part out, if you're having too much trouble with audio working, since you still can add sound later on. //audio related part begin AudioDeviceHandler.initAudioDriver(OS_PREFERRED_DRIVER); //Initializes the driver - AudioSpecs as = AudioSpecs(predefinedFormats[PredefinedFormats.FP32], cfg.audioFrequency, 0, 2, cfg.audioBufferLen, + AudioSpecs as = AudioSpecs(predefinedFormats[PredefinedFormats.FP32], 48_000, 0, 2, cfg.audioBufferLen, Duration.init); //Sets up a default audio specification - adh = new AudioDeviceHandler(as, cfg.audioBufferLen, cfg.audioBufferLen / cfg.audioFrameLen); //Creates a new AudioDeviceHandler and sets up the basics + adh = new AudioDeviceHandler(as, 1024, 1024 / 128); //Creates a new AudioDeviceHandler and sets up the basics adh.initAudioDevice(-1); //Initializes the default device modMan = new ModuleManager(adh); //Initializes the module manager modCfg = new ModuleConfig(modMan); //Initializes the module configurator - modCfg.loadConfigFromFile("yourAudioConfiguration.sdl");//This line loads an audio configuration file (make sure you have a valid one - create one with the ADK/test1!) + modCfg.loadConfigFromFile("../assets/test4_audio.sdl");//This line loads an audio configuration file (make sure you have a valid one - create one with the ADK/test1!) modCfg.compile(false); //Compiles the current module configuration. midiSeq = new SequencerM1(modMan.moduleList, modCfg.midiRouting, modCfg.midiGroups); modMan.runAudioThread(); //Runs the audio thread. //audio related part end // + { + import pixelperfectengine.system.input.scancode; + ih.addBinding(BindingCode(ScanCode.UP, 0, Devicetype.Keyboard, 0, KeyModifier.LockKeys), InputBinding("up")); + ih.addBinding(BindingCode(ScanCode.DOWN, 0, Devicetype.Keyboard, 0, KeyModifier.LockKeys), InputBinding("down")); + ih.addBinding(BindingCode(ScanCode.LEFT, 0, Devicetype.Keyboard, 0, KeyModifier.LockKeys), InputBinding("left")); + ih.addBinding(BindingCode(ScanCode.RIGHT, 0, Devicetype.Keyboard, 0, KeyModifier.LockKeys), InputBinding("right")); + ih.addBinding(BindingCode(ScanCode.SPACE, 0, Devicetype.Keyboard, 0, KeyModifier.LockKeys), InputBinding("space")); + ih.addBinding(BindingCode(ScanCode.LALT, 0, Devicetype.Keyboard, 0, KeyModifier.LockKeys), InputBinding("leftalt")); + + ih.addBinding(BindingCode(11, 0, Devicetype.Joystick), InputBinding("up")); + ih.addBinding(BindingCode(12, 0, Devicetype.Joystick), InputBinding("down")); + ih.addBinding(BindingCode(13, 0, Devicetype.Joystick), InputBinding("left")); + ih.addBinding(BindingCode(14, 0, Devicetype.Joystick), InputBinding("right")); + ih.addBinding(BindingCode(1, 0, Devicetype.Joystick), InputBinding("space")); + ih.addBinding(BindingCode(2, 0, Devicetype.Joystick), InputBinding("leftalt")); + } + } void whereTheMagicHappens() { while (stateFlags.isRunning) {