完整重构

分离各SDL类的包装代码.
事件分发处理全部转移至Lua Init层. C层只提供获取事件的方法.
这样有助于提高性能,以及今后Coroutine scheduler的添加.
This commit is contained in:
Kirigaya Kazuto 2019-08-25 00:09:25 +08:00
parent a516ae15ec
commit bc189b4951
29 changed files with 1829 additions and 1686 deletions

6
EventDef.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
constexpr int ENGINE_TIMER_EVENT = 1001; // 定时器. 参数: 定时器ID
constexpr int ENGINE_GENERAL_CALLBACK = 1002; // 只有Ticket参数的回调. 用于Lua层区分回调.
constexpr int ENGINE_MUSIC_FINISH = 1003; // 音乐播放结束
constexpr int ENGINE_CHANNEL_FINISH = 1004; // 频道播放结束. 参数: 频道号.

94
Font.cpp Normal file
View File

@ -0,0 +1,94 @@
#include "Font.h"
#include "Renderer.h"
#include "Texture.h"
#include "Surface.h"
#include "LuaCommon.h"
#include <iostream>
using namespace std;
#define setfn(cfunc, name) lua_pushcfunction(L, cfunc);lua_setfield(L, -2, name)
inline int Font::close(lua_State* L)
{
cout << "In Font::close" << endl;
auto p = (Font*)luaL_checkudata(L, 1, "font");
p->~Font();
return 0;
}
inline Font::Font(TTF_Font* f) : font(f, TTF_CloseFont)
{
}
inline int Font::renderText(lua_State* L)
{
auto p = (Font*)luaL_checkudata(L, 1, "font");
std::shared_ptr<SDL_Renderer> r;
const char* msg = nullptr;
SDL_Color c;
if (lua_gettop(L) >= 4)
{
r = ((Renderer*)luaL_checkudata(L, 2, "renderer"))->rnd;
msg = luaL_checkstring(L, 3);
if (LuaColorToColor(L, 4, c))
{
return luaL_error(L, "bad argument #4. rgba expected, got %s", lua_tostring(L, -1));
}
}
else
{
msg = luaL_checkstring(L, 2);
if (LuaColorToColor(L, 3, c))
{
return luaL_error(L, "bad argument #3. rgba expected, got %s", lua_tostring(L, -1));
}
}
SDL_Surface* surf = TTF_RenderText_Blended(p->font.get(), msg, c);
if (r.get())
{
Texture::create(L, r, SDL_CreateTextureFromSurface(r.get(), surf));
SDL_FreeSurface(surf);
}
else
{
Surface::create(L, surf);
}
return 1;
}
int Font::create(lua_State* L)
{
cout << "In Font::create" << endl;
const char* font = luaL_checkstring(L, 1);
int fontsz = luaL_checkinteger(L, 2);
TTF_Font* ttf = TTF_OpenFont(font, fontsz);
if (!ttf)
{
return LuaSDLError(L);
}
Font* f = new (lua_newuserdata(L, sizeof(Font))) Font(ttf);
if (luaL_newmetatable(L, "font"))
{
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
lua_pushstring(L, "font"); lua_setfield(L, -2, "type");
setfn(close, "close");
setfn(renderText, "renderText");
// Set __index of metatable.
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
return 1;
}

17
Font.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include "LuaVM.h"
#include "SDL2/include/SDL_ttf.h"
#include <memory>
class Font
{
public:
std::shared_ptr<TTF_Font> font;
Font(TTF_Font* f);
static int renderText(lua_State* L);
static int close(lua_State* L);
static int create(lua_State* L);
};

View File

@ -112,8 +112,8 @@ void VMRunner(VMInfo& vm, string code)
int CreateVM(lua_State* L)
{
string code(luaL_checkstring(L, 1));
VMInfo* vm = new (lua_newuserdata(L, sizeof(VMInfo))) VMInfo;
string code(lua_tostring(L, 1));
vm->ptd.reset(new thread(VMRunner, *vm, code));
vm->ptd.reset(new thread(VMRunner, ref(*vm), code));
return 1;
}

View File

@ -25,33 +25,154 @@ bool LuaCompareType(lua_State* L, int index, const char* type, bool leave)
}
}
void check(lua_State* L, const vector<int>& typearr, const vector<const char*>& userdata_type)
int LuaRectToRect(lua_State* L, int index, SDL_Rect& rect)
{
int sz = typearr.size();
int nextIndex = 0;
int maxIndex = userdata_type.size();
for (int i = 0; i < sz; i++)
if (index < 0)
{
int thisType = lua_type(L, i + 1);
if (thisType != typearr[i])
{
luaL_error(L, "Bad argument #%d. %s expected, got %s", i + 1, lua_typename(L, typearr[i]), lua_typename(L, lua_type(L, i + 1)));
}
if (maxIndex && thisType == LUA_TUSERDATA)
{
if (nextIndex < maxIndex)
{
if (!LuaCompareType(L, i + 1, userdata_type[nextIndex], true))
{
luaL_error(L, "Bad argument #%d. %s expected, got %s", i + 1, userdata_type[nextIndex], lua_tostring(L, -1));
}
lua_pop(L, 1);
nextIndex++;
}
else
{
luaL_error(L, "Not enough userdata type string.");
}
}
index = lua_gettop(L) + index + 1;
}
if (lua_getfield(L, index, "type") != LUA_TSTRING)
{
int t = lua_type(L, -1);
lua_pop(L, 1);
lua_pushstring(L, lua_typename(L, t));
return 1;
}
if (strcmp(lua_tostring(L, -1), "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;
}
}
int LuaPointToPoint(lua_State* L, int index, SDL_Point& point)
{
if (index < 0)
{
index = lua_gettop(L) + index + 1;
}
if (lua_getfield(L, index, "type") != LUA_TSTRING)
{
int t = lua_type(L, -1);
lua_pop(L, 1);
lua_pushstring(L, lua_typename(L, t));
return 1;
}
if (strcmp(lua_tostring(L, -1), "point") == 0)
{
lua_pop(L, 1);
lua_getfield(L, index, "x");
point.x = lua_tointeger(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "y");
point.y = lua_tointeger(L, -1);
lua_pop(L, 1);
return 0;
}
else
{
return 1;
}
}
int LuaColorToColor(lua_State* L, int index, SDL_Color& c)
{
if (index < 0)
{
index = lua_gettop(L) + index + 1;
}
if (lua_getfield(L, index, "type") != LUA_TSTRING)
{
int t = lua_type(L, -1);
lua_pop(L, 1);
lua_pushstring(L, lua_typename(L, t));
return 1;
}
if (strcmp(lua_tostring(L, -1), "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;
}
}
int LuaRectPointToRect(lua_State* L, int index, SDL_Rect& r, int default_w, int default_h)
{
if (index < 0)
{
index = lua_gettop(L) + index + 1;
}
if (LuaRectToRect(L, index, r))
{
SDL_Point p;
if (LuaPointToPoint(L, index, p))
{
lua_pop(L, 1);
return 1;
}
lua_pop(L, 1);
r.x = p.x;
r.y = p.y;
r.w = default_w;
r.h = default_h;
return 0;
}
return 0;
}
int LuaSDLError(lua_State* L)
{
return luaL_error(L, "SDLError: %s", SDL_GetError());
}

View File

@ -1,6 +1,23 @@
#pragma once
#include "LuaVM.h"
#include "SDL2/include/SDL.h"
#include <vector>
bool LuaCompareType(lua_State* L, int index, const char* type, bool leave = false);
void check(lua_State* L, const std::vector<int>& typearr, const std::vector<const char*>& userdata_type = std::vector<const char*>());
// 从Lua Rect/Point转换到SDL_Rect. 给定index类型必须是table (此方法不会校验是否为table)
// 正确转换则返回 0
// 出错则返回 1, 同时将 type 放在栈上. (有可能是nil)
int LuaRectPointToRect(lua_State* L, int index, SDL_Rect& r, int default_w = 0, int default_h = 0);
int LuaRectToRect(lua_State* L, int index, SDL_Rect& rect);
int LuaPointToPoint(lua_State* L, int index, SDL_Point& point);
// 从Lua RGBA转换到SDL_Color. 给定index类型必须是table. (此方法不会校验是否为table)
// 正确转换则返回 0
// 出错则返回 1, 同时将 type 放在栈上. (有可能是nil)
int LuaColorToColor(lua_State* L, int index, SDL_Color& c);
// Generate SDL error on lua stack.
// NOTE: Never actually returns. If this function is used in C++ context, you should compile Lua as C++.
int LuaSDLError(lua_State* L);

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,6 @@
#undef main
int InitEngine(lua_State* L);
int StartEngine(lua_State* L);
int InitEngine();
int InitLibs(lua_State* L);
int StopEngine();

View File

@ -10,7 +10,7 @@ using namespace std;
/*
Key code generated with Python script:
Key code generated by Python script:
```python
lst = filter(lambda x: True if x else False, content.replace('\r', '').split('\n'))
@ -29,7 +29,7 @@ for line in lst:
```
*/
int InitEnum(lua_State* L)
int InitKeys(lua_State* L)
{
lua_newtable(L);
addkey(SDLK_UNKNOWN, "unknown");
@ -502,6 +502,5 @@ int InitEnum(lua_State* L)
addkey(SDLK_AUDIOREWIND, "AUDIOREWIND");
addkey(SDLK_AUDIOFASTFORWARD, "audiofastforward");
addkey(SDLK_AUDIOFASTFORWARD, "AUDIOFASTFORWARD");
lua_setglobal(L, "Keys");
return 0;
return 1;
}

View File

@ -2,4 +2,5 @@
#include "LuaVM.h"
int InitEnum(lua_State* L);
// create a table on top of the stack.
int InitKeys(lua_State* L);

4
LuaHelper.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
#define setfn(cfunc, name) lua_pushcfunction(L, cfunc);lua_setfield(L, -2, name)
#define settype(type_name) lua_pushstring(L, type_name);lua_setfield(L, -2, "type")

View File

@ -161,7 +161,7 @@ public:
{
for (int i = 0; i < maxSize; i++)
{
workers.emplace_back(task_runner, tasks[i]);
workers.emplace_back(task_runner, ref(tasks[i]));
}
}
@ -519,132 +519,6 @@ struct ClientSocket
}
};
template<typename T>
class ClassWrapper
{
public:
bool __destroyed;
const char* type;
struct Fuck
{
using TMemFn = int (T::*)(lua_State*);
TMemFn f;
};
static int destroy(lua_State* L)
{
T* t = static_cast<T*>(lua_touserdata(L, 1));
if (!t->__destroyed)
{
t->__destroyed = true;
t->~T();
}
return 0;
}
static int create(lua_State* L)
{
T* t = new (lua_newuserdata(L, sizeof(T))) T(L);
t->__destroyed = false;
char mtname[64] = { 0 };
sprintf(mtname, "__clsw_%u_mt", typeid(T).hash_code);
if (lua_getfield(L, LUA_REGISTRYINDEX, mtname) != LUA_TTABLE)
{
lua_pop(L, 1);
lua_newtable(L);
lua_pushstring(L, t->type);
lua_setfield(L, -2, "type");
lua_pushcfunction(L, destroy);
lua_setfield(L, -2, "__gc");
lua_newtable(L);
int __chk_before = lua_gettop(L);
t->prepare(L); // T::prepare(lua_State*) must keep stack balance!
int __chk_after = lua_gettop(L);
if (__chk_before != __chk_after)
{
return luaL_error(L, "Stack unbalance detected while initializing: %s", type);
}
lua_setfield(L, -2, "__index");
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, mtname);
}
lua_setmetatable(L, -1);
return 1;
}
static int LuaCallGate(lua_State* L)
{
if (lua_type(L, 1) != LUA_TUSERDATA)
{
return luaL_error(L, "Bad argument #1. userdata expected. Got %s.", lua_typename(L, lua_type(L, 1)));
}
if (!lua_getmetatable(L, 1))
{
return luaL_error(L, "Bad argument #1. cannot get metatable.");
}
char mtname[64] = { 0 };
sprintf(mtname, "__clsw_%u_mt", typeid(T).hash_code);
lua_getfield(L, LUA_REGISTRYINDEX, mtname);
if (!lua_rawequal(L, -1, -2))
{
lua_pop(L, 2);
return luaL_error(L, "Bad argument #1. metatable mismatch.");
}
lua_pop(L, 2);
T* p = (T*)(lua_touserdata(L, 1));
Fuck* f = (Fuck*)(lua_touserdata(L, lua_upvalueindex(1)));
return std::invoke(f->f, *p, L);
}
void AddFunction(lua_State* L, typename Fuck::TMemFn callable)
{
Fuck* f = new Fuck;
f->f = callable;
lua_pushlightuserdata(L, f);
lua_pushcclosure(L, LuaCallGate, 1);
}
};
class MyClass : public ClassWrapper<MyClass>
{
public:
string welcome;
MyClass(lua_State* L)
{
printf("MyClass ctor.\n");
type = "MyClass";
welcome = lua_tostring(L, 1);
}
int showit(lua_State* L)
{
printf("In MyClass::showit, %s", welcome.c_str());
return 0;
}
~MyClass()
{
printf("MyClass dtor.\n");
}
void prepare(lua_State* L)
{
AddFunction(L, &MyClass::showit);
}
};
int InitNetwork(lua_State* L)
{
WORD wd;
@ -660,3 +534,7 @@ int InitNetwork(lua_State* L)
return 0;
}
void HandleNetworkEvent(lua_State* L, const SDL_Event& e)
{
}

View File

@ -0,0 +1,63 @@
#include "LuaVM.h"
void pushvalue(lua_State* L, int val)
{
lua_pushinteger(L, val);
}
void pushvalue(lua_State* L, double val)
{
lua_pushnumber(L, val);
}
void pushvalue(lua_State* L, const char* str)
{
lua_pushstring(L, str);
}
void pushvalue(lua_State* L, const char* str, int len)
{
lua_pushlstring(L, str, len);
}
void pushvalue(lua_State* L, const std::string& str)
{
lua_pushlstring(L, str.c_str(), str.size());
}
void pushvalue(lua_State* L, lua_CFunction fn)
{
lua_pushcfunction(L, fn);
}
void pushvalue(lua_State* L, lua_CFunction fn, int nup)
{
lua_pushcclosure(L, fn, nup);
}
template<>
const char* getvalue(lua_State* L, int index) // LUA_TSTRING
{
return luaL_checkstring(L, index);
}
template<>
std::string getvalue(lua_State* L, int index) // LUA_TSTRING
{
size_t sz;
const char* s = luaL_checklstring(L, index, &sz);
return std::string(s, sz);
}
template<>
int getvalue(lua_State* L, int index) // LUA_TNUMBER
{
return (const int)luaL_checkinteger(L, index);
}
template<>
double getvalue(lua_State* L, int index) // LUA_TNUMBER
{
return luaL_checknumber(L, index);
}

32
LuaVM.h
View File

@ -2,7 +2,7 @@
#include "lua/lua.h"
#include "lua/lualib.h"
#include "lua/lauxlib.h"
#include <string>
class LuaVM
{
@ -35,3 +35,33 @@ private:
lua_State* _L;
bool _managed;
};
template<typename T>
T& getuserdata(lua_State* L, int index) // LUA_TUSERDATA
{
return *(T*)luaL_checkudata(L, index, T::tname);
}
template<typename T>
T getvalue(lua_State* L, int index);
template<typename T>
T& pushvalue(lua_State* L)
{
return *(T*)lua_newuserdata(L, sizeof(T));
}
void pushvalue(lua_State* L, int val);
void pushvalue(lua_State* L, double val);
void pushvalue(lua_State* L, const char* str);
void pushvalue(lua_State* L, const char* str, int len);
void pushvalue(lua_State* L, const std::string& str);
void pushvalue(lua_State* L, lua_CFunction fn);
void pushvalue(lua_State* L, lua_CFunction fn, int nup);

View File

@ -5,16 +5,19 @@ using namespace std;
int main()
{
InitEngine();
do {
LuaVM L;
InitEngine(L);
InitLibs(L);
cout << "<ENGINE> Started." << endl;
if (luaL_dofile(L, "code/init.lua"))
{
cout << lua_tostring(L, -1) << endl;
cout << "<ENGINE FATAL ERROR> " << lua_tostring(L, -1) << endl;
}
else
{
cout << "<ENGINE> Stopped normally." << endl;
}
StartEngine(L);
cout << "<ENGINE> Stopped." << endl;
} while (0);
StopEngine();
}

111
Music.cpp Normal file
View File

@ -0,0 +1,111 @@
#include "Music.h"
#include "LuaCommon.h"
#include "LuaHelper.h"
#include <iostream>
using namespace std;
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;
}
inline int Chunk::close(lua_State* L)
{
auto p = (Chunk*)luaL_checkudata(L, 1, "chunk");
p->~Chunk();
return 0;
}
int Chunk::create(lua_State* L)
{
cout << "In Chunk::create" << endl;
const char* filepath = luaL_checkstring(L, 1);
Mix_Chunk* c = Mix_LoadWAVEx(filepath);
if (!c)
{
return LuaSDLError(L);
}
auto p = new (lua_newuserdata(L, sizeof(Chunk))) Chunk(c);
if (luaL_newmetatable(L, "chunk"))
{
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
settype("chunk");
setfn(close, "close");
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
return 1;
}
inline int Chunk::setVolume(lua_State* L)
{
auto p = (Chunk*)luaL_checkudata(L, 1, "chunk");
int v = luaL_checkinteger(L, 2);
int old = Mix_VolumeChunk(p->chunk.get(), v);
lua_pushinteger(L, old);
return 1;
}
inline Chunk::Chunk(Mix_Chunk* c) : chunk(c, Mix_FreeChunk)
{
}
inline Music::Music(Mix_Music* m) : music(m, Mix_FreeMusic)
{
}
inline int Music::close(lua_State* L)
{
cout << "In Music::close" << endl;
auto p = (Music*)luaL_checkudata(L, 1, "music");
p->~Music();
return 0;
}
int Music::create(lua_State* L)
{
cout << "In Music::create" << endl;
const char* filepath = luaL_checkstring(L, 1);
Mix_Music* m = Mix_LoadMUS(filepath);
if (!m)
{
return LuaSDLError(L);
}
auto p = new (lua_newuserdata(L, sizeof(Music))) Music(m);
if(luaL_newmetatable(L, "music"))
{
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
settype("music");
setfn(close, "close");
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
return 1;
}

28
Music.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include "LuaVM.h"
#include "SDL2/include/SDL_mixer.h"
#include <memory>
class Chunk
{
public:
std::shared_ptr<Mix_Chunk> chunk;
Chunk(Mix_Chunk* c);
static int setVolume(lua_State* L);
static int close(lua_State* L);
static int create(lua_State* L);
};
class Music
{
public:
std::shared_ptr<Mix_Music> music;
Music(Mix_Music* m);
static int close(lua_State* L);
static int create(lua_State* L);
};

349
MusicPlayer.cpp Normal file
View File

@ -0,0 +1,349 @@
#include "MusicPlayer.h"
#include "Music.h"
#include "LuaCommon.h"
#include "LuaHelper.h"
#include <iostream>
using namespace std;
inline int MusicPlayer::close(lua_State* L)
{
cout << "In MusicPlayer::close" << endl;
return 0;
}
inline int MusicPlayer::playMusic(lua_State* L)
{
Music* m = (Music*)luaL_checkudata(L, 1, "music");
int nLoop = -1;
if (lua_gettop(L) >= 2)
{
nLoop = luaL_checkinteger(L, 2);
}
int ret = Mix_PlayMusic(m->music.get(), nLoop);
cout << "Play music ret: " << ret << " " << SDL_GetError() << endl;
return 0;
}
inline int MusicPlayer::resumeMusic(lua_State* L)
{
Mix_ResumeMusic();
return 0;
}
inline int MusicPlayer::stopMusic(lua_State* L)
{
Mix_HaltMusic();
return 0;
}
inline int MusicPlayer::pauseMusic(lua_State* L)
{
Mix_PauseMusic();
return 0;
}
inline int MusicPlayer::rewindMusic(lua_State* L)
{
Mix_RewindMusic();
return 0;
}
inline int MusicPlayer::fadeInMusic(lua_State* L)
{
Music* m = (Music*)luaL_checkudata(L, 1, "music");
int fadeTime = luaL_checkinteger(L, 2);
int nLoop = -1;
if (lua_gettop(L) >= 3)
{
nLoop = luaL_checkinteger(L, 3);
}
int ret = Mix_FadeInMusic(m->music.get(), nLoop, fadeTime);
cout << "Fade in music ret: " << ret << " " << SDL_GetError() << endl;
return 0;
}
inline int MusicPlayer::fadeInMusicPos(lua_State* L)
{
Music* m = (Music*)luaL_checkudata(L, 1, "music");
int fadeTime = luaL_checkinteger(L, 2);
double pos = luaL_checknumber(L, 3);
int nLoop = -1;
if (lua_gettop(L) >= 4)
{
nLoop = luaL_checkinteger(L, 4);
}
int ret = Mix_FadeInMusicPos(m->music.get(), nLoop, fadeTime, pos);
cout << "Fade in music ret: " << ret << " " << SDL_GetError() << endl;
return 0;
}
inline int MusicPlayer::fadeOutMusic(lua_State* L)
{
int fadeTime = luaL_checkinteger(L, 1);
int ret = Mix_FadeOutMusic(fadeTime);
cout << "Fade out music ret: " << ret << " " << SDL_GetError() << endl;
return 0;
}
inline int MusicPlayer::setMusicVolume(lua_State* L)
{
int v = luaL_checkinteger(L, 1);
int old = Mix_VolumeMusic(v);
lua_pushinteger(L, old);
return 1;
}
inline int MusicPlayer::setMusicPos(lua_State* L)
{
double pos = luaL_checknumber(L, 1);
int ret = Mix_SetMusicPosition(pos);
if (ret != 0)
{
return LuaSDLError(L);
}
return 0;
}
inline int MusicPlayer::isPlayingMusic(lua_State* L)
{
lua_pushboolean(L, Mix_PlayingMusic());
return 1;
}
inline int MusicPlayer::isPausedMusic(lua_State* L)
{
lua_pushboolean(L, Mix_PausedMusic());
return 1;
}
inline int MusicPlayer::isFadingMusic(lua_State* L)
{
switch (Mix_FadingMusic())
{
case MIX_FADING_OUT:
lua_pushstring(L, "out");
break;
case MIX_FADING_IN:
lua_pushstring(L, "in");
break;
case MIX_NO_FADING:
default:
lua_pushstring(L, "no");
break;
}
return 1;
}
inline int MusicPlayer::playChannel(lua_State* L)
{
Chunk* c = (Chunk*)luaL_checkudata(L, 1, "chunk");
int channel = luaL_checkinteger(L, 2);
int nLoop = -1;
if (lua_gettop(L) >= 3)
{
nLoop = luaL_checkinteger(L, 3);
}
int ret = Mix_PlayChannel(channel, c->chunk.get(), nLoop);
cout << "Play channel ret: " << ret << " " << SDL_GetError() << endl;
return 0;
}
inline int MusicPlayer::fadeInChannel(lua_State* L)
{
Chunk* c = (Chunk*)luaL_checkudata(L, 1, "chunk");
int channel = luaL_checkinteger(L, 2);
int fadeTime = luaL_checkinteger(L, 3);
int nLoop = -1;
if (lua_gettop(L) >= 4)
{
nLoop = luaL_checkinteger(L, 4);
}
int ret = Mix_FadeInChannel(channel, c->chunk.get(), nLoop, fadeTime);
cout << "Fade in channel ret: " << ret << " " << SDL_GetError() << endl;
return 0;
}
inline int MusicPlayer::fadeOutChannel(lua_State* L)
{
int channel = luaL_checkinteger(L, 1);
int fadeTime = luaL_checkinteger(L, 2);
Mix_FadeOutChannel(channel, fadeTime);
return 0;
}
inline int MusicPlayer::stopChannel(lua_State* L)
{
int channel = luaL_checkinteger(L, 1);
Mix_HaltChannel(channel);
return 0;
}
inline int MusicPlayer::resumeChannel(lua_State* L)
{
int channel = luaL_checkinteger(L, 1);
Mix_Resume(channel);
return 0;
}
inline int MusicPlayer::pauseChannel(lua_State* L)
{
int channel = luaL_checkinteger(L, 1);
Mix_Pause(channel);
return 0;
}
inline int MusicPlayer::isPlayingChannel(lua_State* L)
{
int channel = luaL_checkinteger(L, 1);
if (channel == -1)
{
lua_pushinteger(L, Mix_Playing(channel));
}
else
{
lua_pushboolean(L, Mix_Playing(channel));
}
return 1;
}
inline int MusicPlayer::isPausedChannel(lua_State* L)
{
int channel = luaL_checkinteger(L, 1);
if (channel == -1)
{
lua_pushinteger(L, Mix_Paused(channel));
}
else
{
lua_pushboolean(L, Mix_Paused(channel));
}
return 1;
}
inline int MusicPlayer::isFadingChannel(lua_State* L)
{
int channel = luaL_checkinteger(L, 1);
if (channel == -1)
{
return luaL_error(L, "Invalid channel id for isFadingChannel.");
}
switch (Mix_FadingChannel(channel))
{
case MIX_FADING_OUT:
lua_pushstring(L, "out");
break;
case MIX_FADING_IN:
lua_pushstring(L, "in");
break;
case MIX_NO_FADING:
default:
lua_pushstring(L, "no");
break;
}
return 1;
}
inline int MusicPlayer::setChannelVolume(lua_State* L)
{
int channel = luaL_checkinteger(L, 1);
int v = luaL_checkinteger(L, 2);
int old = Mix_Volume(channel, v);
lua_pushinteger(L, old);
return 1;
}
inline int MusicPlayer::setChannelDistance(lua_State* L)
{
int channel = luaL_checkinteger(L, 1);
int dist = luaL_checkinteger(L, 2);
int ret = Mix_SetDistance(channel, dist);
if (ret == 0)
{
return LuaSDLError(L);
}
return 0;
}
inline int MusicPlayer::setChannelPosition(lua_State* L)
{
int channel = luaL_checkinteger(L, 1);
int angle = luaL_checkinteger(L, 2);
int dist = luaL_checkinteger(L, 3);
cout << "Mix_SetPosition " << channel << " " << angle << " " << dist << endl;
if (0 == Mix_SetPosition(channel, angle, dist))
{
return LuaSDLError(L);
}
return 0;
}
inline int MusicPlayer::setChannelPanning(lua_State* L)
{
int channel = luaL_checkinteger(L, 1);
int left = luaL_checkinteger(L, 2);
int right = luaL_checkinteger(L, 3);
if (0 == Mix_SetPanning(channel, left, right))
{
return LuaSDLError(L);
}
return 0;
}
inline int MusicPlayer::setTotalChannel(lua_State* L)
{
int nTotal = luaL_checkinteger(L, 1);
int count = Mix_AllocateChannels(nTotal);
lua_pushinteger(L, count);
return 0;
}
int MusicPlayer::create(lua_State* L)
{
cout << "In MusicPlayer::create" << endl;
if (luaL_newmetatable(L, "musicplayer"))
{
setfn(close, "close");
setfn(playMusic, "playMusic");
setfn(resumeMusic, "resumeMusic");
setfn(pauseMusic, "pauseMusic");
setfn(stopMusic, "stopMusic");
setfn(rewindMusic, "rewindMusic");
setfn(fadeInMusic, "fadeInMusic");
setfn(fadeOutMusic, "fadeOutMusic");
setfn(fadeInMusicPos, "fadeInMusicPos");
setfn(setMusicVolume, "setMusicVolume");
setfn(setMusicPos, "setMusicPos");
setfn(isPlayingMusic, "isPlayingMusic");
setfn(isPausedMusic, "isPausedMusic");
setfn(isFadingMusic, "isFadingMusic");
setfn(playChannel, "playChannel");
setfn(resumeChannel, "resumeChannel");
setfn(pauseChannel, "pauseChannel");
setfn(stopChannel, "stopChannel");
setfn(fadeInChannel, "fadeInChannel");
setfn(fadeOutChannel, "fadeOutChannel");
setfn(setChannelVolume, "setChannelVolume");
setfn(setChannelDistance, "setChannelDistance");
setfn(setChannelPosition, "setChannelPosition");
setfn(setChannelPanning, "setChannelPanning");
setfn(setTotalChannel, "setTotalChannel");
setfn(isPlayingChannel, "isPlayingChannel");
setfn(isPausedChannel, "isPausedChannel");
setfn(isFadingChannel, "isFadingChannel");
}
return 1;
}

66
MusicPlayer.h Normal file
View File

@ -0,0 +1,66 @@
#pragma once
#include "LuaVM.h"
#include "SDL2/include/SDL_mixer.h"
class MusicPlayer
{
public:
static int close(lua_State* L);
static int playMusic(lua_State* L);
static int resumeMusic(lua_State* L);
static int stopMusic(lua_State* L);
static int pauseMusic(lua_State* L);
static int rewindMusic(lua_State* L);
static int fadeInMusic(lua_State* L);
static int fadeInMusicPos(lua_State* L);
static int fadeOutMusic(lua_State* L);
static int setMusicVolume(lua_State* L);
static int setMusicPos(lua_State* L);
static int isPlayingMusic(lua_State* L);
static int isPausedMusic(lua_State* L);
static int isFadingMusic(lua_State* L);
static int playChannel(lua_State* L);
static int fadeInChannel(lua_State* L);
static int fadeOutChannel(lua_State* L);
static int stopChannel(lua_State* L);
static int resumeChannel(lua_State* L);
static int pauseChannel(lua_State* L);
static int isPlayingChannel(lua_State* L);
static int isPausedChannel(lua_State* L);
static int isFadingChannel(lua_State* L);
static int setChannelVolume(lua_State* L);
static int setChannelDistance(lua_State* L);
static int setChannelPosition(lua_State* L);
static int setChannelPanning(lua_State* L);
static int setTotalChannel(lua_State* L);
static int create(lua_State* L);
};

201
Renderer.cpp Normal file
View File

@ -0,0 +1,201 @@
#include "Renderer.h"
#include "Texture.h"
#include "Window.h"
#include "SDL2/include/SDL_image.h"
#include "LuaHelper.h"
#include <iostream>
using namespace std;
inline int Renderer::close(lua_State* L)
{
cout << "In Renderer::close" << endl;
auto p = (Renderer*)luaL_checkudata(L, 1, "renderer");
p->~Renderer();
return 0;
}
Renderer::Renderer(SDL_Renderer* r) : rnd(r, SDL_DestroyRenderer)
{
}
inline int Renderer::update(lua_State* L)
{
auto p = (Renderer*)luaL_checkudata(L, 1, "renderer");
SDL_RenderPresent(p->rnd.get());
return 0;
}
inline int Renderer::clear(lua_State* L)
{
auto p = (Renderer*)luaL_checkudata(L, 1, "renderer");
SDL_RenderClear(p->rnd.get());
return 0;
}
inline int Renderer::setColor(lua_State* L)
{
auto p = (Renderer*)luaL_checkudata(L, 1, "renderer");
luaL_checktype(L, 2, LUA_TTABLE);
SDL_Color c;
if (LuaColorToColor(L, 2, c))
{
luaL_error(L, "bad argument #2 to setColor. rgba expected, got %s", lua_tostring(L, -1));
}
SDL_SetRenderDrawColor(p->rnd.get(), c.r, c.g, c.b, c.a);
return 0;
}
inline int Renderer::getColor(lua_State* L)
{
auto p = (Renderer*)luaL_checkudata(L, 1, "renderer");
Uint8 r, b, g, a;
SDL_GetRenderDrawColor(p->rnd.get(), &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;
}
inline int Renderer::drawRect(lua_State* L)
{
auto p = (Renderer*)luaL_checkudata(L, 1, "renderer");
luaL_checktype(L, 2, LUA_TTABLE);
SDL_Rect r;
if (LuaRectToRect(L, 2, r))
{
luaL_error(L, "bad argument #2 to drawRect. rect expected, got %s", lua_tostring(L, -1));
}
SDL_RenderDrawRect(p->rnd.get(), &r);
return 0;
}
inline int Renderer::fillRect(lua_State* L)
{
auto p = (Renderer*)luaL_checkudata(L, 1, "renderer");
luaL_checktype(L, 2, LUA_TTABLE);
SDL_Rect r;
if (LuaRectToRect(L, 2, r))
{
luaL_error(L, "bad argument #2 to drawRect. rect expected, got %s", lua_tostring(L, -1));
}
SDL_RenderFillRect(p->rnd.get(), &r);
return 0;
}
inline int Renderer::loadTexture(lua_State* L)
{
auto p = (Renderer*)luaL_checkudata(L, 1, "renderer");
auto filepath = luaL_checkstring(L, 2);
SDL_Texture* text = IMG_LoadTexture(p->rnd.get(), filepath);
Texture::create(L, p->rnd, text);
return 1;
}
inline int Renderer::copy(lua_State* L)
{
auto p = (Renderer*)luaL_checkudata(L, 1, "renderer");
auto t = (Texture*)luaL_checkudata(L, 2, "texture");
luaL_checktype(L, 3, LUA_TTABLE);
luaL_checktype(L, 4, LUA_TTABLE);
SDL_Rect src;
if (LuaRectToRect(L, 3, src))
{
luaL_error(L, "bad argument #3 to copy. rect expected, got %s", lua_tostring(L, -1));
}
SDL_Rect dst;
if (LuaRectToRect(L, 4, dst))
{
luaL_error(L, "bad argument #4 to copy. rect expected, got %s", lua_tostring(L, -1));
}
SDL_RenderCopy(p->rnd.get(), t->text.get(), &src, &dst);
return 0;
}
inline int Renderer::copyTo(lua_State* L)
{
auto p = (Renderer*)luaL_checkudata(L, 1, "renderer");
auto t = (Texture*)luaL_checkudata(L, 2, "texture");
luaL_checktype(L, 3, LUA_TTABLE);
SDL_Rect dst;
if (LuaRectPointToRect(L, 3, dst, t->w, t->h))
{
luaL_error(L, "bad argument #4 to copy. rect/point expected, got %s", lua_tostring(L, -1));
}
SDL_RenderCopy(p->rnd.get(), t->text.get(), NULL, &dst);
return 0;
}
inline int Renderer::copyFill(lua_State* L)
{
auto p = (Renderer*)luaL_checkudata(L, 1, "renderer");
auto t = (Texture*)luaL_checkudata(L, 2, "texture");
luaL_checktype(L, 3, LUA_TTABLE);
SDL_Rect src;
if (LuaRectToRect(L, 3, src))
{
luaL_error(L, "bad argument #4 to copy. rect/point expected, got %s", lua_tostring(L, -1));
}
SDL_RenderCopy(p->rnd.get(), t->text.get(), &src, NULL);
return 0;
}
inline int Renderer::copyFullFill(lua_State* L)
{
auto p = (Renderer*)luaL_checkudata(L, 1, "renderer");
auto t = (Texture*)luaL_checkudata(L, 2, "texture");
SDL_RenderCopy(p->rnd.get(), t->text.get(), NULL, NULL);
return 0;
}
int Renderer::create(lua_State* L)
{
cout << "In Renderer::create" << endl;
auto w = (Window*)luaL_checkudata(L, 1, "window");
auto p = new (lua_newuserdata(L, sizeof(Renderer))) Renderer(SDL_CreateRenderer(w->wnd.get(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE));
if (luaL_newmetatable(L, "renderer"))
{
// Type
lua_pushstring(L, "renderer");
lua_setfield(L, -2, "type");
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
setfn(close, "close");
setfn(update, "update");
setfn(clear, "clear");
setfn(setColor, "setColor");
setfn(getColor, "getColor");
setfn(drawRect, "drawRect");
setfn(fillRect, "fillRect");
setfn(loadTexture, "loadTexture");
setfn(copy, "copy");
setfn(copyTo, "copyTo");
setfn(copyFill, "copyFill");
setfn(copyFullFill, "copyFullFill");
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
return 1;
}

38
Renderer.h Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include "LuaCommon.h"
#include <memory>
class Renderer
{
public:
std::shared_ptr<SDL_Renderer> rnd;
Renderer(SDL_Renderer* r);
static int update(lua_State* L);
static int clear(lua_State* L);
static int setColor(lua_State* L);
static int getColor(lua_State* L);
static int drawRect(lua_State* L);
static int fillRect(lua_State* L);
static int loadTexture(lua_State* L);
static int copy(lua_State* L);
static int copyTo(lua_State* L);
static int copyFill(lua_State* L);
static int copyFullFill(lua_State* L);
static int close(lua_State* L);
static int create(lua_State* L);
};

37
Surface.cpp Normal file
View File

@ -0,0 +1,37 @@
#include "Surface.h"
#include "LuaHelper.h"
#include <iostream>
using namespace std;
inline Surface::Surface(SDL_Surface* s) : surf(s, SDL_FreeSurface)
{
}
inline int Surface::close(lua_State* L)
{
cout << "In Surface::close" << endl;
auto p = (Surface*)luaL_checkudata(L, 1, "surface");
p->~Surface();
return 0;
}
int Surface::create(lua_State* L, SDL_Surface* s)
{
cout << "In Surface::create" << endl;
auto p = new (lua_newuserdata(L, sizeof(Surface))) Surface(s);
if (luaL_newmetatable(L, "surface"))
{
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
settype("surface");
setfn(close, "close");
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
return 1;
}

16
Surface.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "LuaVM.h"
#include "SDL2/include/SDL.h"
#include <memory>
class Surface
{
public:
std::shared_ptr<SDL_Surface> surf;
Surface(SDL_Surface* s);
static int close(lua_State* L);
// static int create(lua_State* L, SDL_Surface* surf);
static int create(lua_State* L, SDL_Surface* s);
};

41
Texture.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "Texture.h"
#include "LuaHelper.h"
#include <iostream>
using namespace std;
inline Texture::Texture(const std::shared_ptr<SDL_Renderer>& exrnd, SDL_Texture* t) : rnd(exrnd), text(t, SDL_DestroyTexture)
{
SDL_QueryTexture(t, NULL, NULL, &w, &h);
}
int Texture::create(lua_State* L, const std::shared_ptr<SDL_Renderer>& rnd, SDL_Texture* t)
{
cout << "In Texture::create" << endl;
auto p = new (lua_newuserdata(L, sizeof(Texture))) Texture(rnd, t);
// Metatable
if (luaL_newmetatable(L, "texture"))
{
// Type
lua_pushstring(L, "texture");
lua_setfield(L, -2, "type");
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
setfn(close, "close");
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
return 1;
}
inline int Texture::close(lua_State* L)
{
cout << "In Texture::close" << endl;
auto p = (Texture*)luaL_checkudata(L, 1, "texture");
p->~Texture();
return 0;
}

19
Texture.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include "LuaVM.h"
#include "SDL2/include/SDL.h"
#include <memory>
class Texture
{
public:
std::shared_ptr<SDL_Renderer> rnd;
std::shared_ptr<SDL_Texture> text;
int w;
int h;
Texture(const std::shared_ptr<SDL_Renderer>& exrnd, SDL_Texture* t);
static int close(lua_State* L);
static int create(lua_State* L, const std::shared_ptr<SDL_Renderer>& rnd, SDL_Texture* t);
};

78
Window.cpp Normal file
View File

@ -0,0 +1,78 @@
#include "Window.h"
#include <iostream>
using namespace std;
#define setfn(cfunc, name) lua_pushcfunction(L, cfunc);lua_setfield(L, -2, name)
inline int Window::close(lua_State* L)
{
cout << "In Window::close" << endl;
auto p = (Window*)luaL_checkudata(L, 1, "window");
p->~Window();
return 0;
}
inline int Window::showWindow(lua_State* L)
{
auto p = (Window*)luaL_checkudata(L, 1, "window");
SDL_ShowWindow(p->wnd.get());
return 0;
}
inline int Window::hideWindow(lua_State* L)
{
auto p = (Window*)luaL_checkudata(L, 1, "window");
SDL_HideWindow(p->wnd.get());
return 0;
}
int Window::getWindowID(lua_State* L)
{
auto p = (Window*)luaL_checkudata(L, 1, "window");
lua_pushinteger(L, SDL_GetWindowID(p->wnd.get()));
return 1;
}
int Window::create(lua_State* L)
{
auto title = luaL_checkstring(L, 1);
int w = luaL_checkinteger(L, 2);
int h = luaL_checkinteger(L, 3);
cout << "In Window::create" << endl;
auto p = new (lua_newuserdata(L, sizeof(Window))) Window(w, h, title);
// Data table (for storing lua values)
lua_newtable(L);
lua_setuservalue(L, -2);
// Metatable
if (luaL_newmetatable(L, "window"))
{
// Type
lua_pushstring(L, "window");
lua_setfield(L, -2, "type");
// GC
lua_pushcfunction(L, close);
lua_setfield(L, -2, "__gc");
// Fields
lua_newtable(L);
setfn(close, "close");
setfn(showWindow, "show");
setfn(hideWindow, "hide");
setfn(getWindowID, "getid");
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
return 1;
}
Window::Window(int w, int h, const char* title) : wnd(SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_HIDDEN), SDL_DestroyWindow)
{
}

22
Window.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "LuaVM.h"
#include "SDL2/include/SDL.h"
#include <memory>
class Window
{
public:
std::shared_ptr<SDL_Window> wnd;
Window(int w, int h, const char* title);
static int getWindowID(lua_State* L);
static int showWindow(lua_State* L);
static int hideWindow(lua_State* L);
static int close(lua_State* L);
static int create(lua_State* L);
};

View File

@ -1,3 +1,12 @@
local Window = require("window")
local Renderer = require("renderer")
local Font = require("font")
local MusicPlayer = require("musicplayer")
local Chunk = require("chunk")
local Music = require("music")
local fs = require('fs')
local utils = require("utils")
local wnd = Window("Hello", 1024, 768)
local rnd = Renderer(wnd)
local font = Font("asserts/msyh.ttf", 18)
@ -23,7 +32,7 @@ local next_music = 1
for i, info in ipairs(all_music) do
local filename = string.format("tmp\\tmp_%d.wav", i)
ConvertMusic(string.format("asserts\\mp3\\%s",info.name), filename, function()
utils.ConvertMusic(string.format("asserts\\mp3\\%s",info.name), filename, function()
print(filename, "convert finished.")
print("Start loading: ", filename)
table.insert(music_table, Chunk(filename))
@ -41,24 +50,25 @@ setmetatable(texture_track, {
__mode = "k"
})
wnd:on('mousedown', function(x, y)
print("Clicked", x, y)
local t = font:renderText(rnd, string.format("%.0f,%.0f", x, y), {r=255,g=255,b=255,a=0,type="color"})
wnd:on('mousedown', function(e)
print("Clicked", e.x, e.y)
local t = font:renderText(rnd, string.format("%.0f,%.0f", e.x, e.y), RGBA(255, 255, 255, 0))
texture_track[t] = true
rnd:copyTo(t, {x=x,y=y,type="point"})
rnd:copyTo(t, Point(e.x, e.y))
rnd:update()
end)
wnd:on('mousemove', function(x, y, xrel, yrel)
-- print("Mousemove", x, y, xrel, yrel)
wnd:on('mousemove', function(e)
-- print("Mousemove", e.x, e.y, e.xrel, e.yrel)
end)
wnd:on('quit', function()
print("before quit")
return false
end)
wnd:on('keydown', function(key)
wnd:on('keydown', function(e)
local key = e.key
print("keydown", key)
if key == string.byte('q') then
local current = collectgarbage("count")
@ -74,12 +84,12 @@ wnd:on('keydown', function(key)
print ("Tracked texture: ", cnt)
return
elseif key == string.byte('p') then
musicPlayer:fadeOutChannel(last_channel, 5000)
musicPlayer.fadeOutChannel(last_channel, 5000)
if not music_table[next_music] then
next_music = 1
end
print("Playing", next_music, next_channel)
musicPlayer:fadeInChannel(music_table[next_music], next_channel, 1, 3000)
musicPlayer.fadeInChannel(music_table[next_music], next_channel, 1, 3000)
next_music = next_music + 1
last_channel = next_channel
next_channel = next_channel + 1
@ -92,8 +102,8 @@ wnd:on('keydown', function(key)
rnd:clear()
local t = rnd:loadTexture("asserts/bqb_all/" .. all_bqb[math.random(#all_bqb)].name)
texture_track[t] = true
rnd:copyTo(t, {x=0,y=0,type="point"})
rnd:copyTo(t, Point(0, 0))
rnd:update()
end)
wnd:show()
wnd:show()

View File

@ -1,6 +1,49 @@
-- Tweaks
local plainRenderer = Renderer
Renderer = function(...)
local engine = require("engine")
------------------------- Events -------------------------
local event = {}
local timers = {}
local listeners = {}
local callbacks = {}
local window_map = {}
function event.window_listen(wnd, event_name, cb)
local window_id = wnd:getid()
window_map[window_id] = wnd
if not listeners[window_id] then
listeners[window_id] = {}
end
if not listeners[window_id][event_name] then
listeners[window_id][event_name] = {}
end
listeners[window_id][event_name][cb] = true
end
function event.listen(event_name, cb)
if not listeners[event_name] then
listeners[event_name] = {}
end
listeners[event_name][cb] = true
end
------------------------- Utils -------------------------
local utils = {}
function utils.ConvertMusic(from, target, cb)
table.insert(callbacks, cb)
engine.convertMusic(from, target, #callbacks)
end
function utils.setInterval(cb, ms)
local tid = engine.setInterval(ms)
timers[tid] = cb
end
function utils.setTimeout(cb, ms)
local tid = engine.setTimeout(ms)
timers[tid] = cb
end
package.loaded["utils"] = utils
------------------------- Tweaks -------------------------
local plainRenderer = require("renderer")
package.loaded["renderer"] = function(...)
local r = plainRenderer(...)
local mt = getmetatable(r)
local oldFunc = mt.__index.loadTexture
@ -23,12 +66,26 @@ Renderer = function(...)
end
return text
end
Renderer = plainRenderer
package.loaded["renderer"] = plainRenderer
return r
end
local plainWindow = require("window")
package.loaded["window"] = function(...)
local w = plainWindow(...)
local mt = getmetatable(w)
mt.__index["on"] = function(wnd, event_name, cb)
if event_name == "quit" then
event.listen("quit", cb)
else
event.window_listen(wnd, event_name, cb)
end
end
package.loaded["window"] = plainWindow
return w
end
-- Promise, Async/Await Helpers
function Promise(callback)
------------------------- Promise, Async/Await Helpers -------------------------
function Promise(cb)
local p = {
__waiting = {},
__status = 0
@ -54,7 +111,7 @@ function Promise(callback)
end
end
callback(p.resolve, p.reject)
cb(p.resolve, p.reject)
return p
end
@ -95,14 +152,50 @@ function async(fn)
end
end
-- Load & run game
local gameMain, err = loadfile("code/network_test.lua")
------------------------- Load & run game -------------------------
local gameMain, err = loadfile("code/game.lua")
if not gameMain then
print("Failed to load chunk.")
print("Lua compile error:")
print(err)
error("Abort")
else
xpcall(gameMain, function(err)
print("LuaMain Exception: ", err)
if not xpcall(gameMain, function(err)
print("Uncaught Exception from LuaMain: ", err)
print(debug.traceback())
end)
end) then
error("Abort")
end
end
------------------------- Event handling -------------------------
local engineState = true
local function DispatchEvent(e)
if e.windowID then
if listeners[e.windowID] and listeners[e.windowID][e.type] then
for k in pairs(listeners[e.windowID][e.type]) do
k(e)
end
end
elseif e.type == "general" then
callbacks[e.ticket]()
elseif e.type == "quit" then
for k in pairs(listeners["quit"]) do
local ret = k()
if ret or ret == nil then
engineState = false
end
end
else
if listeners[e.type] then
for k in pairs(listeners[e.type]) do
k(e)
end
end
end
end
while engineState do
local e = engine.waitEvent()
DispatchEvent(e)
end