diff --git a/WickedEngine/MainComponent.cpp b/WickedEngine/MainComponent.cpp index 0ce45bf0a..5158bdf80 100644 --- a/WickedEngine/MainComponent.cpp +++ b/WickedEngine/MainComponent.cpp @@ -48,14 +48,16 @@ void MainComponent::run() { static wiTimer timer = wiTimer(); static double accumulator = 0.0; + const double elapsedTime = timer.elapsed() / 1000.0; + timer.record(); + + wiLua::GetGlobal()->SetDeltaTime(elapsedTime); if (frameskip) { - accumulator += timer.elapsed() / 1000.0; + accumulator += elapsedTime; if (accumulator > applicationControlLostThreshold) //application probably lost control accumulator = 0; - timer.record(); - while (accumulator >= targetFrameRateInv) { diff --git a/WickedEngine/wiLua.cpp b/WickedEngine/wiLua.cpp index d8cff5edb..2c078496b 100644 --- a/WickedEngine/wiLua.cpp +++ b/WickedEngine/wiLua.cpp @@ -27,6 +27,7 @@ wiLua::wiLua() m_luaState = luaL_newstate(); luaL_openlibs(m_luaState); RegisterFunc("debugout", DebugOut); + RunText(wiLua_Globals); } wiLua::~wiLua() @@ -58,7 +59,6 @@ wiLua* wiLua::GetGlobal() wiResourceManager_BindLua::Bind(); wiLoader_BindLua::Bind(); - globalLua->RunText(wiLua_Globals); } return globalLua; } @@ -190,6 +190,13 @@ void wiLua::AddInt(const string& name, int data) lua_setfield(m_luaState, -2, name.c_str()); } +void wiLua::SetDeltaTime(double dt) +{ + lua_getglobal(m_luaState, "wakeUpWaitingThreads"); + SSetDouble(m_luaState, dt); + lua_call(m_luaState, 1, 0); +} + int wiLua::DebugOut(lua_State* L) { int argc = lua_gettop(L); @@ -290,6 +297,10 @@ void wiLua::SSetFloat4(lua_State* L, const XMFLOAT4& data) SSetFloat(L, data.z); SSetFloat(L, data.w); } +void wiLua::SSetDouble(lua_State* L, double data) +{ + lua_pushnumber(L, (lua_Number)data); +} void wiLua::SSetString(lua_State* L, const string& data) { lua_pushstring(L, data.c_str()); diff --git a/WickedEngine/wiLua.h b/WickedEngine/wiLua.h index 39717f81b..4bc237a24 100644 --- a/WickedEngine/wiLua.h +++ b/WickedEngine/wiLua.h @@ -57,6 +57,9 @@ public: //add int member to registered object void AddInt(const string& name, int data); + //set delta time to use with lua + void SetDeltaTime(double dt); + //Static function wrappers from here on //get string from lua on stack position @@ -94,6 +97,8 @@ public: static void SSetFloat3(lua_State* L, const XMFLOAT3& data); //push float4 to lua stack static void SSetFloat4(lua_State* L, const XMFLOAT4& data); + //push double to lua stack + static void SSetDouble(lua_State* L, double data); //push string to lua stack static void SSetString(lua_State* L, const string& data); //push pointer (light userdata) to lua stack diff --git a/WickedEngine/wiLua_Globals.h b/WickedEngine/wiLua_Globals.h index e27b9e8fd..a98468b9a 100644 --- a/WickedEngine/wiLua_Globals.h +++ b/WickedEngine/wiLua_Globals.h @@ -5,6 +5,9 @@ static const char* wiLua_Globals = R"( -- Wicked Engine lua globals ------------------------------------------ +-- Print prints to debug output by default +local print = debugout + -- Get object properties getprops = function(object) for key,value in pairs(getmetatable(object)) do @@ -24,4 +27,90 @@ function rand() X2 = V - X1*D20 return V/D40 end + + + +-- This table is indexed by coroutine and simply contains the time at which the coroutine +-- should be woken up. +local WAITING_ON_TIME = {} + +-- Keep track of how long the game has been running. +local CURRENT_TIME = 0 + +function waitSeconds(seconds) + -- Grab a reference to the current running coroutine. + local co = coroutine.running() + + -- If co is nil, that means we're on the main process, which isn't a coroutine and can't yield + assert(co ~= nil, "The main thread cannot wait!") + + -- Store the coroutine and its wakeup time in the WAITING_ON_TIME table + local wakeupTime = CURRENT_TIME + seconds + WAITING_ON_TIME[co] = wakeupTime + + -- And suspend the process + return coroutine.yield(co) +end + +-- This function should be called once per game logic update with the amount of time +-- that has passed since it was last called +function wakeUpWaitingThreads(deltaTime) + CURRENT_TIME = CURRENT_TIME + deltaTime + + -- First, grab a list of the threads that need to be woken up. They'll need to be removed + -- from the WAITING_ON_TIME table which we don't want to try and do while we're iterating + -- through that table, hence the list. + local threadsToWake = {} + for co, wakeupTime in pairs(WAITING_ON_TIME) do + if wakeupTime < CURRENT_TIME then + table.insert(threadsToWake, co) + end + end + + -- Now wake them all up. + for _, co in ipairs(threadsToWake) do + WAITING_ON_TIME[co] = nil -- Setting a field to nil removes it from the table + coroutine.resume(co) + end +end + + +-- This function is just a quick wrapper to start a coroutine. +function runProcess(func) + local co = coroutine.create(func) + return coroutine.resume(co) +end + + +-- Signal helpers +local WAITING_ON_SIGNAL = {} + +-- Block coroutine while waiting for a signal +function waitSignal(signalName) + -- Same check as in waitSeconds; the main thread cannot wait + local co = coroutine.running() + assert(co ~= nil, "The main thread cannot wait!") + + if WAITING_ON_SIGNAL[signalStr] == nil then + -- If there wasn't already a list for this signal, start a new one. + WAITING_ON_SIGNAL[signalName] = { co } + else + table.insert(WAITING_ON_SIGNAL[signalName], co) + end + + return coroutine.yield() +end + +-- Send a signal on which a coroutine can be blocked +function signal(signalName) + local threads = WAITING_ON_SIGNAL[signalName] + if threads == nil then return end + + WAITING_ON_SIGNAL[signalName] = nil + for _, co in ipairs(threads) do + coroutine.resume(co) + end +end + + )";