From f1ef4bfc9dc07c8acd29544535cac9ec78819166 Mon Sep 17 00:00:00 2001 From: Kiritow <1362050620@qq.com> Date: Sat, 10 Aug 2019 21:36:15 +0800 Subject: [PATCH] =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E4=BA=8B=E4=BB=B6=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将事件循环从Window类移动到Top Level. --- LuaEngine.cpp | 569 ++++++++++++++++++++++++++++++++------------------ LuaEngine.h | 1 + LuaYard.cpp | 3 +- 3 files changed, 363 insertions(+), 210 deletions(-) diff --git a/LuaEngine.cpp b/LuaEngine.cpp index efc03fe..3bd3933 100644 --- a/LuaEngine.cpp +++ b/LuaEngine.cpp @@ -68,6 +68,13 @@ void check(lua_State* L, const vector& typearr, const vector& } } +// Generate SDL error on lua stack. +// NOTE: Never returns. If this function is used in C++ context, you should compile Lua as C++. +void LuaSDLError(lua_State* L) +{ + luaL_error(L, "SDLError: %s", SDL_GetError()); +} + void ConvertMusicAsyncImpl(const string& filename, const string& targetname, int ticket) { string command = "bin\\ffmpeg.exe -y -loglevel error -hide_banner -i \""s + filename + "\" \"" + targetname + "\""; @@ -162,218 +169,57 @@ struct Window return 0; } - static int start(lua_State* L) - { - check(L, { LUA_TUSERDATA }); - Window* p = (Window*)lua_touserdata(L, 1); - lua_settop(L, 1); - lua_pushlightuserdata(L, p); - lua_gettable(L, LUA_REGISTRYINDEX); - - bool running = true; - - SDL_Event e; - while (running && SDL_WaitEvent(&e)) - { - switch (e.type) - { - case SDL_MOUSEBUTTONDOWN: - { - if (lua_getfield(L, -1, "onmousedown") != LUA_TNIL) - { - lua_pushnumber(L, e.button.x); - lua_pushnumber(L, e.button.y); - lua_pushnumber(L, e.button.button); - const char* arr[8]; - int ret = GetMouseState(arr, e.button.state); - lua_newtable(L); - for (int i = 0; i < ret; i++) - { - lua_pushboolean(L, 1); - lua_setfield(L, -2, arr[i]); - } - lua_call(L, 4, LUA_MULTRET); - } - else lua_pop(L, 1); - break; - } - case SDL_MOUSEBUTTONUP: - { - if (lua_getfield(L, -1, "onmouseup") != LUA_TNIL) - { - lua_pushnumber(L, e.button.x); - lua_pushnumber(L, e.button.y); - lua_pushnumber(L, e.button.button); - const char* arr[8]; - int ret = GetMouseState(arr, e.button.state); - lua_newtable(L); - for (int i = 0; i < ret; i++) - { - lua_pushboolean(L, 1); - lua_setfield(L, -2, arr[i]); - } - lua_call(L, 3, LUA_MULTRET); - } - else lua_pop(L, 1); - break; - } - case SDL_MOUSEMOTION: - { - if (lua_getfield(L, -1, "onmousemove") != LUA_TNIL) - { - lua_pushnumber(L, e.motion.x); - lua_pushnumber(L, e.motion.y); - lua_pushnumber(L, e.motion.xrel); - lua_pushnumber(L, e.motion.yrel); - const char* arr[8]; - int ret = GetMouseState(arr, e.button.state); - lua_newtable(L); - for (int i = 0; i < ret; i++) - { - lua_pushboolean(L, 1); - lua_setfield(L, -2, arr[i]); - } - lua_call(L, 5, LUA_MULTRET); - } - else lua_pop(L, 1); - break; - } - case SDL_QUIT: - { - if (lua_getfield(L, -1, "onquit") != LUA_TNIL) - { - lua_call(L, 0, LUA_MULTRET); - } - else lua_pop(L, 1); - running = 0; - break; - } - case SDL_KEYDOWN: - { - if (lua_getfield(L, -1, "onkeydown") != LUA_TNIL) - { - lua_pushnumber(L, e.key.keysym.sym); - lua_call(L, 1, LUA_MULTRET); - } - else lua_pop(L, 1); - break; - } - case SDL_KEYUP: - { - if (lua_getfield(L, -1, "onkeyup") != LUA_TNIL) - { - lua_pushnumber(L, e.key.keysym.sym); - lua_call(L, 1, LUA_MULTRET); - } - else lua_pop(L, 1); - break; - } - case SDL_USEREVENT: - { - switch (e.user.code) - { - case 1001: - { - LuaTimerCallbackData* pd = (LuaTimerCallbackData* )e.user.data1; - lua_pushlightuserdata(L, pd->p); - lua_gettable(L, LUA_REGISTRYINDEX); - lua_pushfstring(L, "tmcb%d", pd->id); - lua_gettable(L, -2); - delete pd; - lua_call(L, 0, LUA_MULTRET); - lua_pop(L, 1); - break; - } - case 1002: - { - // È«¾Ö»Øµ÷, Òì²½²Ù×÷ÎÞ·µ»ØÖµ - lua_pushfstring(L, "cb%d", *(int*)e.user.data1); - lua_gettable(L, LUA_REGISTRYINDEX); - delete e.user.data1; - lua_call(L, 0, LUA_MULTRET); - break; - } - } - break; - case 1003: - { - // ÒôÀÖ²¥·ÅÍê±Ï - if (lua_getfield(L, -1, "onmusicover") != LUA_TNIL) - { - lua_call(L, 0, LUA_MULTRET); - } - else lua_pop(L, 1); - break; - } - case 1004: - { - // ƵµÀ²¥·ÅÍê±Ï - if (lua_getfield(L, -1, "onchannelover") != LUA_TNIL) - { - lua_pushinteger(L, *(int*)e.user.data1); - delete e.user.data1; - lua_call(L, 1, LUA_MULTRET); - } - else lua_pop(L, 1); - break; - } - } - default: - { - cout << e.type << endl; - } - } - } - - return 0; - } - static int set_event_handler(lua_State* L) { - check(L, { LUA_TUSERDATA, LUA_TSTRING, LUA_TFUNCTION }); + check(L, { LUA_TUSERDATA, LUA_TSTRING, LUA_TFUNCTION }, { "window" }); + if (strcmp(lua_tostring(L, 2), "quit") == 0) // quitʼþÌØÊâ´¦Àí + { + lua_pushlightuserdata(L, &StartEngine); + lua_gettable(L, LUA_REGISTRYINDEX); + lua_getfield(L, -1, "onquit"); + lua_pushvalue(L, 3); + lua_setfield(L, -3, "onquit"); + return 1; // return old callback. + } + Window* p = (Window*)lua_touserdata(L, 1); - lua_pushlightuserdata(L, p); - lua_gettable(L, LUA_REGISTRYINDEX); - lua_pushfstring(L, "on%s", lua_tostring(L, 2)); - lua_pushvalue(L, 3); - lua_settable(L, -3); - return 0; - } + if (p->wnd) + { + lua_pushlightuserdata(L, p->wnd); + if (lua_gettable(L, LUA_REGISTRYINDEX) != LUA_TTABLE) + { + lua_pop(L, 1); - static int setTimeout(lua_State* L) - { - check(L, { LUA_TUSERDATA, LUA_TFUNCTION, LUA_TNUMBER }); // ms - Window* p = (Window*)lua_touserdata(L, 1); + lua_pushlightuserdata(L, p->wnd); - LuaTimerCallbackData* pd = new LuaTimerCallbackData(); - pd->p = p; - pd->type = 0; - pd->id = SDL_AddTimer(lua_tointeger(L, 3), LuaTimerCallbackGate, pd); + lua_newtable(L); + lua_pushfstring(L, "on%s", lua_tostring(L, 2)); + lua_pushvalue(L, 3); + lua_settable(L, -3); - lua_pushlightuserdata(L, p); - lua_gettable(L, LUA_REGISTRYINDEX); - lua_pushfstring(L, "tmcb%d", pd->id); - lua_pushvalue(L, 2); - lua_settable(L, -3); - return 0; - } + lua_settable(L, LUA_REGISTRYINDEX); - static int setInterval(lua_State* L) - { - check(L, { LUA_TUSERDATA, LUA_TFUNCTION, LUA_TNUMBER }); // ms - Window* p = (Window*)lua_touserdata(L, 1); - - LuaTimerCallbackData* pd = new LuaTimerCallbackData(); - pd->p = p; - pd->type = 1; - pd->id = SDL_AddTimer(lua_tointeger(L, 3), LuaTimerCallbackGate, pd); - - lua_pushlightuserdata(L, p); - lua_gettable(L, LUA_REGISTRYINDEX); - lua_pushfstring(L, "tmcb%d", pd->id); - lua_pushvalue(L, 2); - lua_settable(L, -3); - return 0; + lua_pushnil(L); // No old callback. Will return empty. + } + else + { + lua_pushfstring(L, "on%s", lua_tostring(L, 2)); + lua_pushvalue(L, -1); + // window, eventName, callback, windowCBTable, onEvent, onEvent + lua_gettable(L, -3); + // window, eventName, callback, windowCBTable, onEvent, oldCallback + lua_pushvalue(L, -2); + lua_pushvalue(L, 3); + // window, eventName, callback, windowCBTable, onEvent, oldCallback, onEvent, callback + lua_settable(L, -5); + // window, eventName, callback, windowCBTable, onEvent, oldCallback + } + return 1; + } + else + { + return luaL_error(L, "Unable to add event listener to null window."); + } } static int showWindow(lua_State* L) @@ -418,9 +264,6 @@ struct Window lua_pushstring(L, "window"); lua_setfield(L, -2, "type"); setfn(L, close, "close"); setfn(L, set_event_handler, "on"); - setfn(L, start, "start"); - setfn(L, setTimeout, "setTimeout"); - setfn(L, setInterval, "setInterval"); setfn(L, showWindow, "show"); setfn(L, hideWindow, "hide"); @@ -870,6 +713,25 @@ struct Font } }; +Mix_Chunk* Mix_LoadWAVEx(const char* filepath) +{ + SDL_RWops* fileData = SDL_RWFromFile(filepath, "rb"); + if (!fileData) + { + std::cout << "Mix_LoadWAVEx() failed to call SDL_RWFromFile().\n\t\"" << SDL_GetError() << "\"" << std::endl; + return NULL; + } + + Mix_Chunk* chunk = Mix_LoadWAV_RW(fileData, 1); + if (!chunk) + { + std::cout << "Mix_LoadWAVEx() failed to call Mix_LoadWAV_RW().\n\t\"" << SDL_GetError() << "\"" << std::endl; + return NULL; + } + + return chunk; +} + struct Chunk { Mix_Chunk* chunk; @@ -928,7 +790,7 @@ struct Chunk const char* filename = lua_tostring(L, 1); cout << "LoadWAV: " << filename << endl; - c->chunk = Mix_LoadWAV(filename); + c->chunk = Mix_LoadWAVEx(filename); cout << "Load chunk error: " << SDL_GetError() << endl; return 1; @@ -1365,6 +1227,62 @@ void _Global_On_Channel_Finished(int channel) SDL_PushEvent(&e); } +static int setTimeout(lua_State* L) +{ + check(L, { LUA_TFUNCTION, LUA_TNUMBER }); // setTimeout(cb: function, ms: number) + + LuaTimerCallbackData* pd = new LuaTimerCallbackData(); + pd->p = nullptr; + pd->type = 0; + pd->id = SDL_AddTimer(lua_tointeger(L, 2), LuaTimerCallbackGate, pd); + + lua_pushlightuserdata(L, &setTimeout); + if (lua_gettable(L, LUA_REGISTRYINDEX) != LUA_TTABLE) + { + lua_pop(L, 1); + + lua_pushlightuserdata(L, &setTimeout); + lua_newtable(L); + lua_pushvalue(L, 1); + lua_seti(L, -2, pd->id); // { [timerID] = callback } + + lua_settable(L, LUA_REGISTRYINDEX); // registry[&setTimeout] = timerCallbackTable + } + else + { + lua_pushvalue(L, 1); + lua_seti(L, -2, pd->id); // timerCallbackTable[timerID] = callback + } + return 0; +} + +static int setInterval(lua_State* L) +{ + check(L, { LUA_TFUNCTION, LUA_TNUMBER }); // setTimeout(cb: function, ms: number) + + LuaTimerCallbackData* pd = new LuaTimerCallbackData(); + pd->p = nullptr; + pd->type = 1; + pd->id = SDL_AddTimer(lua_tointeger(L, 2), LuaTimerCallbackGate, pd); + + lua_pushlightuserdata(L, &setTimeout); + if (lua_gettable(L, LUA_REGISTRYINDEX) != LUA_TTABLE) + { + lua_newtable(L); + lua_pushvalue(L, 1); + lua_seti(L, -2, pd->id); // { [timerID] = callback } + + lua_pushlightuserdata(L, &setTimeout); + lua_settable(L, LUA_REGISTRYINDEX); // registry[&setTimeout] = timerCallbackTable + } + else + { + lua_pushvalue(L, 1); + lua_seti(L, -2, pd->id); // timerCallbackTable[timerID] = callback + } + return 0; +} + int InitEngine(lua_State* L) { int ret; @@ -1389,10 +1307,243 @@ int InitEngine(lua_State* L) reg_in_lua(L, Chunk::create, "Chunk"); reg_in_lua(L, Music::create, "Music"); reg_in_lua(L, MusicPlayer::create, "MusicPlayer"); + + // Global functions reg_in_lua(L, ConvertMusicAsync, "ConvertMusic"); + reg_in_lua(L, setTimeout, "SetTimeout"); + reg_in_lua(L, setInterval, "SetInterval"); + // Global Library LibFS::create(L); lua_setglobal(L, "fs"); + // Registry table + lua_pushlightuserdata(L, &StartEngine); + lua_newtable(L); + lua_settable(L, LUA_REGISTRYINDEX); + + return 0; +} + +int LuaRunCallback(lua_State* L, int nargs, int nresults = LUA_MULTRET) +{ + int ret = lua_pcall(L, nargs, nresults, 0); + if (ret) + { + switch (ret) + { + case LUA_ERRRUN: + cout << "LuaRunError: " << lua_tostring(L, -1) << endl; + break; + case LUA_ERRMEM: + cout << "LuaMemError: " << lua_tostring(L, -1) << endl; + break; + case LUA_ERRERR: + cout << "LuaRecursiveError: " << lua_tostring(L, -1) << endl; + break; + case LUA_ERRGCMM: + cout << "LuaGCError: " << lua_tostring(L, -1) << endl; + break; + default: + cout << "LuaError: " << lua_tostring(L, -1) << endl; + break; + } + lua_pop(L, 1); + return -1; + } + return 0; +} + +int StartEngine(lua_State* L) +{ + // The Event Loop + bool running = true; + + SDL_Event e; + while (running && SDL_WaitEvent(&e)) + { + switch (e.type) + { + case SDL_MOUSEBUTTONDOWN: + { + lua_pushlightuserdata(L, SDL_GetWindowFromID(e.button.windowID)); + lua_gettable(L, LUA_REGISTRYINDEX); + if (lua_getfield(L, -1, "onmousedown") != LUA_TNIL) + { + lua_pushnumber(L, e.button.x); + lua_pushnumber(L, e.button.y); + lua_pushnumber(L, e.button.button); + const char* arr[8]; + int ret = GetMouseState(arr, e.button.state); + lua_newtable(L); + for (int i = 0; i < ret; i++) + { + lua_pushboolean(L, 1); + lua_setfield(L, -2, arr[i]); + } + LuaRunCallback(L, 4); + } + else lua_pop(L, 1); + lua_pop(L, 1); + break; + } + case SDL_MOUSEBUTTONUP: + { + lua_pushlightuserdata(L, SDL_GetWindowFromID(e.button.windowID)); + lua_gettable(L, LUA_REGISTRYINDEX); + if (lua_getfield(L, -1, "onmouseup") != LUA_TNIL) + { + lua_pushnumber(L, e.button.x); + lua_pushnumber(L, e.button.y); + lua_pushnumber(L, e.button.button); + const char* arr[8]; + int ret = GetMouseState(arr, e.button.state); + lua_newtable(L); + for (int i = 0; i < ret; i++) + { + lua_pushboolean(L, 1); + lua_setfield(L, -2, arr[i]); + } + LuaRunCallback(L, 4); + } + else lua_pop(L, 1); + lua_pop(L, 1); + break; + } + case SDL_MOUSEMOTION: + { + lua_pushlightuserdata(L, SDL_GetWindowFromID(e.motion.windowID)); + lua_gettable(L, LUA_REGISTRYINDEX); + if (lua_getfield(L, -1, "onmousemove") != LUA_TNIL) + { + lua_pushnumber(L, e.motion.x); + lua_pushnumber(L, e.motion.y); + lua_pushnumber(L, e.motion.xrel); + lua_pushnumber(L, e.motion.yrel); + const char* arr[8]; + int ret = GetMouseState(arr, e.button.state); + lua_newtable(L); + for (int i = 0; i < ret; i++) + { + lua_pushboolean(L, 1); + lua_setfield(L, -2, arr[i]); + } + LuaRunCallback(L, 5); + } + else lua_pop(L, 1); + lua_pop(L, 1); + break; + } + case SDL_QUIT: + { + running = 0; + + lua_pushlightuserdata(L, &StartEngine); + lua_gettable(L, LUA_REGISTRYINDEX); + + if (lua_getfield(L, -1, "onquit") != LUA_TNIL) + { + if (!LuaRunCallback(L, 0, 1)) + { + if (lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1)) + { + running = 1; + } + lua_pop(L, 1); + } + } + else lua_pop(L, 1); + + lua_pop(L, 1); + break; + } + case SDL_KEYDOWN: + { + lua_pushlightuserdata(L, SDL_GetWindowFromID(e.key.windowID)); + lua_gettable(L, LUA_REGISTRYINDEX); + if (lua_getfield(L, -1, "onkeydown") != LUA_TNIL) + { + lua_pushnumber(L, e.key.keysym.sym); + LuaRunCallback(L, 1); + } + else lua_pop(L, 1); + lua_pop(L, 1); + break; + } + case SDL_KEYUP: + { + lua_pushlightuserdata(L, SDL_GetWindowFromID(e.key.windowID)); + lua_gettable(L, LUA_REGISTRYINDEX); + if (lua_getfield(L, -1, "onkeyup") != LUA_TNIL) + { + lua_pushnumber(L, e.key.keysym.sym); + LuaRunCallback(L, 1); + } + else lua_pop(L, 1); + lua_pop(L, 1); + break; + } + case SDL_USEREVENT: + { + switch (e.user.code) + { + case 1001: + { + // ¶¨Ê±Æ÷»Øµ÷ + LuaTimerCallbackData* pd = (LuaTimerCallbackData*)e.user.data1; + lua_pushlightuserdata(L, &setTimeout); + lua_gettable(L, LUA_REGISTRYINDEX); // registry[&setTimeout] + lua_geti(L, -1, pd->id); // registry[&setTimeout][timerID] + delete pd; + LuaRunCallback(L, 0); + lua_pop(L, 1); + break; + } + case 1002: + { + // È«¾Ö»Øµ÷, Òì²½²Ù×÷ÎÞ·µ»ØÖµ + lua_pushfstring(L, "cb%d", *(int*)e.user.data1); + lua_gettable(L, LUA_REGISTRYINDEX); + delete e.user.data1; + LuaRunCallback(L, 0); + break; + } + case 1003: + + // ÒôÀÖ²¥·ÅÍê±Ï + lua_pushlightuserdata(L, &StartEngine); + lua_gettable(L, LUA_REGISTRYINDEX); + if (lua_getfield(L, -1, "onmusicover") != LUA_TNIL) + { + LuaRunCallback(L, 0); + } + else lua_pop(L, 1); + lua_pop(L, 1); + break; + } + case 1004: + { + // ƵµÀ²¥·ÅÍê±Ï + lua_pushlightuserdata(L, &StartEngine); + lua_gettable(L, LUA_REGISTRYINDEX); + if (lua_getfield(L, -1, "onchannelover") != LUA_TNIL) + { + lua_pushinteger(L, *(int*)e.user.data1); + delete e.user.data1; + LuaRunCallback(L, 1); + } + else lua_pop(L, 1); + lua_pop(L, 1); + break; + } + break; + } + default: + { + cout << e.type << endl; + } + } + } + return 0; } diff --git a/LuaEngine.h b/LuaEngine.h index 5ac6ba3..c1fe0e9 100644 --- a/LuaEngine.h +++ b/LuaEngine.h @@ -3,4 +3,5 @@ int InitEngine(lua_State* L); +int StartEngine(lua_State* L); int StopEngine(); diff --git a/LuaYard.cpp b/LuaYard.cpp index 9098a70..3674af3 100644 --- a/LuaYard.cpp +++ b/LuaYard.cpp @@ -9,10 +9,11 @@ int main() LuaVM L; InitEngine(L); cout << " Started." << endl; - if (luaL_dofile(L, "code/game.lua")) + if (luaL_dofile(L, "code/init.lua")) { cout << lua_tostring(L, -1) << endl; } + StartEngine(L); cout << " Stopped." << endl; } while (0); StopEngine();