LuaYard/LuaEngine.cpp

441 lines
9.3 KiB
C++
Raw Permalink Blame History

#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;
}