Next Attempt (2024)!
-Still lots todo! but I have a (mostly) working version up and running!
This commit is contained in:
parent
2eb6d44c2c
commit
2f19ab8bb5
|
@ -1,4 +1,5 @@
|
|||
build*/
|
||||
debug*/
|
||||
bin
|
||||
obj
|
||||
*.depend
|
||||
|
|
|
@ -54,6 +54,8 @@ set(SOURCES_QT_SDL
|
|||
|
||||
LANDialog.cpp
|
||||
NetplayDialog.cpp
|
||||
|
||||
LuaMain.cpp
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
|
@ -84,6 +86,7 @@ endif()
|
|||
pkg_check_modules(SDL2 REQUIRED IMPORTED_TARGET sdl2)
|
||||
pkg_check_modules(LibArchive REQUIRED IMPORTED_TARGET libarchive)
|
||||
pkg_check_modules(Zstd REQUIRED IMPORTED_TARGET libzstd)
|
||||
pkg_search_module(Lua REQUIRED IMPORTED_TARGET lua-5.4 lua-5.3 lua>=5.3)
|
||||
|
||||
fix_interface_includes(PkgConfig::SDL2 PkgConfig::LibArchive)
|
||||
|
||||
|
@ -178,7 +181,7 @@ else()
|
|||
target_include_directories(melonDS PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
endif()
|
||||
target_link_libraries(melonDS PRIVATE core)
|
||||
target_link_libraries(melonDS PRIVATE PkgConfig::SDL2 PkgConfig::LibArchive PkgConfig::Zstd)
|
||||
target_link_libraries(melonDS PRIVATE PkgConfig::SDL2 PkgConfig::LibArchive PkgConfig::Zstd PkgConfig::Lua)
|
||||
target_link_libraries(melonDS PRIVATE ${QT_LINK_LIBS} ${CMAKE_DL_LIBS})
|
||||
|
||||
if (WIN32)
|
||||
|
|
|
@ -136,6 +136,7 @@ public:
|
|||
int getJoystickID() { return joystickID; }
|
||||
SDL_Joystick* getJoystick() { return joystick; }
|
||||
|
||||
std::vector<int> keyStrokes;
|
||||
private:
|
||||
static int lastSep(const std::string& path);
|
||||
std::string getAssetPath(bool gba, const std::string& configpath, const std::string& ext, const std::string& file);
|
||||
|
@ -205,6 +206,7 @@ private:
|
|||
static void audioCallback(void* data, Uint8* stream, int len);
|
||||
static void micCallback(void* data, Uint8* stream, int len);
|
||||
|
||||
|
||||
void onKeyPress(QKeyEvent* event);
|
||||
void onKeyRelease(QKeyEvent* event);
|
||||
void keyReleaseAll();
|
||||
|
@ -254,6 +256,8 @@ public:
|
|||
bool doLimitFPS;
|
||||
int maxFPS;
|
||||
bool doAudioSync;
|
||||
|
||||
melonDS::u32 getInputMask(){return inputMask;}
|
||||
private:
|
||||
|
||||
std::unique_ptr<melonDS::Savestate> backupState;
|
||||
|
|
|
@ -220,6 +220,7 @@ void EmuInstance::onKeyPress(QKeyEvent* event)
|
|||
{
|
||||
int keyHK = getEventKeyVal(event);
|
||||
int keyKP = keyHK;
|
||||
keyStrokes.push_back(keyHK);
|
||||
if (event->modifiers() != Qt::KeypadModifier)
|
||||
keyKP &= ~event->modifiers();
|
||||
|
||||
|
|
|
@ -56,6 +56,8 @@
|
|||
|
||||
#include "EmuInstance.h"
|
||||
|
||||
#include "LuaMain.h"
|
||||
|
||||
using namespace melonDS;
|
||||
|
||||
|
||||
|
@ -439,6 +441,11 @@ void EmuThread::run()
|
|||
}
|
||||
|
||||
handleMessages();
|
||||
|
||||
//Lua Script Stuff (-for now happens at the end of each frame regardless of emuStatus)
|
||||
LuaScript::createLuaState();//Create LuaState if needed
|
||||
LuaScript::luaUpdate(); //"_Update()" gets called in current lua script
|
||||
|
||||
}
|
||||
|
||||
file = Platform::OpenLocalFile("rtc.bin", Platform::FileMode::Write);
|
||||
|
|
|
@ -107,6 +107,12 @@ public:
|
|||
void deinitContext();
|
||||
void updateVideoSettings() { videoSettingsDirty = true; }
|
||||
|
||||
void onLuaPrint(const QString&);
|
||||
void onLuaClearConsole();
|
||||
void onLuaLoadState(const QString&);
|
||||
void onLuaSaveState(const QString&);
|
||||
void onLuaLayoutChange();
|
||||
|
||||
int FrontBuffer = 0;
|
||||
QMutex FrontBufferLock;
|
||||
|
||||
|
@ -130,6 +136,11 @@ signals:
|
|||
|
||||
void syncVolumeLevel();
|
||||
|
||||
void signalLuaPrint(const QString&);
|
||||
void signalLuaClearConsole();
|
||||
void signalLuaSaveState(const QString&);
|
||||
void signalLuaLoadState(const QString&);
|
||||
|
||||
private:
|
||||
void handleMessages();
|
||||
|
||||
|
|
|
@ -0,0 +1,628 @@
|
|||
#include "LuaMain.h"
|
||||
#include <filesystem>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QPushButton>
|
||||
#include <QGuiApplication>
|
||||
#include <QScrollBar>
|
||||
#include <QPainter>
|
||||
#include "types.h"
|
||||
#include "NDS.h"
|
||||
#include <SDL_joystick.h>
|
||||
#include <NDS_Header.h>
|
||||
#include "main.h"
|
||||
|
||||
// #include "Input.h" --Need to fix keyboard inputs
|
||||
|
||||
void EmuThread::onLuaPrint(const QString& string)
|
||||
{
|
||||
emit signalLuaPrint(string);
|
||||
}
|
||||
|
||||
void EmuThread::onLuaClearConsole()
|
||||
{
|
||||
emit signalLuaClearConsole();
|
||||
}
|
||||
|
||||
void EmuThread::onLuaLoadState(const QString& string)
|
||||
{
|
||||
emit signalLuaLoadState(string);
|
||||
}
|
||||
|
||||
void EmuThread::onLuaLayoutChange()
|
||||
{
|
||||
//TODO:
|
||||
//emit screenLayoutChange();
|
||||
}
|
||||
|
||||
void EmuThread::onLuaSaveState(const QString& string)
|
||||
{
|
||||
emit signalLuaSaveState(string);
|
||||
}
|
||||
|
||||
namespace LuaScript
|
||||
{
|
||||
LuaConsoleDialog* LuaDialog=nullptr;
|
||||
|
||||
//Currently only supporting one EmuInstance
|
||||
EmuInstance* CurrentInstance = nullptr;
|
||||
EmuThread* CurrentThread = nullptr;
|
||||
|
||||
LuaConsoleDialog::LuaConsoleDialog(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
QWidget* w = parent;
|
||||
|
||||
//Yoinked from ScreenPanel in Screen.cpp
|
||||
for (;;)
|
||||
{
|
||||
mainWindow = qobject_cast<MainWindow*>(w);
|
||||
if (mainWindow) break;
|
||||
w = w->parentWidget();
|
||||
if (!w) break;
|
||||
}
|
||||
|
||||
CurrentInstance = mainWindow->getEmuInstance();
|
||||
CurrentThread = CurrentInstance->getEmuThread();
|
||||
console = new LuaConsole(this);
|
||||
console->setGeometry(0,20,302,80);
|
||||
bar = console->verticalScrollBar();
|
||||
buttonPausePlay = new QPushButton("Pause/UnPause",this);
|
||||
buttonPausePlay->setGeometry(0,0,100,20);
|
||||
buttonStartStop = new QPushButton("Stop",this);
|
||||
buttonStartStop->setGeometry(101,0,100,20);
|
||||
buttonOpenScript = new QPushButton("OpenLuaFile",this);
|
||||
buttonOpenScript->setGeometry(202,0,100,20);
|
||||
connect(buttonOpenScript,&QPushButton::clicked,this,&LuaConsoleDialog::onOpenScript);
|
||||
connect(buttonStartStop,&QPushButton::clicked,this,&LuaConsoleDialog::onStop);
|
||||
connect(buttonPausePlay,&QPushButton::clicked,this,&LuaConsoleDialog::onPausePlay);
|
||||
connect(CurrentThread,&EmuThread::signalLuaPrint,console,&LuaConsole::onGetText);
|
||||
connect(CurrentThread,&EmuThread::signalLuaClearConsole,console,&LuaConsole::onClear);
|
||||
this->setWindowTitle("Lua Script");
|
||||
}
|
||||
|
||||
void LuaConsoleDialog::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
onStop();
|
||||
LuaDialog = nullptr;
|
||||
LuaOverlays.clear();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void LuaConsoleDialog::onOpenScript()
|
||||
{
|
||||
QFileInfo file = QFileInfo(QFileDialog::getOpenFileName(this, "Load Lua Script",QDir::currentPath()));
|
||||
if (!file.exists())
|
||||
return;
|
||||
currentScript = file;
|
||||
FlagNewLua = true;
|
||||
}
|
||||
|
||||
LuaConsole::LuaConsole(QWidget* parent)
|
||||
{
|
||||
this->setParent(parent);
|
||||
}
|
||||
|
||||
void LuaConsole::onGetText(const QString& string)
|
||||
{
|
||||
this->appendPlainText(string);
|
||||
QScrollBar* bar = verticalScrollBar();
|
||||
bar->setValue(bar->maximum());
|
||||
}
|
||||
|
||||
void LuaConsole::onClear()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
void luaClearConsole()
|
||||
{
|
||||
LuaDialog->console->clear();
|
||||
}
|
||||
|
||||
std::vector<LuaFunction*> LuaFunctionList; // List of all lua functions.
|
||||
lua_State* MainLuaState = nullptr;
|
||||
bool FlagPause = false;
|
||||
bool FlagStop = false;
|
||||
bool FlagNewLua = false;
|
||||
|
||||
LuaFunction::LuaFunction(luaFunctionPointer cf,const char* n,std::vector<LuaFunction*>* container)
|
||||
{
|
||||
this->cfunction = cf;
|
||||
this->name = n;
|
||||
container->push_back(this);
|
||||
}
|
||||
|
||||
#define MELON_LUA_HOOK_INSTRUCTION_COUNT 50 //number of vm instructions between hook calls
|
||||
void luaHookFunction(lua_State* L, lua_Debug *arg)
|
||||
{
|
||||
if(FlagStop and (arg->event == LUA_HOOKCOUNT))
|
||||
luaL_error(L, "Force Stopped");
|
||||
}
|
||||
|
||||
void createLuaState()
|
||||
{
|
||||
if(!FlagNewLua)
|
||||
return;
|
||||
printf("Creating LuaState");
|
||||
LuaOverlays.clear();
|
||||
FlagNewLua = false;
|
||||
MainLuaState = nullptr;
|
||||
std::string fileName = LuaDialog->currentScript.fileName().toStdString();
|
||||
std::string filedir = LuaDialog->currentScript.dir().path().toStdString();
|
||||
lua_State* L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
for(LuaFunction* function : LuaFunctionList)
|
||||
lua_register(L,function->name,function->cfunction);
|
||||
std::filesystem::current_path(filedir.c_str());
|
||||
lua_sethook(L,&luaHookFunction,LUA_MASKCOUNT,MELON_LUA_HOOK_INSTRUCTION_COUNT);
|
||||
FlagStop = false;
|
||||
if (luaL_dofile(L,&fileName[0])==LUA_OK)
|
||||
{
|
||||
MainLuaState = L;
|
||||
FlagPause = false;
|
||||
}
|
||||
else //Error loading script
|
||||
{
|
||||
CurrentThread->onLuaPrint(lua_tostring(L,-1));
|
||||
MainLuaState = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void LuaConsoleDialog::onStop()
|
||||
{
|
||||
FlagStop = true;
|
||||
}
|
||||
|
||||
void LuaConsoleDialog::onPausePlay()
|
||||
{
|
||||
FlagPause = !FlagPause;
|
||||
}
|
||||
|
||||
//Gets Called once a frame
|
||||
void luaUpdate()
|
||||
{
|
||||
if(!MainLuaState || FlagPause)
|
||||
return;
|
||||
if (lua_getglobal(MainLuaState,"_Update")!=LUA_TFUNCTION)
|
||||
{
|
||||
CurrentThread->onLuaPrint("No \"_Update\" Function found, pausing script...");
|
||||
FlagPause = true;
|
||||
return;
|
||||
}
|
||||
if(lua_pcall(MainLuaState,0,0,0)!=0)
|
||||
{
|
||||
//Handel Errors
|
||||
CurrentThread->onLuaPrint(lua_tostring(MainLuaState,-1));
|
||||
MainLuaState = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Front End Stuff
|
||||
*/
|
||||
|
||||
OverlayCanvas::OverlayCanvas(int x,int y,int width,int height,bool isActive)
|
||||
{
|
||||
this->isActive=isActive;
|
||||
buffer1 = new QImage(width,height,QImage::Format_ARGB32_Premultiplied);
|
||||
buffer2 = new QImage(width,height,QImage::Format_ARGB32_Premultiplied);
|
||||
buffer1->fill(0xffffff00); //initializes buffer with yellow pixels (probably should change this to transparent black pixels at some point...)
|
||||
buffer2->fill(0xffffff00);
|
||||
imageBuffer = buffer1;
|
||||
displayBuffer = buffer2;
|
||||
rectangle = QRect(x,y,width,height);
|
||||
flipped = false;
|
||||
GLTextureLoaded = false;
|
||||
}
|
||||
void OverlayCanvas::flip()
|
||||
{
|
||||
if (imageBuffer == buffer1)
|
||||
{
|
||||
imageBuffer = buffer2;
|
||||
displayBuffer = buffer1;
|
||||
}
|
||||
else
|
||||
{
|
||||
imageBuffer = buffer1;
|
||||
displayBuffer = buffer2;
|
||||
}
|
||||
flipped = true;
|
||||
}
|
||||
|
||||
std::vector<OverlayCanvas> LuaOverlays;
|
||||
OverlayCanvas* CurrentCanvas;
|
||||
QHash<QString , QImage> ImageHash;
|
||||
|
||||
void luaResetOSD()
|
||||
{
|
||||
for (auto lo = LuaOverlays.begin(); lo != LuaOverlays.end();)
|
||||
{
|
||||
OverlayCanvas& overlay = *lo;
|
||||
overlay.GLTextureLoaded = false;
|
||||
lo++;
|
||||
}
|
||||
}
|
||||
|
||||
int RightPadding = 0;
|
||||
int BottomPadding = 0;
|
||||
int LeftPadding = 0;
|
||||
int TopPadding = 0;
|
||||
|
||||
#define AddLuaFunction(functPointer,name)LuaFunction name(functPointer,#name,&LuaFunctionList)
|
||||
|
||||
/*
|
||||
* Start Defining Lua Functions:
|
||||
*/
|
||||
|
||||
namespace LuaFunctionDefinition
|
||||
{
|
||||
int lua_MelonPrint(lua_State* L)
|
||||
{
|
||||
QString string = luaL_checkstring(L,1);
|
||||
CurrentThread->onLuaPrint(string);
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(lua_MelonPrint,MelonPrint);
|
||||
|
||||
int lua_MelonClear(lua_State* L)
|
||||
{
|
||||
CurrentThread->onLuaClearConsole();
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(lua_MelonClear,MelonClear);
|
||||
|
||||
enum ramInfo_ByteType
|
||||
{
|
||||
ramInfo_OneByte = 1,
|
||||
ramInfo_TwoBytes = 2,
|
||||
ramInfo_FourBytes = 4
|
||||
};
|
||||
|
||||
melonDS::u32 GetMainRAMValueU(const melonDS::u32& addr, const ramInfo_ByteType& byteType)
|
||||
{
|
||||
|
||||
melonDS::NDS* nds = CurrentInstance->getNDS();
|
||||
switch (byteType)
|
||||
{
|
||||
case ramInfo_OneByte:
|
||||
return *(melonDS::u8*)(nds->MainRAM + (addr&nds->MainRAMMask));
|
||||
case ramInfo_TwoBytes:
|
||||
return *(melonDS::u16*)(nds->MainRAM + (addr&nds->MainRAMMask));
|
||||
case ramInfo_FourBytes:
|
||||
return *(melonDS::u32*)(nds->MainRAM + (addr&nds->MainRAMMask));
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
melonDS::s32 GetMainRAMValueS(const melonDS::u32& addr, const ramInfo_ByteType& byteType)
|
||||
{
|
||||
melonDS::NDS* nds = CurrentInstance->getNDS();
|
||||
switch (byteType)
|
||||
{
|
||||
case ramInfo_OneByte:
|
||||
return *(melonDS::s8*)(nds->MainRAM + (addr&nds->MainRAMMask));
|
||||
case ramInfo_TwoBytes:
|
||||
return *(melonDS::s16*)(nds->MainRAM + (addr&nds->MainRAMMask));
|
||||
case ramInfo_FourBytes:
|
||||
return *(melonDS::s32*)(nds->MainRAM + (addr&nds->MainRAMMask));
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Lua_ReadDatau(lua_State* L,ramInfo_ByteType byteType)
|
||||
{
|
||||
melonDS::u32 address = luaL_checkinteger(L,1);
|
||||
melonDS::u32 value = GetMainRAMValueU(address,byteType);
|
||||
lua_pushinteger(L, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Lua_ReadDatas(lua_State* L,ramInfo_ByteType byteType)
|
||||
{
|
||||
melonDS::u32 address = luaL_checkinteger(L,1);
|
||||
melonDS::s32 value = GetMainRAMValueS(address,byteType);
|
||||
lua_pushinteger(L, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Lua_Readu8(lua_State* L)
|
||||
{
|
||||
return Lua_ReadDatau(L,ramInfo_OneByte);
|
||||
}
|
||||
AddLuaFunction(Lua_Readu8,Readu8);
|
||||
|
||||
int Lua_Readu16(lua_State* L)
|
||||
{
|
||||
return Lua_ReadDatau(L,ramInfo_TwoBytes);
|
||||
}
|
||||
AddLuaFunction(Lua_Readu16,Readu16);
|
||||
|
||||
int Lua_Readu32(lua_State* L)
|
||||
{
|
||||
return Lua_ReadDatau(L,ramInfo_FourBytes);
|
||||
}
|
||||
AddLuaFunction(Lua_Readu32,Readu32);
|
||||
|
||||
int Lua_Reads8(lua_State* L)
|
||||
{
|
||||
return Lua_ReadDatas(L,ramInfo_OneByte);
|
||||
}
|
||||
AddLuaFunction(Lua_Reads8,Reads8);
|
||||
|
||||
int Lua_Reads16(lua_State* L)
|
||||
{
|
||||
return Lua_ReadDatas(L,ramInfo_TwoBytes);
|
||||
}
|
||||
AddLuaFunction(Lua_Reads16,Reads16);
|
||||
|
||||
int Lua_Reads32(lua_State* L)
|
||||
{
|
||||
return Lua_ReadDatas(L,ramInfo_FourBytes);
|
||||
}
|
||||
AddLuaFunction(Lua_Reads32,Reads32);
|
||||
|
||||
int Lua_NDSTapDown(lua_State* L)
|
||||
{
|
||||
int x = luaL_checkinteger(L,1);
|
||||
int y = luaL_checkinteger(L,2);
|
||||
//TODO
|
||||
//NDS::TouchScreen(x,y);
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_NDSTapDown,NDSTapDown);
|
||||
|
||||
int Lua_NDSTapUp(lua_State* L)
|
||||
{
|
||||
//TODO
|
||||
//NDS::ReleaseScreen();
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_NDSTapUp,NDSTapUp);
|
||||
|
||||
int Lua_StateSave(lua_State* L)
|
||||
{
|
||||
QString filename = luaL_checkstring(L,1);
|
||||
CurrentThread->onLuaSaveState(filename);
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_StateSave,StateSave);
|
||||
|
||||
int Lua_StateLoad(lua_State* L)
|
||||
{
|
||||
QString filename = luaL_checkstring(L,1);
|
||||
CurrentThread->onLuaLoadState(filename);
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_StateLoad,StateLoad);
|
||||
|
||||
int Lua_getMouse(lua_State* L)
|
||||
{
|
||||
Qt::MouseButtons btns = QGuiApplication::mouseButtons();
|
||||
QPoint pos = CurrentInstance->getMainWindow()->panel->mapFromGlobal(QCursor::pos(QGuiApplication::primaryScreen()));
|
||||
const char* keys[6] = {"Left","Middle","Right","XButton1","XButton2","Wheel"};
|
||||
bool vals[6] =
|
||||
{
|
||||
btns.testFlag(Qt::LeftButton),
|
||||
btns.testFlag(Qt::MiddleButton),
|
||||
btns.testFlag(Qt::RightButton),
|
||||
btns.testFlag(Qt::XButton1),
|
||||
btns.testFlag(Qt::XButton2),
|
||||
false //TODO: add mouse wheel support
|
||||
};
|
||||
lua_createtable(L, 0, 8);
|
||||
lua_pushinteger(L, pos.x());
|
||||
lua_setfield(L, -2, "X");
|
||||
lua_pushinteger(L, pos.y());
|
||||
lua_setfield(L, -2, "Y");
|
||||
for(int i=0;i<6;i++)
|
||||
{
|
||||
lua_pushboolean(L,vals[i]);
|
||||
lua_setfield(L,-2,keys[i]);
|
||||
}
|
||||
return 1;//returns table describing the current pos and state of the mouse
|
||||
}
|
||||
AddLuaFunction(Lua_getMouse,GetMouse);
|
||||
|
||||
/*
|
||||
* Front end lua functions
|
||||
*/
|
||||
//TODO: Lua Colors
|
||||
|
||||
//MakeCanvas(int x,int y,int width,int height,[int target,topScreen=0,bottomScreen=1,OSD(default)>=2)],[bool active = true])
|
||||
int Lua_MakeCanvas(lua_State* L)
|
||||
{
|
||||
int x = luaL_checknumber(L,1);
|
||||
int y = luaL_checknumber(L,2);
|
||||
int w = luaL_checknumber(L,3);
|
||||
int h = luaL_checknumber(L,4);
|
||||
int t = luaL_optinteger(L,5,2);
|
||||
bool a = 0 != luaL_optinteger(L,6,1);
|
||||
|
||||
OverlayCanvas canvas(x,y,w,h,a);
|
||||
switch(t)
|
||||
{
|
||||
case 0:
|
||||
canvas.target=LuaScript::CanvasTarget::TopScreen;
|
||||
break;
|
||||
case 1:
|
||||
canvas.target=LuaScript::CanvasTarget::BottomScreen;
|
||||
break;
|
||||
default:
|
||||
canvas.target=LuaScript::CanvasTarget::OSD;
|
||||
}
|
||||
|
||||
lua_pushinteger(L,LuaOverlays.size());
|
||||
LuaOverlays.push_back(canvas);
|
||||
return 1; //returns index of the new overlay
|
||||
}
|
||||
AddLuaFunction(Lua_MakeCanvas,MakeCanvas);
|
||||
|
||||
int Lua_SetCanvas(lua_State* L) //SetCanvas(int index)
|
||||
{
|
||||
int index = luaL_checknumber(L,1);
|
||||
CurrentCanvas = &LuaOverlays.at(index);
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_SetCanvas,SetCanvas);
|
||||
int Lua_ClearOverlay(lua_State* L)
|
||||
{
|
||||
CurrentCanvas->imageBuffer->fill(0x00000000);
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_ClearOverlay,ClearOverlay);
|
||||
|
||||
int Lua_Flip(lua_State* L)
|
||||
{
|
||||
CurrentCanvas->flip();
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_Flip,Flip);
|
||||
|
||||
//text(int x, int y, string message, [u32 color = 'black'], [int fontsize = 9], [string fontfamily = Franklin Gothic Medium])
|
||||
int Lua_text(lua_State* L)
|
||||
{
|
||||
int x = luaL_checknumber(L,1);
|
||||
int y = luaL_checknumber(L,2);
|
||||
const char* message = luaL_checklstring(L,3,NULL);
|
||||
melonDS::u32 color = luaL_optnumber(L,4,0x00000000);
|
||||
QString FontFamily = luaL_optlstring(L,6,"Franklin Gothic Medium",NULL);
|
||||
int size = luaL_optnumber(L,5,9);
|
||||
QPainter painter(CurrentCanvas->imageBuffer);
|
||||
QFont font(FontFamily,size,0,false);
|
||||
font.setStyleStrategy(QFont::NoAntialias);
|
||||
font.setLetterSpacing(QFont::AbsoluteSpacing,-1);
|
||||
painter.setFont(font);
|
||||
painter.setPen(color);
|
||||
painter.drawText(x,y,message);
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_text,Text);
|
||||
|
||||
int Lua_line(lua_State* L)
|
||||
{
|
||||
int x1 = luaL_checknumber(L,1);
|
||||
int y1 = luaL_checknumber(L,2);
|
||||
int x2 = luaL_checknumber(L,3);
|
||||
int y2 = luaL_checknumber(L,4);
|
||||
melonDS::u32 color = luaL_checknumber(L,5);
|
||||
QPainter painter(CurrentCanvas->imageBuffer);
|
||||
painter.setPen(color);
|
||||
painter.drawLine(x1,y1,x2,y2);
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_line,Line);
|
||||
|
||||
int Lua_rect(lua_State* L)
|
||||
{
|
||||
melonDS::u32 color = luaL_checknumber(L,5);
|
||||
int x = luaL_checknumber(L,1);
|
||||
int y = luaL_checknumber(L,2);
|
||||
int width = luaL_checknumber(L,3);
|
||||
int height = luaL_checknumber(L,4);
|
||||
QPainter painter(CurrentCanvas->imageBuffer);
|
||||
painter.setPen(color);
|
||||
painter.drawRect(x,y,width,height);
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_rect,Rect);
|
||||
|
||||
int Lua_fillrect(lua_State* L)
|
||||
{
|
||||
melonDS::u32 color = luaL_checknumber(L,5);
|
||||
int x = luaL_checknumber(L,1);
|
||||
int y = luaL_checknumber(L,2);
|
||||
int width = luaL_checknumber(L,3);
|
||||
int height = luaL_checknumber(L,4);
|
||||
QPainter painter(CurrentCanvas->imageBuffer);
|
||||
painter.setPen(color);
|
||||
painter.fillRect(x,y,width,height,color);
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_fillrect,FillRect);
|
||||
|
||||
int Lua_keystrokes(lua_State* L)
|
||||
{
|
||||
lua_createtable(L,0,CurrentInstance->keyStrokes.size());
|
||||
for (int i = 0; i<CurrentInstance->keyStrokes.size(); i++)
|
||||
{
|
||||
lua_pushinteger(L,CurrentInstance->keyStrokes.at(i));
|
||||
lua_seti(L,-2,i);
|
||||
}
|
||||
CurrentInstance->keyStrokes.clear();
|
||||
lua_createtable(L,0,1);
|
||||
return 1;
|
||||
}
|
||||
AddLuaFunction(Lua_keystrokes,Keys);
|
||||
|
||||
//DrawImage(string path, int x, int y,[int source x=0], [int source y=0], [int source w=-1],[int source h=-1])
|
||||
int Lua_drawImage(lua_State* L)
|
||||
{
|
||||
QString path = luaL_checklstring(L,1,NULL);
|
||||
int x = luaL_checkinteger(L,2);
|
||||
int y = luaL_checkinteger(L,3);
|
||||
int sx = luaL_optinteger(L,4,0);
|
||||
int sy = luaL_optinteger(L,5,0);
|
||||
int sw = luaL_optinteger(L,6,-1);
|
||||
int sh = luaL_optinteger(L,7,-1);
|
||||
QPainter painter(CurrentCanvas->imageBuffer);
|
||||
QImage image;
|
||||
if(ImageHash.contains(path))
|
||||
{
|
||||
image=ImageHash[path];
|
||||
}
|
||||
else
|
||||
{
|
||||
image=QImage(path);
|
||||
ImageHash[path] = image;
|
||||
}
|
||||
painter.drawImage(x,y,image,sx,sy,sw,sh);
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_drawImage,DrawImage);
|
||||
|
||||
int Lua_clearImageHash(lua_State* L)
|
||||
{
|
||||
ImageHash.clear();
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_clearImageHash,ClearHash);
|
||||
|
||||
int Lua_getJoy(lua_State* L)
|
||||
{
|
||||
//TODO:
|
||||
melonDS::u32 buttonMask=CurrentInstance->getInputMask();//current button state.
|
||||
const char* keys[12] =
|
||||
{//Buttons in order of mask.
|
||||
"A","B","Select","Start",
|
||||
"Right","Left","Up","Down",
|
||||
"R","L","X","Y"
|
||||
};
|
||||
lua_createtable(L, 0, 12);
|
||||
for(melonDS::u32 i=0;i<12;i++)
|
||||
{
|
||||
lua_pushboolean(L,0 >= (buttonMask&(1<<i)));
|
||||
lua_setfield(L,-2,keys[i]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
AddLuaFunction(Lua_getJoy,GetJoy);
|
||||
|
||||
/*
|
||||
int Lua_setPadding(lua_State* L) //TODO: Currently only works well with force integer scaling
|
||||
{
|
||||
LeftPadding = abs(luaL_checkinteger(L,1));
|
||||
TopPadding = abs(luaL_checkinteger(L,2));
|
||||
RightPadding = abs(luaL_checkinteger(L,3));
|
||||
BottomPadding = abs(luaL_checkinteger(L,4));
|
||||
CurrentThread->onLuaLayoutChange();
|
||||
return 0;
|
||||
}
|
||||
AddLuaFunction(Lua_setPadding,SetPadding);
|
||||
*/
|
||||
|
||||
|
||||
}//LuaFunctionDefinition
|
||||
}//LuaScript
|
|
@ -0,0 +1,95 @@
|
|||
#ifndef LUASCRIPT_H
|
||||
#define LUASCRIPT_H
|
||||
#include <QDialog>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QFileInfo>
|
||||
#include <lua.hpp>
|
||||
#include "Window.h"
|
||||
|
||||
namespace LuaScript
|
||||
{
|
||||
class LuaConsole: public QPlainTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LuaConsole(QWidget* parent=nullptr);
|
||||
public slots:
|
||||
void onGetText(const QString& string);
|
||||
void onClear();
|
||||
};
|
||||
|
||||
class LuaConsoleDialog: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LuaConsoleDialog(QWidget* parent);
|
||||
LuaConsole* console;
|
||||
QFileInfo currentScript;
|
||||
QPushButton* buttonOpenScript;
|
||||
QPushButton* buttonStartStop;
|
||||
QPushButton* buttonPausePlay;
|
||||
QScrollBar* bar;
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
MainWindow* mainWindow;
|
||||
signals:
|
||||
void signalNewLua();
|
||||
void signalClosing();
|
||||
public slots:
|
||||
//void onStartStop();
|
||||
void onOpenScript();
|
||||
void onStop();
|
||||
void onPausePlay();
|
||||
};
|
||||
|
||||
//Based on ScreenLayout::GetScreenTransforms
|
||||
enum CanvasTarget
|
||||
{
|
||||
TopScreen = 0,
|
||||
BottomScreen = 1,
|
||||
OSD = 2 //Used for drawing to OSD / non-screen target
|
||||
};
|
||||
|
||||
struct OverlayCanvas
|
||||
{
|
||||
QImage* imageBuffer; // buffer edited by luascript
|
||||
QImage* displayBuffer; //buffer displayed on screen
|
||||
QImage* buffer1;
|
||||
QImage* buffer2;
|
||||
QRect rectangle;
|
||||
CanvasTarget target = OSD;
|
||||
bool isActive = true; // only active overlays are drawn
|
||||
unsigned int GLTexture; // used by GL rendering
|
||||
bool GLTextureLoaded;
|
||||
OverlayCanvas(int x,int y,int w, int h, bool active);
|
||||
void flip();//used to swap buffers
|
||||
bool flipped; //used to signal update to graphics.
|
||||
};
|
||||
void luaResetOSD();
|
||||
void luaUpdate();
|
||||
void luaPrint(QString string);
|
||||
void luaClearConsole();
|
||||
void luaHookFunction(lua_State*,lua_Debug*);
|
||||
extern QWidget* panel;
|
||||
extern lua_State* MainLuaState;
|
||||
extern bool FlagPause;
|
||||
extern bool FlagStop;
|
||||
extern bool FlagNewLua;
|
||||
typedef int(*luaFunctionPointer)(lua_State*);
|
||||
struct LuaFunction
|
||||
{
|
||||
luaFunctionPointer cfunction;
|
||||
const char* name;
|
||||
LuaFunction(luaFunctionPointer,const char*,std::vector<LuaFunction*>*);
|
||||
};
|
||||
extern LuaConsoleDialog* LuaDialog;
|
||||
void createLuaState();
|
||||
extern std::vector<OverlayCanvas> LuaOverlays;
|
||||
extern OverlayCanvas* CurrentCanvas;
|
||||
extern QHash<QString, QImage> ImageHash;
|
||||
extern int RightPadding;
|
||||
extern int BottomPadding;
|
||||
extern int TopPadding;
|
||||
extern int LeftPadding;
|
||||
}
|
||||
#endif
|
|
@ -63,4 +63,46 @@ void main()
|
|||
}
|
||||
)";
|
||||
|
||||
//Fragment Shader for overlay copied from melonPrimeDS project.
|
||||
const char* kScreenFS_overlay = R"(#version 140
|
||||
|
||||
uniform sampler2D OverlayTex;
|
||||
|
||||
smooth in vec2 fTexcoord;
|
||||
|
||||
uniform vec2 uOverlayPos;
|
||||
uniform vec2 uOverlaySize;
|
||||
uniform int uOverlayScreenType;
|
||||
|
||||
out vec4 oColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
const vec2 dsSize = vec2(256.0, 193.0); // +1 on y for pixel gap
|
||||
|
||||
vec2 uv = fTexcoord * vec2(1.0, 2.0);
|
||||
|
||||
if (uOverlayScreenType < 1) {
|
||||
// top screen
|
||||
uv -= uOverlayPos / dsSize;
|
||||
uv *= dsSize / uOverlaySize;
|
||||
} else {
|
||||
// bottom screen
|
||||
uv -= vec2(0.0, 1.0);
|
||||
uv -= (uOverlayPos + vec2(0.0, 1.0)) / dsSize;
|
||||
uv *= dsSize / uOverlaySize;
|
||||
}
|
||||
|
||||
vec4 pixel = texture(OverlayTex, uv);
|
||||
pixel.rgb *= pixel.a;
|
||||
|
||||
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
|
||||
oColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
} else {
|
||||
oColor = pixel.bgra;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
|
||||
#endif // OSD_SHADERS_H
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include "main_shaders.h"
|
||||
#include "OSD_shaders.h"
|
||||
#include "font.h"
|
||||
#include "LuaMain.h"
|
||||
|
||||
|
||||
using namespace melonDS;
|
||||
|
||||
|
@ -667,13 +669,29 @@ void ScreenPanelNative::setupScreenLayout()
|
|||
}
|
||||
}
|
||||
|
||||
// From ScreenLayout::GetScreenTransforms
|
||||
// TopScreen = 0
|
||||
// BottomScreen = 1
|
||||
// OSD / non-screen target = 2 (used by LuaScript stuff)
|
||||
void ScreenPanelNative::drawOverlays(QPainter* painter,int type)
|
||||
{
|
||||
for (auto lo = LuaScript::LuaOverlays.begin(); lo != LuaScript::LuaOverlays.end();)
|
||||
{
|
||||
LuaScript::OverlayCanvas& overlay = *lo;
|
||||
if ((overlay.target == type) && overlay.isActive)
|
||||
painter->drawImage(overlay.rectangle,*overlay.displayBuffer);
|
||||
lo++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ScreenPanelNative::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
||||
// fill background
|
||||
painter.fillRect(event->rect(), QColor::fromRgb(0, 0, 0));
|
||||
|
||||
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
auto emuThread = emuInstance->getEmuThread();
|
||||
|
||||
if (emuThread->emuIsActive())
|
||||
|
@ -693,12 +711,15 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event)
|
|||
memcpy(screen[1].scanLine(0), nds->GPU.Framebuffer[frontbuf][1].get(), 256 * 192 * 4);
|
||||
emuThread->FrontBufferLock.unlock();
|
||||
|
||||
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
QRect screenrc(0, 0, 256, 192);
|
||||
|
||||
for (int i = 0; i < numScreens; i++)
|
||||
{
|
||||
painter.setTransform(screenTrans[i]);
|
||||
painter.drawImage(screenrc, screen[screenKind[i]]);
|
||||
if (osdEnabled)
|
||||
drawOverlays(&painter,screenKind[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -711,6 +732,8 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event)
|
|||
|
||||
painter.resetTransform();
|
||||
|
||||
drawOverlays(&painter,LuaScript::CanvasTarget::OSD);
|
||||
|
||||
for (auto it = osdItems.begin(); it != osdItems.end(); )
|
||||
{
|
||||
OSDItem& item = *it;
|
||||
|
@ -877,6 +900,21 @@ void ScreenPanelGL::initOpenGL()
|
|||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0));
|
||||
|
||||
transferLayout();
|
||||
//TODO: Lookinto seeing if we can just re-use screen shader for this...
|
||||
OpenGL::CompileVertexFragmentProgram(overlayShader,
|
||||
kScreenVS,kScreenFS_overlay,
|
||||
"OverlayShader",
|
||||
{{"vPosition", 0}, {"vTexcoord", 1}},
|
||||
{{"oColor", 0}});
|
||||
|
||||
glUseProgram(overlayShader);
|
||||
|
||||
overlayScreenSizeULoc = glGetUniformLocation(overlayShader, "uScreenSize");
|
||||
overlayTransformULoc = glGetUniformLocation(overlayShader, "uTransform");
|
||||
|
||||
overlayPosULoc = glGetUniformLocation(overlayShader, "uOverlayPos");
|
||||
overlaySizeULoc = glGetUniformLocation(overlayShader, "uOverlaySize");
|
||||
overlayScreenTypeULoc = glGetUniformLocation(overlayShader, "uOverlayScreenType");
|
||||
}
|
||||
|
||||
void ScreenPanelGL::deinitOpenGL()
|
||||
|
@ -902,6 +940,16 @@ void ScreenPanelGL::deinitOpenGL()
|
|||
|
||||
glDeleteProgram(osdShader);
|
||||
|
||||
glDeleteProgram(overlayShader);
|
||||
for (auto lo = LuaScript::LuaOverlays.begin(); lo != LuaScript::LuaOverlays.end();)
|
||||
{
|
||||
LuaScript::OverlayCanvas& overlay = *lo;
|
||||
lo++;
|
||||
if (!overlay.GLTextureLoaded)
|
||||
continue;
|
||||
glDeleteTextures(1,&overlay.GLTexture);
|
||||
overlay.GLTextureLoaded=false;
|
||||
}
|
||||
|
||||
glContext->DoneCurrent();
|
||||
|
||||
|
@ -943,6 +991,51 @@ void ScreenPanelGL::osdDeleteItem(OSDItem* item)
|
|||
ScreenPanel::osdDeleteItem(item);
|
||||
}
|
||||
|
||||
void ScreenPanelGL::drawOverlays(int type,int screen)
|
||||
{
|
||||
for (auto lo = LuaScript::LuaOverlays.begin(); lo != LuaScript::LuaOverlays.end();)
|
||||
{
|
||||
LuaScript::OverlayCanvas& overlay = *lo;
|
||||
lo++;
|
||||
if (!overlay.isActive || overlay.target != type)
|
||||
continue;
|
||||
if (!overlay.GLTextureLoaded)//Load texture if none loaded
|
||||
{
|
||||
glGenTextures(1,&overlay.GLTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, overlay.GLTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, overlay.rectangle.width(), overlay.rectangle.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, overlay.displayBuffer->bits());
|
||||
overlay.GLTextureLoaded = true;
|
||||
}
|
||||
if (overlay.flipped) //Only update texture if needed
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, overlay.GLTexture);
|
||||
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,overlay.rectangle.width(),overlay.rectangle.height(),GL_RGBA,GL_UNSIGNED_BYTE,overlay.displayBuffer->bits());
|
||||
overlay.flipped = false;
|
||||
}
|
||||
if(type == LuaScript::CanvasTarget::OSD) // OSD gets drawn differently then top or bottom screen target
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, overlay.GLTexture);
|
||||
glUniform2i(osdPosULoc,overlay.rectangle.left(),overlay.rectangle.top());
|
||||
glUniform2i(osdSizeULoc,overlay.rectangle.width(),overlay.rectangle.height());
|
||||
glDrawArrays(GL_TRIANGLES, 0, 2*3);
|
||||
continue;
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, overlay.GLTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glUniform2f(overlayPosULoc,overlay.rectangle.left(),overlay.rectangle.top());
|
||||
glUniform2f(overlaySizeULoc,overlay.rectangle.width(),overlay.rectangle.height());
|
||||
glUniform1i(overlayScreenTypeULoc, type);
|
||||
glUniformMatrix2x3fv(overlayTransformULoc, 1, GL_TRUE,screenMatrix[screen]);
|
||||
glDrawArrays(GL_TRIANGLES,type == 0 ? 0 : 2*3, 2*3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ScreenPanelGL::drawScreenGL()
|
||||
{
|
||||
if (!glContext) return;
|
||||
|
@ -1015,6 +1108,29 @@ void ScreenPanelGL::drawScreenGL()
|
|||
osdUpdate();
|
||||
if (osdEnabled)
|
||||
{
|
||||
|
||||
glUseProgram(overlayShader);
|
||||
|
||||
//Need to blend this layer onto the screen layer!
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glUniform2f(overlayScreenSizeULoc, w / factor, h / factor);
|
||||
|
||||
screenSettingsLock.lock();
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer);
|
||||
glBindVertexArray(screenVertexArray);
|
||||
|
||||
for(int i = 0;i<numScreens;i++){
|
||||
drawOverlays(screenKind[i],i);
|
||||
}
|
||||
|
||||
|
||||
screenSettingsLock.unlock();
|
||||
|
||||
|
||||
|
||||
osdMutex.lock();
|
||||
|
||||
u32 y = kOSDMargin;
|
||||
|
@ -1032,6 +1148,8 @@ void ScreenPanelGL::drawScreenGL()
|
|||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
drawOverlays(LuaScript::CanvasTarget::OSD,0);
|
||||
|
||||
for (auto it = osdItems.begin(); it != osdItems.end(); )
|
||||
{
|
||||
OSDItem& item = *it;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <QScreen>
|
||||
#include <QCloseEvent>
|
||||
#include <QTimer>
|
||||
#include <QPainter>
|
||||
|
||||
#include "glad/glad.h"
|
||||
#include "ScreenLayout.h"
|
||||
|
@ -157,6 +158,7 @@ protected:
|
|||
|
||||
private:
|
||||
void setupScreenLayout() override;
|
||||
void drawOverlays(QPainter* painter,int type);
|
||||
|
||||
QImage screen[2];
|
||||
QTransform screenTrans[kMaxScreenTransforms];
|
||||
|
@ -195,6 +197,7 @@ protected:
|
|||
|
||||
private:
|
||||
void setupScreenLayout() override;
|
||||
void drawOverlays(int type,int screen);
|
||||
|
||||
std::unique_ptr<GL::Context> glContext;
|
||||
|
||||
|
@ -217,6 +220,11 @@ private:
|
|||
|
||||
void osdRenderItem(OSDItem* item) override;
|
||||
void osdDeleteItem(OSDItem* item) override;
|
||||
|
||||
GLuint overlayShader;
|
||||
GLuint overlayScreenSizeULoc, overlayTransformULoc;
|
||||
GLuint overlayPosULoc, overlaySizeULoc, overlayScreenTypeULoc;
|
||||
|
||||
};
|
||||
|
||||
#endif // SCREEN_H
|
||||
|
|
|
@ -82,6 +82,8 @@
|
|||
#include "ArchiveUtil.h"
|
||||
#include "CameraManager.h"
|
||||
|
||||
#include "LuaMain.h"
|
||||
|
||||
using namespace melonDS;
|
||||
|
||||
|
||||
|
@ -403,6 +405,12 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) :
|
|||
actDateTime = menu->addAction("Date and time");
|
||||
connect(actDateTime, &QAction::triggered, this, &MainWindow::onOpenDateTime);
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
actLuaScript = menu->addAction("Lua Script");
|
||||
connect(actLuaScript,&QAction::triggered,this,&MainWindow::onOpenLuaScript);
|
||||
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
actEnableCheats = menu->addAction("Enable cheats");
|
||||
|
@ -1449,6 +1457,13 @@ void MainWindow::onEjectGBACart()
|
|||
updateCartInserted(true);
|
||||
}
|
||||
|
||||
void MainWindow::onLuaSaveState(const QString& filename)
|
||||
{
|
||||
emuThread->emuPause();
|
||||
emuInstance->saveState(filename.toStdString());
|
||||
emuThread->emuUnpause();
|
||||
}
|
||||
|
||||
void MainWindow::onSaveState()
|
||||
{
|
||||
int slot = ((QAction*)sender())->data().toInt();
|
||||
|
@ -1491,6 +1506,13 @@ void MainWindow::onSaveState()
|
|||
emuThread->emuUnpause();
|
||||
}
|
||||
|
||||
void MainWindow::onLuaLoadState(const QString& filename)
|
||||
{
|
||||
emuThread->emuPause();
|
||||
emuInstance->loadState(filename.toStdString());
|
||||
emuThread->emuUnpause();
|
||||
}
|
||||
|
||||
void MainWindow::onLoadState()
|
||||
{
|
||||
int slot = ((QAction*)sender())->data().toInt();
|
||||
|
@ -1657,6 +1679,16 @@ void MainWindow::onOpenPowerManagement()
|
|||
PowerManagementDialog* dlg = PowerManagementDialog::openDlg(this);
|
||||
}
|
||||
|
||||
void MainWindow::onOpenLuaScript()
|
||||
{
|
||||
if (LuaScript::LuaDialog) // only one at a time.
|
||||
return;
|
||||
LuaScript::LuaDialog = new LuaScript::LuaConsoleDialog(this);
|
||||
LuaScript::LuaDialog->show();
|
||||
//connect(emuThread,&EmuThread::signalLuaSaveState,mainWindow,&MainWindow::onLuaSaveState);
|
||||
//connect(emuThread,&EmuThread::signalLuaLoadState,mainWindow,&MainWindow::onLuaLoadState);
|
||||
}
|
||||
|
||||
void MainWindow::onEnableCheats(bool checked)
|
||||
{
|
||||
localCfg.SetBool("EnableCheats", checked);
|
||||
|
|
|
@ -152,7 +152,9 @@ private slots:
|
|||
void onInsertGBACart();
|
||||
void onInsertGBAAddon();
|
||||
void onEjectGBACart();
|
||||
void onLuaSaveState(const QString& filename);
|
||||
void onSaveState();
|
||||
void onLuaLoadState(const QString& filename);
|
||||
void onLoadState();
|
||||
void onUndoStateLoad();
|
||||
void onImportSavefile();
|
||||
|
@ -163,6 +165,7 @@ private slots:
|
|||
void onStop();
|
||||
void onFrameStep();
|
||||
void onOpenPowerManagement();
|
||||
void onOpenLuaScript();
|
||||
void onOpenDateTime();
|
||||
void onEnableCheats(bool checked);
|
||||
void onSetupCheats();
|
||||
|
@ -300,6 +303,7 @@ public:
|
|||
#ifdef __APPLE__
|
||||
QAction* actPreferences;
|
||||
#endif
|
||||
QAction* actLuaScript;
|
||||
QAction* actInputConfig;
|
||||
QAction* actVideoSettings;
|
||||
QAction* actCameraSettings;
|
||||
|
|
Loading…
Reference in New Issue