LuaYard/LuaEngine.cpp
2019-08-18 02:01:00 +08:00

1635 lines
39 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "LuaEngine.h"
#include <iostream>
#include <string>
#include <thread>
#include <vector>
#include <cstdlib>
#include "SDL2/include/SDL.h"
#include "SDL2/include/SDL_mixer.h"
#include "SDL2/include/SDL_ttf.h"
#include "SDL2/include/SDL_image.h"
#include "PlatAPI.h"
#include "LuaEnum.h"
#include "LuaCommon.h"
#include "LuaNetwork.h"
using namespace std;
// Global single-thread unprotected event callback id counter
int callback_counter = 1;
// 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 + "\"";
cout << command << endl;
system(command.c_str());
SDL_Event e;
e.type = SDL_USEREVENT;
e.user.code = 1002; // General zero ret callback.
e.user.data1 = new int(ticket);
e.user.data2 = nullptr;
SDL_PushEvent(&e);
}
static int ConvertMusicAsync(lua_State* L)
{
check(L, { LUA_TSTRING, LUA_TSTRING, LUA_TFUNCTION });
lua_pushfstring(L, "cb%d", callback_counter);
lua_pushvalue(L, 3);
lua_settable(L, LUA_REGISTRYINDEX);
string filename(lua_tostring(L, 1));
string targetname(lua_tostring(L, 2));
thread td(ConvertMusicAsyncImpl, filename, targetname, callback_counter);
td.detach();
lua_pushnumber(L, callback_counter);
callback_counter++;
return 1;
}
struct LuaTimerCallbackData
{
void* p;
int id;
int type; // 0=setTimeout, 1=setInterval
};
Uint32 LuaTimerCallbackGate(Uint32 interval, void* param)
{
SDL_Event e;
e.type = SDL_USEREVENT;
e.user.code = 1001;
e.user.data1 = param;
SDL_PushEvent(&e);
return ((LuaTimerCallbackData*)(param))->type ? interval : 0;
}
int GetMouseState(const char** output, Uint32 state)
{
int i = 0;
if (state & SDL_BUTTON_LMASK)
{
output[i++] = "left";
}
if (state & SDL_BUTTON_MMASK)
{
output[i++] = "middle";
}
if (state & SDL_BUTTON_RMASK)
{
output[i++] = "right";
}
if (state & SDL_BUTTON_X1MASK)
{
output[i++] = "x1";
}
if (state & SDL_BUTTON_X2MASK)
{
output[i++] = "x2";
}
return i;
}
int LuaColorToColor(lua_State* L, int index, SDL_Color& c)
{
if (lua_getfield(L, index, "type") != LUA_TSTRING)
{
lua_pop(L, 1);
return -1;
}
const char* type = lua_tostring(L, -1);
if (strcmp(type, "rgba") == 0)
{
lua_pop(L, 1);
lua_getfield(L, index, "r");
c.r = lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "g");
c.g = lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "b");
c.b = lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "a");
c.a = lua_tointeger(L, -1);
lua_pop(L, 1);
return 0;
}
else
{
return -1;
}
}
#define setfn(L, cfunc, name) lua_pushcfunction(L, cfunc); lua_setfield(L, -2, name)
struct Window
{
SDL_Window* wnd;
static int close(lua_State* L)
{
check(L, { LUA_TUSERDATA });
cout << "In Window::close" << endl;
Window* p = (Window*)lua_touserdata(L, 1);
if (p->wnd)
{
// release data table
lua_pushlightuserdata(L, p);
lua_pushnil(L);
lua_settable(L, LUA_REGISTRYINDEX);
SDL_DestroyWindow(p->wnd);
p->wnd = nullptr;
}
return 0;
}
static int set_event_handler(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TSTRING, LUA_TFUNCTION }, { "window" });
if (strcmp(lua_tostring(L, 2), "quit") == 0) // quit<69>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><E2B4A6>
{
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);
if (p->wnd)
{
lua_pushlightuserdata(L, p->wnd);
if (lua_gettable(L, LUA_REGISTRYINDEX) != LUA_TTABLE)
{
lua_pop(L, 1);
lua_pushlightuserdata(L, p->wnd);
lua_newtable(L);
lua_pushfstring(L, "on%s", lua_tostring(L, 2));
lua_pushvalue(L, 3);
lua_settable(L, -3);
lua_settable(L, LUA_REGISTRYINDEX);
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)
{
check(L, { LUA_TUSERDATA });
Window* p = (Window*)lua_touserdata(L, 1);
SDL_ShowWindow(p->wnd);
return 0;
}
static int hideWindow(lua_State* L)
{
check(L, { LUA_TUSERDATA });
Window* p = (Window*)lua_touserdata(L, 1);
SDL_HideWindow(p->wnd);
return 0;
}
static int create(lua_State* L)
{
check(L, { LUA_TSTRING, LUA_TNUMBER, LUA_TNUMBER });
cout << "In Window::create" << endl;
Window* p = (Window*) lua_newuserdata(L, sizeof(Window));
// Data table (for storing lua values)
lua_pushlightuserdata(L, p);
lua_newtable(L);
lua_settable(L, LUA_REGISTRYINDEX);
// Metatable
lua_getfield(L, LUA_REGISTRYINDEX, "__window_mt");
if (lua_type(L, -1) == LUA_TNIL)
{
lua_pop(L, 1);
lua_newtable(L);
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
lua_pushstring(L, "window"); lua_setfield(L, -2, "type");
setfn(L, close, "close");
setfn(L, set_event_handler, "on");
setfn(L, showWindow, "show");
setfn(L, hideWindow, "hide");
// Binding
lua_setfield(L, -2, "__index");
lua_setfield(L, LUA_REGISTRYINDEX, "__window_mt");
lua_getfield(L, LUA_REGISTRYINDEX, "__window_mt");
}
lua_setmetatable(L, -2);
// Internal logic
p->wnd = SDL_CreateWindow(lua_tostring(L, 1), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, lua_tointeger(L, 2), lua_tointeger(L, 3), SDL_WINDOW_HIDDEN);
return 1;
}
};
struct Texture
{
SDL_Texture* text;
int w;
int h;
static int close(lua_State* L)
{
check(L, { LUA_TUSERDATA });
cout << "In Texture::close" << endl;
Texture* t = (Texture*)lua_touserdata(L, 1);
if (t->text)
{
SDL_DestroyTexture(t->text);
t->text = nullptr;
}
return 0;
}
static void create(lua_State* L) // -2, +1
{
// <20>˺<EFBFBD><CBBA><EFBFBD><EFBFBD><EFBFBD>Renderer<65><72>C<EFBFBD><43>ֱ<EFBFBD>ӵ<EFBFBD><D3B5><EFBFBD>. <20><><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0>Ҫ<EFBFBD>ȷ<EFBFBD>һ<EFBFBD><D2BB>renderer userdata<74><61>lightuserdata<74><61>ջ<EFBFBD><D5BB>, ֵ<><D6B5><EFBFBD>ǵ<EFBFBD>ǰ<EFBFBD><C7B0>SDL_Texture.
// <20><><EFBFBD>ú<EFBFBD>ջ<EFBFBD>ϻ<EFBFBD><CFBB><EFBFBD><EFBFBD><EFBFBD>Texture<72><65>userdata.
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Lua<75><61>û<EFBFBD><C3BB>ֱ<EFBFBD>Ӵ<EFBFBD><D3B4><EFBFBD>Texture<72>ķ<EFBFBD><C4B7><EFBFBD>.
cout << "In Texture::create" << endl;
Texture* p = (Texture*)lua_newuserdata(L, sizeof(Texture));
// Metatable
lua_getfield(L, LUA_REGISTRYINDEX, "__texture_mt");
if (lua_type(L, -1) == LUA_TNIL)
{
lua_pop(L, 1);
lua_newtable(L);
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
lua_pushstring(L, "texture"); lua_setfield(L, -2, "type");
setfn(L, close, "close");
// Binding
lua_setfield(L, -2, "__index");
lua_setfield(L, LUA_REGISTRYINDEX, "__texture_mt");
lua_getfield(L, LUA_REGISTRYINDEX, "__texture_mt");
}
lua_setmetatable(L, -2);
p->text = (SDL_Texture * )lua_touserdata(L, -2);
SDL_QueryTexture(p->text, NULL, NULL, &p->w, &p->h);
lua_pushvalue(L, -3);
lua_setuservalue(L, -2); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Rendere userdata
// stack balance
lua_remove(L, lua_gettop(L) - 1); // ɾ<><C9BE>lightuserdata
lua_remove(L, lua_gettop(L) - 1); // ɾ<><C9BE>rendere userdata
}
};
int LuaRectPointToRect(lua_State* L, int index, SDL_Rect& rect)
{
if (lua_getfield(L, index, "type") != LUA_TSTRING)
{
lua_pop(L, 1);
return -1;
}
const char* type = lua_tostring(L, -1);
if (strcmp(type, "point") == 0)
{
lua_pop(L, 1);
lua_getfield(L, index, "x");
rect.x = lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "y");
rect.y = lua_tointeger(L, -1);
lua_pop(L, 1);
return 1;
}
else if (strcmp(type, "rect") == 0)
{
lua_pop(L, 1);
lua_getfield(L, index, "x");
rect.x = lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "y");
rect.y = lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "w");
rect.w = lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "h");
rect.h = lua_tointeger(L, -1);
lua_pop(L, 1);
return 0;
}
else
{
return -1;
}
}
struct Surface
{
SDL_Surface* surf;
static int close(lua_State* L)
{
check(L, { LUA_TUSERDATA });
cout << "In Surface::close" << endl;
Surface* p = (Surface*)lua_touserdata(L, 1);
if (p->surf)
{
SDL_FreeSurface(p->surf);
p->surf = nullptr;
}
return 0;
}
static void create(lua_State* L) // -1, +1
{
cout << "In Surface::create" << endl;
Surface* p = (Surface*)lua_newuserdata(L, sizeof(Surface));
// Metatable
lua_getfield(L, LUA_REGISTRYINDEX, "__surface_mt");
if (lua_type(L, -1) == LUA_TNIL)
{
lua_pop(L, 1);
lua_newtable(L);
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
lua_pushstring(L, "surface"); lua_setfield(L, -2, "type");
setfn(L, close, "close");
// Binding
lua_setfield(L, -2, "__index");
lua_setfield(L, LUA_REGISTRYINDEX, "__surface_mt");
lua_getfield(L, LUA_REGISTRYINDEX, "__surface_mt");
}
lua_setmetatable(L, -2);
p->surf = (SDL_Surface*)lua_touserdata(L, -2);
// stack balance
lua_remove(L, lua_gettop(L) - 1); // ɾ<><C9BE>lightuserdata
}
};
struct Renderer
{
SDL_Renderer* rnd;
static int close(lua_State* L)
{
check(L, { LUA_TUSERDATA });
cout << "In Renderer::close" << endl;
Renderer* p = (Renderer*)lua_touserdata(L, 1);
if (p->rnd)
{
SDL_DestroyRenderer(p->rnd);
p->rnd = nullptr;
}
return 0;
}
static int update(lua_State* L)
{
check(L, { LUA_TUSERDATA });
Renderer* p = (Renderer*)lua_touserdata(L, 1);
SDL_RenderPresent(p->rnd);
return 0;
}
static int clear(lua_State* L)
{
check(L, { LUA_TUSERDATA });
Renderer* p = (Renderer*)lua_touserdata(L, 1);
SDL_RenderClear(p->rnd);
return 0;
}
static int setColor(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TTABLE });
Renderer* p = (Renderer*)lua_touserdata(L, 1);
SDL_Color c;
if (LuaColorToColor(L, 2, c) < 0)
{
luaL_error(L, "Bad argument #%d. Color expected, got %s", 2, lua_typename(L, lua_type(L, 2)));
}
SDL_SetRenderDrawColor(p->rnd, c.r, c.g, c.b, c.a);
return 0;
}
static int getColor(lua_State* L)
{
check(L, { LUA_TUSERDATA });
Renderer* p = (Renderer*)lua_touserdata(L, 1);
Uint8 r, b, g, a;
SDL_GetRenderDrawColor(p->rnd, &r, &g, &b, &a);
lua_newtable(L);
lua_pushinteger(L, r);
lua_setfield(L, -2, "r");
lua_pushinteger(L, g);
lua_setfield(L, -2, "g");
lua_pushinteger(L, b);
lua_setfield(L, -2, "b");
lua_pushinteger(L, a);
lua_setfield(L, -2, "a");
lua_pushstring(L, "rgba");
lua_setfield(L, -2, "type");
return 1;
}
static int drawRect(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TTABLE });
Renderer* p = (Renderer*)lua_touserdata(L, 1);
SDL_Rect r;
if (LuaRectPointToRect(L, 2, r) < 0)
{
luaL_error(L, "Bad argument #%d. Rect expected, got %s", 2, lua_typename(L, lua_type(L, 2)));
}
SDL_RenderDrawRect(p->rnd, &r);
return 0;
}
static int fillRect(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TTABLE });
Renderer* p = (Renderer*)lua_touserdata(L, 1);
SDL_Rect r;
if (LuaRectPointToRect(L, 2, r) < 0)
{
luaL_error(L, "Bad argument #%d. Rect expected, got %s", 2, lua_typename(L, lua_type(L, 2)));
}
SDL_RenderFillRect(p->rnd, &r);
return 0;
}
static int loadTexture(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TSTRING });
Renderer* p = (Renderer*)lua_touserdata(L, 1);
const char* filepath = lua_tostring(L, 2);
SDL_Texture* text = IMG_LoadTexture(p->rnd, filepath);
lua_pushvalue(L, 1);
lua_pushlightuserdata(L, text);
Texture::create(L);
return 1;
}
static int copy(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TUSERDATA, LUA_TTABLE, LUA_TTABLE });
Renderer* r = (Renderer*)lua_touserdata(L, 1);
Texture* t = (Texture*)lua_touserdata(L, 2);
SDL_Rect src;
int ret = LuaRectPointToRect(L, 3, src);
if (ret <= 0)
{
luaL_error(L, "Bad argument #%d. Rect expected, got %s", 3, lua_typename(L, lua_type(L, 3)));
}
SDL_Rect dst;
ret = LuaRectPointToRect(L, 4, dst);
if (ret <= 0)
{
luaL_error(L, "Bad argument #%d. Rect expected, got %s", 4, lua_typename(L, lua_type(L, 4)));
}
SDL_RenderCopy(r->rnd, t->text, &src, &dst);
return 0;
}
static int copyTo(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TUSERDATA, LUA_TTABLE });
Renderer* r = (Renderer*)lua_touserdata(L, 1);
Texture* t = (Texture*)lua_touserdata(L, 2);
SDL_Rect rect;
int ret = LuaRectPointToRect(L, 3, rect);
if (ret < 0)
{
luaL_error(L, "Bad argument #%d. Point or Rect expected, got %s", 3, lua_typename(L, lua_type(L, 3)));
}
if (ret == 1)
{
rect.w = t->w;
rect.h = t->h;
}
SDL_RenderCopy(r->rnd, t->text, NULL, &rect);
return 0;
}
static int copyFill(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TUSERDATA, LUA_TTABLE });
Renderer* r = (Renderer*)lua_touserdata(L, 1);
Texture* t = (Texture*)lua_touserdata(L, 2);
SDL_Rect rect;
int ret = LuaRectPointToRect(L, 3, rect);
if (ret < 0)
{
luaL_error(L, "Bad argument #%d. Point or Rect expected, got %s", 3, lua_typename(L, lua_type(L, 3)));
}
if (ret == 1)
{
rect.w = t->w;
rect.h = t->h;
}
SDL_RenderCopy(r->rnd, t->text, &rect, NULL);
return 0;
}
static int create(lua_State* L)
{
check(L, { LUA_TUSERDATA });
cout << "In Renderer::create" << endl;
Renderer* p = (Renderer*)lua_newuserdata(L, sizeof(Renderer));
lua_getfield(L, LUA_REGISTRYINDEX, "__renderer_mt");
if (lua_type(L, -1) == LUA_TNIL)
{
lua_pop(L, 1);
lua_newtable(L);
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
lua_pushstring(L, "renderer"); lua_setfield(L, -2, "type");
setfn(L, close, "close");
setfn(L, update, "update");
setfn(L, clear, "clear");
setfn(L, setColor, "setColor");
setfn(L, getColor, "getColor");
setfn(L, drawRect, "drawRect");
setfn(L, fillRect, "fillRect");
setfn(L, loadTexture, "loadTexture");
setfn(L, copy, "copy");
setfn(L, copyTo, "copyTo");
// Set __index of metatable.
lua_setfield(L, -2, "__index");
lua_setfield(L, LUA_REGISTRYINDEX, "__renderer_mt");
lua_getfield(L, LUA_REGISTRYINDEX, "__renderer_mt");
}
lua_setmetatable(L, -2);
// <20>󶨵<EFBFBD>ǰRenderer<65>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><>ֹSDL_Window<6F><77><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>.
lua_pushvalue(L, 1);
lua_setuservalue(L, -2);
// Internal logic
p->rnd = SDL_CreateRenderer(static_cast<Window*>(lua_touserdata(L, 1))->wnd, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE);
return 1;
}
};
struct Font
{
TTF_Font* font;
static int close(lua_State* L)
{
check(L, { LUA_TUSERDATA });
cout << "In Font::close" << endl;
Font* f = (Font*)lua_touserdata(L, 1);
if (f->font)
{
TTF_CloseFont(f->font);
f->font = nullptr;
}
return 0;
}
static int renderText(lua_State* L)
{
Renderer* r = nullptr;
Font* f = nullptr;
const char* text = nullptr;
SDL_Color c;
if (lua_gettop(L) >= 4)
{
check(L, { LUA_TUSERDATA, LUA_TUSERDATA, LUA_TSTRING, LUA_TTABLE });
f = (Font*)lua_touserdata(L, 1);
r = (Renderer*)lua_touserdata(L, 2);
text = lua_tostring(L, 3);
if (LuaColorToColor(L, 4, c) < 0)
{
luaL_error(L, "Bad argument #%d. Color expected, got %s", 4, lua_typename(L, lua_type(L, 4)));
}
}
else
{
check(L, { LUA_TUSERDATA, LUA_TSTRING, LUA_TTABLE });
f = (Font*)lua_touserdata(L, 1);
text = lua_tostring(L, 3);
if (LuaColorToColor(L, 4, c) < 0)
{
luaL_error(L, "Bad argument #%d. Color expected, got %s", 4, lua_typename(L, lua_type(L, 4)));
}
}
SDL_Surface* surf = TTF_RenderText_Blended(f->font, text, c);
if (r)
{
SDL_Texture* text = SDL_CreateTextureFromSurface(r->rnd, surf);
SDL_FreeSurface(surf);
lua_pushvalue(L, 2);
lua_pushlightuserdata(L, text);
Texture::create(L);
}
else
{
lua_pushlightuserdata(L, surf);
Surface::create(L);
}
return 1;
}
static int create(lua_State* L)
{
check(L, { LUA_TSTRING, LUA_TNUMBER });
cout << "In Font::create" << endl;
Font* f = (Font*)lua_newuserdata(L, sizeof(Font));
lua_getfield(L, LUA_REGISTRYINDEX, "__font_mt");
if (lua_type(L, -1) == LUA_TNIL)
{
lua_pop(L, 1);
lua_newtable(L);
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
lua_pushstring(L, "font"); lua_setfield(L, -2, "type");
setfn(L, close, "close");
setfn(L, renderText, "renderText");
// Set __index of metatable.
lua_setfield(L, -2, "__index");
lua_setfield(L, LUA_REGISTRYINDEX, "__font_mt");
lua_getfield(L, LUA_REGISTRYINDEX, "__font_mt");
}
lua_setmetatable(L, -2);
const char* filename = lua_tostring(L, 1);
int fontsz = lua_tointeger(L, 2);
f->font = TTF_OpenFont(filename, fontsz);
return 1;
}
};
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;
static int close(lua_State* L)
{
check(L, { LUA_TUSERDATA });
cout << "In Chunk::close" << endl;
Chunk* c = (Chunk*)lua_touserdata(L, 1);
if (c->chunk)
{
Mix_FreeChunk(c->chunk);
c->chunk = nullptr;
}
return 0;
}
static int setVolume(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER });
Chunk* c = (Chunk*)lua_touserdata(L, 1);
Mix_VolumeChunk(c->chunk, lua_tointeger(L, 2));
return 0;
}
static int create(lua_State* L)
{
check(L, { LUA_TSTRING });
cout << "In Chunk::create" << endl;
Chunk* c = (Chunk*)lua_newuserdata(L, sizeof(Chunk));
lua_getfield(L, LUA_REGISTRYINDEX, "__chunk_mt");
if (lua_type(L, -1) == LUA_TNIL)
{
lua_pop(L, 1);
lua_newtable(L);
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
lua_pushstring(L, "chunk"); lua_setfield(L, -2, "type");
setfn(L, close, "close");
setfn(L, setVolume, "setVolumne");
// Set __index of metatable.
lua_setfield(L, -2, "__index");
lua_setfield(L, LUA_REGISTRYINDEX, "__chunk_mt");
lua_getfield(L, LUA_REGISTRYINDEX, "__chunk_mt");
}
lua_setmetatable(L, -2);
const char* filename = lua_tostring(L, 1);
cout << "LoadWAV: " << filename << endl;
c->chunk = Mix_LoadWAVEx(filename);
cout << "Load chunk error: " << SDL_GetError() << endl;
return 1;
}
};
struct Music
{
Mix_Music* music;
static int close(lua_State* L)
{
check(L, { LUA_TUSERDATA });
cout << "In Music::close" << endl;
Music* m = (Music*)lua_touserdata(L, 1);
if (m->music)
{
Mix_FreeMusic(m->music);
m->music = nullptr;
}
return 0;
}
static int create(lua_State* L)
{
check(L, { LUA_TSTRING });
cout << "In Music::create" << endl;
Music* m = (Music*)lua_newuserdata(L, sizeof(Music));
lua_getfield(L, LUA_REGISTRYINDEX, "__music_mt");
if (lua_type(L, -1) == LUA_TNIL)
{
lua_pop(L, 1);
lua_newtable(L);
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
lua_pushstring(L, "music"); lua_setfield(L, -2, "type");
setfn(L, close, "close");
// Set __index of metatable.
lua_setfield(L, -2, "__index");
lua_setfield(L, LUA_REGISTRYINDEX, "__music_mt");
lua_getfield(L, LUA_REGISTRYINDEX, "__music_mt");
}
lua_setmetatable(L, -2);
const char* filename = lua_tostring(L, 1);
m->music = Mix_LoadMUS(filename);
cout << "Load music error: " << SDL_GetError() << endl;
return 1;
}
};
struct MusicPlayer
{
static int close(lua_State* L)
{
check(L, { LUA_TUSERDATA });
cout << "In MusicPlayer::close" << endl;
return 0;
}
static int playMusic(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TUSERDATA });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Music* m = (Music*)lua_touserdata(L, 2);
cout << "Play music ret: " << Mix_PlayMusic(m->music, 1) << " " << SDL_GetError() << endl;
return 0;
}
static int resumeMusic(lua_State* L)
{
check(L, { LUA_TUSERDATA });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_ResumeMusic();
return 0;
}
static int stopMusic(lua_State* L)
{
check(L, { LUA_TUSERDATA });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_HaltMusic();
return 0;
}
static int pauseMusic(lua_State* L)
{
check(L, { LUA_TUSERDATA });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_PauseMusic();
return 0;
}
static int rewindMusic(lua_State* L)
{
check(L, { LUA_TUSERDATA });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_RewindMusic();
return 0;
}
static int fadeInMusic(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TUSERDATA , LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Music* m = (Music*)lua_touserdata(L, 2);
cout << "Fade in music ret: " << Mix_FadeInMusic(m->music, 1, lua_tointeger(L, 3)) << " " << SDL_GetError() << endl;
return 0;
}
static int fadeInMusicPos(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TUSERDATA , LUA_TNUMBER, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Music* m = (Music*)lua_touserdata(L, 2);
cout << "Fade in music ret: " << Mix_FadeInMusicPos(m->music, 1, lua_tointeger(L, 3), lua_tonumber(L, 4)) << " " << SDL_GetError() << endl;
return 0;
}
static int fadeOutMusic(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
cout << "Fade out music ret: " << Mix_FadeOutMusic(lua_tointeger(L, 2)) << " " << SDL_GetError() << endl;
return 0;
}
static int setMusicVolume(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_VolumeMusic(lua_tointeger(L, 2));
return 0;
}
static int setMusicPos(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_SetMusicPosition(lua_tonumber(L, 2));
return 0;
}
static int isPlayingMusic(lua_State* L)
{
check(L, { LUA_TUSERDATA });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
lua_pushboolean(L, Mix_PlayingMusic());
return 1;
}
static int isPausedMusic(lua_State* L)
{
check(L, { LUA_TUSERDATA });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
lua_pushboolean(L, Mix_PausedMusic());
return 1;
}
static int isFadingMusic(lua_State* L)
{
check(L, { LUA_TUSERDATA });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
int ret = 0;
switch (Mix_FadingMusic())
{
case MIX_NO_FADING:
ret = 0;
break;
case MIX_FADING_OUT:
ret = -1;
break;
case MIX_FADING_IN:
return 1;
}
lua_pushinteger(L, ret);
return 1;
}
static int playChannel(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TUSERDATA, LUA_TNUMBER, LUA_TNUMBER});
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Chunk* c = (Chunk*)lua_touserdata(L, 2);
cout << "Play channel ret: " << Mix_PlayChannel(lua_tointeger(L, 3), c->chunk, lua_tointeger(L, 4)) << " " << SDL_GetError() << endl;
return 0;
}
static int fadeInChannel(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TUSERDATA, LUA_TNUMBER, LUA_TNUMBER, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Chunk* c = (Chunk*)lua_touserdata(L, 2);
Mix_FadeInChannel(lua_tointeger(L, 3), c->chunk, lua_tointeger(L, 4), lua_tointeger(L, 5));
return 0;
}
static int fadeOutChannel(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_FadeOutChannel(lua_tointeger(L, 2), lua_tointeger(L, 3));
return 0;
}
static int stopChannel(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_HaltChannel(lua_tointeger(L, 2));
return 0;
}
static int resumeChannel(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_Resume(lua_tointeger(L, 2));
return 0;
}
static int pauseChannel(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_Pause(lua_tointeger(L, 2));
return 0;
}
static int isPlayingChannel(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
lua_pushinteger(L, Mix_Playing(lua_tointeger(L, 2)));
return 1;
}
static int isPausedChannel(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
lua_pushinteger(L, Mix_Paused(lua_tointeger(L, 2)));
return 1;
}
static int isFadingChannel(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
int ret = 0;
switch (Mix_FadingChannel(lua_tointeger(L, 2)))
{
case MIX_NO_FADING:
ret = 0;
break;
case MIX_FADING_OUT:
ret = -1;
break;
case MIX_FADING_IN:
return 1;
}
lua_pushinteger(L, ret);
return 1;
}
static int setChannelVolume(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_Volume(lua_tointeger(L, 2), lua_tointeger(L, 3));
return 0;
}
static int setChannelDistance(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_SetDistance(lua_tointeger(L, 2), lua_tointeger(L, 3));
return 0;
}
static int setChannelPosition(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER, LUA_TNUMBER, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Sint16 angle = lua_tonumber(L, 3);
unsigned int distance = lua_tonumber(L, 4);
cout << "Mix_SetPosition " << lua_tointeger(L, 2) << " " << angle << " " << distance << endl;
if (0 == Mix_SetPosition(lua_tointeger(L, 2), angle, distance))
{
LuaSDLError(L);
}
return 0;
}
static int setChannelPanning(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER, LUA_TNUMBER, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_SetPanning(lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4));
return 0;
}
static int setTotalChannel(lua_State* L)
{
check(L, { LUA_TUSERDATA, LUA_TNUMBER });
MusicPlayer* p = (MusicPlayer*)lua_touserdata(L, 1);
Mix_AllocateChannels(lua_tointeger(L, 2));
return 0;
}
static int create(lua_State* L)
{
cout << "In MusicPlayer::create" << endl;
MusicPlayer* m = (MusicPlayer*)lua_newuserdata(L, sizeof(MusicPlayer));
lua_getfield(L, LUA_REGISTRYINDEX, "__musicplayer_mt");
if (lua_type(L, -1) == LUA_TNIL)
{
lua_pop(L, 1);
lua_newtable(L);
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
lua_pushstring(L, "musicplayer"); lua_setfield(L, -2, "type");
setfn(L, close, "close");
setfn(L, playMusic, "playMusic");
setfn(L, resumeMusic, "resumeMusic");
setfn(L, pauseMusic, "pauseMusic");
setfn(L, stopMusic, "stopMusic");
setfn(L, rewindMusic, "rewindMusic");
setfn(L, fadeInMusic, "fadeInMusic");
setfn(L, fadeOutMusic, "fadeOutMusic");
setfn(L, fadeInMusicPos, "fadeInMusicPos");
setfn(L, setMusicVolume, "setMusicVolume");
setfn(L, setMusicPos, "setMusicPos");
setfn(L, isPlayingMusic, "isPlayingMusic");
setfn(L, isPausedMusic, "isPausedMusic");
setfn(L, isFadingMusic, "isFadingMusic");
setfn(L, playChannel, "playChannel");
setfn(L, resumeChannel, "resumeChannel");
setfn(L, pauseChannel, "pauseChannel");
setfn(L, stopChannel, "stopChannel");
setfn(L, fadeInChannel, "fadeInChannel");
setfn(L, fadeOutChannel, "fadeOutChannel");
setfn(L, setChannelVolume, "setChannelVolume");
setfn(L, setChannelDistance, "setChannelDistance");
setfn(L, setChannelPosition, "setChannelPosition");
setfn(L, setChannelPanning, "setChannelPanning");
setfn(L, setTotalChannel, "setTotalChannel");
setfn(L, isPlayingChannel, "isPlayingChannel");
setfn(L, isPausedChannel, "isPausedChannel");
setfn(L, isFadingChannel, "isFadingChannel");
// Set __index of metatable.
lua_setfield(L, -2, "__index");
lua_setfield(L, LUA_REGISTRYINDEX, "__musicplayer_mt");
lua_getfield(L, LUA_REGISTRYINDEX, "__musicplayer_mt");
}
lua_setmetatable(L, -2);
return 1;
}
};
struct LibFS
{
static int listdir(lua_State* L)
{
check(L, { LUA_TSTRING });
vector<FileInfo> vec = ListDir(lua_tostring(L, 1));
int sz = vec.size();
lua_newtable(L);
for (lua_Integer i = 0; i < sz; i++)
{
const FileInfo& info = vec[i];
lua_newtable(L);
lua_pushstring(L, info.name.c_str());
lua_setfield(L, -2, "name");
lua_pushstring(L, info.type ? "dir" : "file");
lua_setfield(L, -2, "type");
lua_pushinteger(L, info.size);
lua_setfield(L, -2, "size");
lua_seti(L, -2, i + 1);
}
return 1;
}
static int create(lua_State* L)
{
lua_newtable(L);
setfn(L, listdir, "listdir");
return 1;
}
};
void check_init(lua_State* L, const char* name, int ret, int expected = 0)
{
if (ret != expected)
{
luaL_error(L, "Failed to initialize %s. ret: %d. expected: %d. SDLError: %s", name, ret, expected, SDL_GetError());
}
}
void _Global_On_Music_Finished()
{
SDL_Event e;
e.type = SDL_USEREVENT;
e.user.code = 1003;
SDL_PushEvent(&e);
}
void _Global_On_Channel_Finished(int channel)
{
SDL_Event e;
e.type = SDL_USEREVENT;
e.user.code = 1004;
e.user.data1 = new 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_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 evFireExit(lua_State* L)
{
SDL_Event e;
e.type = SDL_QUIT;
e.quit.timestamp = SDL_GetTicks();
SDL_PushEvent(&e);
return 0;
}
#define reg_in_lua(L, cfunc, name) lua_pushcfunction(L, cfunc); lua_setglobal(L, name)
int InitEngine(lua_State* L)
{
int ret;
ret = SDL_Init(SDL_INIT_EVERYTHING);
check_init(L, "SDL", ret);
ret = IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
check_init(L, "IMG", ret, IMG_INIT_JPG | IMG_INIT_PNG);
ret = TTF_Init();
check_init(L, "TTF", ret);
ret = Mix_Init(MIX_INIT_MP3 | MIX_INIT_MOD | MIX_INIT_OGG );
check_init(L, "MIX", ret, MIX_INIT_MP3 | MIX_INIT_MOD | MIX_INIT_OGG);
ret = Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 512);
check_init(L, "AUDIO", ret);
Mix_AllocateChannels(16);
Mix_HookMusicFinished(_Global_On_Music_Finished);
Mix_ChannelFinished(_Global_On_Channel_Finished);
reg_in_lua(L, Window::create, "Window");
reg_in_lua(L, Renderer::create, "Renderer");
reg_in_lua(L, Font::create, "Font");
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");
reg_in_lua(L, evFireExit, "FireExit");
// Global Library
LibFS::create(L); lua_setglobal(L, "fs");
InitEnum(L);
InitNetwork(L);
// 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:
{
SDL_Window* wnd = SDL_GetWindowFromID(e.button.windowID);
if (wnd)
{
lua_pushlightuserdata(L, wnd);
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:
{
SDL_Window* wnd = SDL_GetWindowFromID(e.button.windowID);
if (wnd)
{
lua_pushlightuserdata(L, wnd);
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:
{
SDL_Window* wnd = SDL_GetWindowFromID(e.motion.windowID);
if (wnd)
{
lua_pushlightuserdata(L, wnd);
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:
{
SDL_Window* wnd = SDL_GetWindowFromID(e.key.windowID);
if (wnd)
{
lua_pushlightuserdata(L, wnd);
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:
{
SDL_Window* wnd = SDL_GetWindowFromID(e.key.windowID);
if (wnd)
{
lua_pushlightuserdata(L, wnd);
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:
{
// <20><>ʱ<EFBFBD><CAB1><EFBFBD>ص<EFBFBD>
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]
if (!pd->type)
{
delete pd;
LuaRunCallback(L, 0);
}
else
{
if (LuaRunCallback(L, 0, 1) == 0)
{
if (lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1))
{
SDL_RemoveTimer(pd->id);
delete pd;
}
lua_pop(L, 1);
}
}
lua_pop(L, 1);
break;
}
case 1002:
{
// ȫ<>ֻص<D6BB>, <20><EFBFBD><ECB2BD><EFBFBD><EFBFBD><EFBFBD>޷<EFBFBD><DEB7><EFBFBD>ֵ
lua_pushfstring(L, "cb%d", *(int*)e.user.data1);
lua_gettable(L, LUA_REGISTRYINDEX);
delete e.user.data1;
LuaRunCallback(L, 0);
break;
}
case 1003:
// <20><><EFBFBD>ֲ<EFBFBD><D6B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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:
{
// Ƶ<><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
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;
}
case 1005:
case 1006:
{
HandleNetworkEvent(L, e);
break;
}
break;
}
default:
{
cout << "Unhandled Event: 0x" << hex << e.type << endl;
}
}
}
return 0;
}
int StopEngine()
{
Mix_CloseAudio();
Mix_Quit();
TTF_Quit();
IMG_Quit();
SDL_Quit();
return 0;
}