441 lines
9.3 KiB
C++
441 lines
9.3 KiB
C++
#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 "LuaHelper.h"
|
||
#include "LuaNetwork.h"
|
||
#include "EventDef.h"
|
||
#include "Window.h"
|
||
#include "Renderer.h"
|
||
#include "Font.h"
|
||
#include "Music.h"
|
||
#include "MusicPlayer.h"
|
||
using namespace std;
|
||
|
||
void doConvertMusicAsync(string filename, 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 = ENGINE_GENERAL_CALLBACK; // General zero ret callback.
|
||
e.user.data1 = new int(ticket);
|
||
SDL_PushEvent(&e);
|
||
}
|
||
|
||
static int ConvertMusicAsyncImpl(lua_State* L)
|
||
{
|
||
string filename(luaL_checkstring(L, 1));
|
||
string targetname(luaL_checkstring(L, 2));
|
||
int ticket = luaL_checkinteger(L, 3);
|
||
|
||
thread td(doConvertMusicAsync, filename, targetname, ticket);
|
||
td.detach();
|
||
|
||
return 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;
|
||
}
|
||
|
||
const char* GetMouseButtonName(int button)
|
||
{
|
||
switch (button)
|
||
{
|
||
case SDL_BUTTON_LEFT:
|
||
return "left";
|
||
case SDL_BUTTON_MIDDLE:
|
||
return "middle";
|
||
case SDL_BUTTON_RIGHT:
|
||
return "right";
|
||
case SDL_BUTTON_X1:
|
||
return "x1";
|
||
case SDL_BUTTON_X2:
|
||
return "x2";
|
||
default:
|
||
return "unknown";
|
||
}
|
||
}
|
||
|
||
struct LibFS
|
||
{
|
||
static int listdir(lua_State* L)
|
||
{
|
||
const char* dirname = luaL_checkstring(L, 1);
|
||
vector<FileInfo> vec = ListDir(dirname);
|
||
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(listdir, "listdir");
|
||
|
||
return 1;
|
||
}
|
||
};
|
||
|
||
void _Global_On_Music_Finished()
|
||
{
|
||
SDL_Event e;
|
||
e.type = SDL_USEREVENT;
|
||
e.user.code = ENGINE_MUSIC_FINISH;
|
||
SDL_PushEvent(&e);
|
||
}
|
||
|
||
void _Global_On_Channel_Finished(int channel)
|
||
{
|
||
SDL_Event e;
|
||
e.type = SDL_USEREVENT;
|
||
e.user.code = ENGINE_CHANNEL_FINISH;
|
||
e.user.data1 = new int(channel);
|
||
SDL_PushEvent(&e);
|
||
}
|
||
|
||
struct LuaTimerCallbackData
|
||
{
|
||
int id;
|
||
int type; // 0=setTimeout, 1=setInterval
|
||
};
|
||
|
||
Uint32 LuaTimerCallbackGate(Uint32 interval, void* param)
|
||
{
|
||
SDL_Event e;
|
||
e.type = SDL_USEREVENT;
|
||
e.user.code = ENGINE_TIMER_EVENT;
|
||
e.user.data1 = param;
|
||
SDL_PushEvent(&e);
|
||
return ((LuaTimerCallbackData*)(param))->type ? interval : 0;
|
||
}
|
||
|
||
static int SetTimeoutImpl(lua_State* L)
|
||
{
|
||
int ms = luaL_checkinteger(L, 1);
|
||
|
||
LuaTimerCallbackData* pd = new LuaTimerCallbackData();
|
||
pd->type = 0;
|
||
pd->id = SDL_AddTimer(ms, LuaTimerCallbackGate, pd);
|
||
if (pd->id == 0)
|
||
{
|
||
return LuaSDLError(L);
|
||
}
|
||
lua_pushinteger(L, pd->id);
|
||
return 1;
|
||
}
|
||
|
||
static int SetIntervalImpl(lua_State* L)
|
||
{
|
||
int ms = luaL_checkinteger(L, 1);
|
||
|
||
LuaTimerCallbackData* pd = new LuaTimerCallbackData();
|
||
pd->type = 1;
|
||
pd->id = SDL_AddTimer(ms, LuaTimerCallbackGate, pd);
|
||
if (pd->id == 0)
|
||
{
|
||
return LuaSDLError(L);
|
||
}
|
||
lua_pushinteger(L, pd->id);
|
||
return 1;
|
||
}
|
||
|
||
int TranslateEvent(lua_State* L, SDL_Event& e);
|
||
|
||
int WaitEvent(lua_State* L)
|
||
{
|
||
SDL_Event e;
|
||
while (SDL_WaitEvent(&e))
|
||
{
|
||
if (TranslateEvent(L, e))
|
||
{
|
||
return 1;
|
||
}
|
||
}
|
||
return LuaSDLError(L);
|
||
}
|
||
|
||
int PollEvent(lua_State* L)
|
||
{
|
||
SDL_Event e;
|
||
int cnt = 1;
|
||
lua_newtable(L);
|
||
while (SDL_PollEvent(&e))
|
||
{
|
||
if (TranslateEvent(L, e))
|
||
{
|
||
lua_seti(L, -2, cnt++);
|
||
}
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
int TranslateEvent(lua_State* L, SDL_Event& e)
|
||
{
|
||
switch (e.type)
|
||
{
|
||
case SDL_MOUSEBUTTONUP:
|
||
case SDL_MOUSEBUTTONDOWN:
|
||
{
|
||
lua_newtable(L);
|
||
if (e.type == SDL_MOUSEBUTTONUP)
|
||
{
|
||
lua_pushstring(L, "mouseup");
|
||
}
|
||
else
|
||
{
|
||
lua_pushstring(L, "mousedown");
|
||
}
|
||
lua_setfield(L, -2, "type");
|
||
lua_pushinteger(L, e.button.windowID); lua_setfield(L, -2, "windowID");
|
||
lua_pushinteger(L, e.button.x); lua_setfield(L, -2, "x");
|
||
lua_pushinteger(L, e.button.y); lua_setfield(L, -2, "y");
|
||
lua_pushinteger(L, e.button.clicks); lua_setfield(L, -2, "clicks");
|
||
lua_pushinteger(L, e.button.state); lua_setfield(L, -2, "state");
|
||
lua_pushstring(L, GetMouseButtonName(e.button.button)); lua_setfield(L, -2, "button");
|
||
break;
|
||
}
|
||
case SDL_MOUSEMOTION:
|
||
{
|
||
lua_newtable(L);
|
||
lua_pushstring(L, "mousemove"); lua_setfield(L, -2, "type");
|
||
lua_pushinteger(L, e.motion.windowID); lua_setfield(L, -2, "windowID");
|
||
lua_pushinteger(L, e.motion.x); lua_setfield(L, -2, "x");
|
||
lua_pushinteger(L, e.motion.y); lua_setfield(L, -2, "y");
|
||
lua_pushinteger(L, e.motion.xrel); lua_setfield(L, -2, "xrel");
|
||
lua_pushinteger(L, e.motion.yrel); lua_setfield(L, -2, "yrel");
|
||
const char* arr[8];
|
||
int ret = GetMouseState(arr, e.motion.state);
|
||
lua_newtable(L);
|
||
for (int i = 0; i < ret; i++)
|
||
{
|
||
lua_pushboolean(L, 1);
|
||
lua_setfield(L, -2, arr[i]);
|
||
}
|
||
lua_setfield(L, -2, "state");
|
||
break;
|
||
}
|
||
case SDL_QUIT:
|
||
{
|
||
lua_newtable(L);
|
||
lua_pushstring(L, "quit"); lua_setfield(L, -2, "type");
|
||
break;
|
||
}
|
||
case SDL_KEYUP:
|
||
case SDL_KEYDOWN:
|
||
{
|
||
lua_newtable(L);
|
||
if (e.type == SDL_KEYUP)
|
||
{
|
||
lua_pushstring(L, "keyup");
|
||
}
|
||
else
|
||
{
|
||
lua_pushstring(L, "keydown");
|
||
}
|
||
lua_setfield(L, -2, "type");
|
||
lua_pushinteger(L, e.key.windowID); lua_setfield(L, -2, "windowID");
|
||
lua_pushinteger(L, e.key.keysym.sym); lua_setfield(L, -2, "key");
|
||
lua_pushinteger(L, e.key.repeat); lua_setfield(L, -2, "repeat");
|
||
break;
|
||
}
|
||
case SDL_USEREVENT:
|
||
{
|
||
switch (e.user.code)
|
||
{
|
||
case ENGINE_TIMER_EVENT:
|
||
{
|
||
// <20><>ʱ<EFBFBD><CAB1><EFBFBD>ص<EFBFBD>
|
||
LuaTimerCallbackData* pd = (LuaTimerCallbackData*)e.user.data1;
|
||
lua_newtable(L);
|
||
lua_pushstring(L, "timer"); lua_setfield(L, -2, "type");
|
||
lua_pushinteger(L, pd->id); lua_setfield(L, -2, "id");
|
||
if (!pd->type)
|
||
{
|
||
delete pd;
|
||
}
|
||
break;
|
||
}
|
||
case ENGINE_GENERAL_CALLBACK:
|
||
{
|
||
// Ticket<65>ص<EFBFBD>
|
||
lua_newtable(L);
|
||
lua_pushstring(L, "general"); lua_setfield(L, -2, "type");
|
||
lua_pushinteger(L, *(int*)e.user.data1); lua_setfield(L, -2, "ticket");
|
||
delete (int*)e.user.data1;
|
||
break;
|
||
}
|
||
case 1003:
|
||
{
|
||
// <20><><EFBFBD>ֲ<EFBFBD><D6B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
lua_newtable(L);
|
||
lua_pushstring(L, "musicover"); lua_setfield(L, -2, "type");
|
||
break;
|
||
}
|
||
case 1004:
|
||
{
|
||
// Ƶ<><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
lua_newtable(L);
|
||
lua_pushstring(L, "channelover"); lua_setfield(L, -2, "type");
|
||
lua_pushinteger(L, *(int*)e.user.data1); lua_setfield(L, -2, "channel");
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
cout << "Unhandled UserEvent: " << e.user.code << endl;
|
||
return 0;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
cout << "Unhandled Event: 0x" << hex << e.type << endl;
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
// "Failed to initialize %s. ret: %d. expected: %d. SDLError: %s", name, ret, expected, SDL_GetError()
|
||
|
||
int InitEngine()
|
||
{
|
||
int ret;
|
||
ret = SDL_Init(SDL_INIT_EVERYTHING);
|
||
if (ret != 0)
|
||
{
|
||
printf("SDL_Init Failed: %s\n", SDL_GetError());
|
||
return -1;
|
||
}
|
||
ret = IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
|
||
if (ret != (IMG_INIT_JPG | IMG_INIT_PNG))
|
||
{
|
||
printf("IMG_Init Failed: %s\n", SDL_GetError());
|
||
return -1;
|
||
}
|
||
ret = TTF_Init();
|
||
if (ret != 0)
|
||
{
|
||
printf("TTF_Init Failed: %s\n", SDL_GetError());
|
||
return -1;
|
||
}
|
||
ret = Mix_Init(MIX_INIT_MP3 | MIX_INIT_MOD | MIX_INIT_OGG);
|
||
if (ret != (MIX_INIT_MP3 | MIX_INIT_MOD | MIX_INIT_OGG))
|
||
{
|
||
printf("Mix_Init Failed: %s\n", SDL_GetError());
|
||
return -1;
|
||
}
|
||
|
||
ret = Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 512);
|
||
if (ret != 0)
|
||
{
|
||
printf("Mix_OpenAudio Failed: %s\n", SDL_GetError());
|
||
return -2;
|
||
}
|
||
|
||
Mix_AllocateChannels(16);
|
||
Mix_HookMusicFinished(_Global_On_Music_Finished);
|
||
Mix_ChannelFinished(_Global_On_Channel_Finished);
|
||
|
||
return 0;
|
||
}
|
||
|
||
#define reg_in_package(cfunc, name) lua_pushcfunction(L, cfunc); lua_setfield(L, -2, name)
|
||
|
||
int InitLibs(lua_State* L)
|
||
{
|
||
lua_getglobal(L, "package");
|
||
lua_getfield(L, -1, "loaded");
|
||
|
||
// Basic things
|
||
reg_in_package(Window::create, "window");
|
||
reg_in_package(Renderer::create, "renderer");
|
||
reg_in_package(Font::create, "font");
|
||
reg_in_package(Chunk::create, "chunk");
|
||
reg_in_package(Music::create, "music");
|
||
reg_in_package(MusicPlayer::create, "musicplayer");
|
||
|
||
// Engine functions
|
||
lua_newtable(L);
|
||
setfn(ConvertMusicAsyncImpl, "convertMusic");
|
||
setfn(SetTimeoutImpl, "setTimeout");
|
||
setfn(SetIntervalImpl, "setInterval");
|
||
setfn(WaitEvent, "waitEvent");
|
||
setfn(PollEvent, "pollEvent");
|
||
lua_setfield(L, -2, "engine");
|
||
|
||
// FS Library
|
||
LibFS::create(L);
|
||
lua_setfield(L, -2, "fs");
|
||
|
||
// Keys
|
||
InitKeys(L);
|
||
lua_setfield(L, -2, "keys");
|
||
|
||
// Network
|
||
InitLuaNetwork(L);
|
||
lua_setfield(L, -2, "socket");
|
||
|
||
// Stack balance
|
||
lua_pop(L, 2);
|
||
return 0;
|
||
}
|
||
|
||
int StopEngine()
|
||
{
|
||
Mix_CloseAudio();
|
||
Mix_Quit();
|
||
TTF_Quit();
|
||
IMG_Quit();
|
||
SDL_Quit();
|
||
|
||
return 0;
|
||
}
|