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*/
|
build*/
|
||||||
|
debug*/
|
||||||
bin
|
bin
|
||||||
obj
|
obj
|
||||||
*.depend
|
*.depend
|
||||||
|
|
|
@ -54,6 +54,8 @@ set(SOURCES_QT_SDL
|
||||||
|
|
||||||
LANDialog.cpp
|
LANDialog.cpp
|
||||||
NetplayDialog.cpp
|
NetplayDialog.cpp
|
||||||
|
|
||||||
|
LuaMain.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
@ -84,6 +86,7 @@ endif()
|
||||||
pkg_check_modules(SDL2 REQUIRED IMPORTED_TARGET sdl2)
|
pkg_check_modules(SDL2 REQUIRED IMPORTED_TARGET sdl2)
|
||||||
pkg_check_modules(LibArchive REQUIRED IMPORTED_TARGET libarchive)
|
pkg_check_modules(LibArchive REQUIRED IMPORTED_TARGET libarchive)
|
||||||
pkg_check_modules(Zstd REQUIRED IMPORTED_TARGET libzstd)
|
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)
|
fix_interface_includes(PkgConfig::SDL2 PkgConfig::LibArchive)
|
||||||
|
|
||||||
|
@ -178,7 +181,7 @@ else()
|
||||||
target_include_directories(melonDS PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
target_include_directories(melonDS PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(melonDS PRIVATE core)
|
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})
|
target_link_libraries(melonDS PRIVATE ${QT_LINK_LIBS} ${CMAKE_DL_LIBS})
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
|
|
@ -136,6 +136,7 @@ public:
|
||||||
int getJoystickID() { return joystickID; }
|
int getJoystickID() { return joystickID; }
|
||||||
SDL_Joystick* getJoystick() { return joystick; }
|
SDL_Joystick* getJoystick() { return joystick; }
|
||||||
|
|
||||||
|
std::vector<int> keyStrokes;
|
||||||
private:
|
private:
|
||||||
static int lastSep(const std::string& path);
|
static int lastSep(const std::string& path);
|
||||||
std::string getAssetPath(bool gba, const std::string& configpath, const std::string& ext, const std::string& file);
|
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 audioCallback(void* data, Uint8* stream, int len);
|
||||||
static void micCallback(void* data, Uint8* stream, int len);
|
static void micCallback(void* data, Uint8* stream, int len);
|
||||||
|
|
||||||
|
|
||||||
void onKeyPress(QKeyEvent* event);
|
void onKeyPress(QKeyEvent* event);
|
||||||
void onKeyRelease(QKeyEvent* event);
|
void onKeyRelease(QKeyEvent* event);
|
||||||
void keyReleaseAll();
|
void keyReleaseAll();
|
||||||
|
@ -254,6 +256,8 @@ public:
|
||||||
bool doLimitFPS;
|
bool doLimitFPS;
|
||||||
int maxFPS;
|
int maxFPS;
|
||||||
bool doAudioSync;
|
bool doAudioSync;
|
||||||
|
|
||||||
|
melonDS::u32 getInputMask(){return inputMask;}
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::unique_ptr<melonDS::Savestate> backupState;
|
std::unique_ptr<melonDS::Savestate> backupState;
|
||||||
|
|
|
@ -220,6 +220,7 @@ void EmuInstance::onKeyPress(QKeyEvent* event)
|
||||||
{
|
{
|
||||||
int keyHK = getEventKeyVal(event);
|
int keyHK = getEventKeyVal(event);
|
||||||
int keyKP = keyHK;
|
int keyKP = keyHK;
|
||||||
|
keyStrokes.push_back(keyHK);
|
||||||
if (event->modifiers() != Qt::KeypadModifier)
|
if (event->modifiers() != Qt::KeypadModifier)
|
||||||
keyKP &= ~event->modifiers();
|
keyKP &= ~event->modifiers();
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,8 @@
|
||||||
|
|
||||||
#include "EmuInstance.h"
|
#include "EmuInstance.h"
|
||||||
|
|
||||||
|
#include "LuaMain.h"
|
||||||
|
|
||||||
using namespace melonDS;
|
using namespace melonDS;
|
||||||
|
|
||||||
|
|
||||||
|
@ -439,6 +441,11 @@ void EmuThread::run()
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMessages();
|
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);
|
file = Platform::OpenLocalFile("rtc.bin", Platform::FileMode::Write);
|
||||||
|
|
|
@ -107,6 +107,12 @@ public:
|
||||||
void deinitContext();
|
void deinitContext();
|
||||||
void updateVideoSettings() { videoSettingsDirty = true; }
|
void updateVideoSettings() { videoSettingsDirty = true; }
|
||||||
|
|
||||||
|
void onLuaPrint(const QString&);
|
||||||
|
void onLuaClearConsole();
|
||||||
|
void onLuaLoadState(const QString&);
|
||||||
|
void onLuaSaveState(const QString&);
|
||||||
|
void onLuaLayoutChange();
|
||||||
|
|
||||||
int FrontBuffer = 0;
|
int FrontBuffer = 0;
|
||||||
QMutex FrontBufferLock;
|
QMutex FrontBufferLock;
|
||||||
|
|
||||||
|
@ -130,6 +136,11 @@ signals:
|
||||||
|
|
||||||
void syncVolumeLevel();
|
void syncVolumeLevel();
|
||||||
|
|
||||||
|
void signalLuaPrint(const QString&);
|
||||||
|
void signalLuaClearConsole();
|
||||||
|
void signalLuaSaveState(const QString&);
|
||||||
|
void signalLuaLoadState(const QString&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleMessages();
|
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
|
#endif // OSD_SHADERS_H
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
#include "main_shaders.h"
|
#include "main_shaders.h"
|
||||||
#include "OSD_shaders.h"
|
#include "OSD_shaders.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
#include "LuaMain.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace melonDS;
|
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)
|
void ScreenPanelNative::paintEvent(QPaintEvent* event)
|
||||||
{
|
{
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
|
|
||||||
// fill background
|
// fill background
|
||||||
painter.fillRect(event->rect(), QColor::fromRgb(0, 0, 0));
|
painter.fillRect(event->rect(), QColor::fromRgb(0, 0, 0));
|
||||||
|
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||||
auto emuThread = emuInstance->getEmuThread();
|
auto emuThread = emuInstance->getEmuThread();
|
||||||
|
|
||||||
if (emuThread->emuIsActive())
|
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);
|
memcpy(screen[1].scanLine(0), nds->GPU.Framebuffer[frontbuf][1].get(), 256 * 192 * 4);
|
||||||
emuThread->FrontBufferLock.unlock();
|
emuThread->FrontBufferLock.unlock();
|
||||||
|
|
||||||
|
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||||
QRect screenrc(0, 0, 256, 192);
|
QRect screenrc(0, 0, 256, 192);
|
||||||
|
|
||||||
for (int i = 0; i < numScreens; i++)
|
for (int i = 0; i < numScreens; i++)
|
||||||
{
|
{
|
||||||
painter.setTransform(screenTrans[i]);
|
painter.setTransform(screenTrans[i]);
|
||||||
painter.drawImage(screenrc, screen[screenKind[i]]);
|
painter.drawImage(screenrc, screen[screenKind[i]]);
|
||||||
|
if (osdEnabled)
|
||||||
|
drawOverlays(&painter,screenKind[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,6 +732,8 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event)
|
||||||
|
|
||||||
painter.resetTransform();
|
painter.resetTransform();
|
||||||
|
|
||||||
|
drawOverlays(&painter,LuaScript::CanvasTarget::OSD);
|
||||||
|
|
||||||
for (auto it = osdItems.begin(); it != osdItems.end(); )
|
for (auto it = osdItems.begin(); it != osdItems.end(); )
|
||||||
{
|
{
|
||||||
OSDItem& item = *it;
|
OSDItem& item = *it;
|
||||||
|
@ -877,6 +900,21 @@ void ScreenPanelGL::initOpenGL()
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0));
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0));
|
||||||
|
|
||||||
transferLayout();
|
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()
|
void ScreenPanelGL::deinitOpenGL()
|
||||||
|
@ -902,6 +940,16 @@ void ScreenPanelGL::deinitOpenGL()
|
||||||
|
|
||||||
glDeleteProgram(osdShader);
|
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();
|
glContext->DoneCurrent();
|
||||||
|
|
||||||
|
@ -943,6 +991,51 @@ void ScreenPanelGL::osdDeleteItem(OSDItem* item)
|
||||||
ScreenPanel::osdDeleteItem(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()
|
void ScreenPanelGL::drawScreenGL()
|
||||||
{
|
{
|
||||||
if (!glContext) return;
|
if (!glContext) return;
|
||||||
|
@ -1015,6 +1108,29 @@ void ScreenPanelGL::drawScreenGL()
|
||||||
osdUpdate();
|
osdUpdate();
|
||||||
if (osdEnabled)
|
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();
|
osdMutex.lock();
|
||||||
|
|
||||||
u32 y = kOSDMargin;
|
u32 y = kOSDMargin;
|
||||||
|
@ -1032,6 +1148,8 @@ void ScreenPanelGL::drawScreenGL()
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
drawOverlays(LuaScript::CanvasTarget::OSD,0);
|
||||||
|
|
||||||
for (auto it = osdItems.begin(); it != osdItems.end(); )
|
for (auto it = osdItems.begin(); it != osdItems.end(); )
|
||||||
{
|
{
|
||||||
OSDItem& item = *it;
|
OSDItem& item = *it;
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
#include "glad/glad.h"
|
#include "glad/glad.h"
|
||||||
#include "ScreenLayout.h"
|
#include "ScreenLayout.h"
|
||||||
|
@ -157,6 +158,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupScreenLayout() override;
|
void setupScreenLayout() override;
|
||||||
|
void drawOverlays(QPainter* painter,int type);
|
||||||
|
|
||||||
QImage screen[2];
|
QImage screen[2];
|
||||||
QTransform screenTrans[kMaxScreenTransforms];
|
QTransform screenTrans[kMaxScreenTransforms];
|
||||||
|
@ -195,6 +197,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupScreenLayout() override;
|
void setupScreenLayout() override;
|
||||||
|
void drawOverlays(int type,int screen);
|
||||||
|
|
||||||
std::unique_ptr<GL::Context> glContext;
|
std::unique_ptr<GL::Context> glContext;
|
||||||
|
|
||||||
|
@ -217,6 +220,11 @@ private:
|
||||||
|
|
||||||
void osdRenderItem(OSDItem* item) override;
|
void osdRenderItem(OSDItem* item) override;
|
||||||
void osdDeleteItem(OSDItem* item) override;
|
void osdDeleteItem(OSDItem* item) override;
|
||||||
|
|
||||||
|
GLuint overlayShader;
|
||||||
|
GLuint overlayScreenSizeULoc, overlayTransformULoc;
|
||||||
|
GLuint overlayPosULoc, overlaySizeULoc, overlayScreenTypeULoc;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SCREEN_H
|
#endif // SCREEN_H
|
||||||
|
|
|
@ -82,6 +82,8 @@
|
||||||
#include "ArchiveUtil.h"
|
#include "ArchiveUtil.h"
|
||||||
#include "CameraManager.h"
|
#include "CameraManager.h"
|
||||||
|
|
||||||
|
#include "LuaMain.h"
|
||||||
|
|
||||||
using namespace melonDS;
|
using namespace melonDS;
|
||||||
|
|
||||||
|
|
||||||
|
@ -403,6 +405,12 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) :
|
||||||
actDateTime = menu->addAction("Date and time");
|
actDateTime = menu->addAction("Date and time");
|
||||||
connect(actDateTime, &QAction::triggered, this, &MainWindow::onOpenDateTime);
|
connect(actDateTime, &QAction::triggered, this, &MainWindow::onOpenDateTime);
|
||||||
|
|
||||||
|
menu->addSeparator();
|
||||||
|
|
||||||
|
actLuaScript = menu->addAction("Lua Script");
|
||||||
|
connect(actLuaScript,&QAction::triggered,this,&MainWindow::onOpenLuaScript);
|
||||||
|
|
||||||
|
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
|
|
||||||
actEnableCheats = menu->addAction("Enable cheats");
|
actEnableCheats = menu->addAction("Enable cheats");
|
||||||
|
@ -1449,6 +1457,13 @@ void MainWindow::onEjectGBACart()
|
||||||
updateCartInserted(true);
|
updateCartInserted(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::onLuaSaveState(const QString& filename)
|
||||||
|
{
|
||||||
|
emuThread->emuPause();
|
||||||
|
emuInstance->saveState(filename.toStdString());
|
||||||
|
emuThread->emuUnpause();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::onSaveState()
|
void MainWindow::onSaveState()
|
||||||
{
|
{
|
||||||
int slot = ((QAction*)sender())->data().toInt();
|
int slot = ((QAction*)sender())->data().toInt();
|
||||||
|
@ -1491,6 +1506,13 @@ void MainWindow::onSaveState()
|
||||||
emuThread->emuUnpause();
|
emuThread->emuUnpause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::onLuaLoadState(const QString& filename)
|
||||||
|
{
|
||||||
|
emuThread->emuPause();
|
||||||
|
emuInstance->loadState(filename.toStdString());
|
||||||
|
emuThread->emuUnpause();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::onLoadState()
|
void MainWindow::onLoadState()
|
||||||
{
|
{
|
||||||
int slot = ((QAction*)sender())->data().toInt();
|
int slot = ((QAction*)sender())->data().toInt();
|
||||||
|
@ -1657,6 +1679,16 @@ void MainWindow::onOpenPowerManagement()
|
||||||
PowerManagementDialog* dlg = PowerManagementDialog::openDlg(this);
|
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)
|
void MainWindow::onEnableCheats(bool checked)
|
||||||
{
|
{
|
||||||
localCfg.SetBool("EnableCheats", checked);
|
localCfg.SetBool("EnableCheats", checked);
|
||||||
|
|
|
@ -152,7 +152,9 @@ private slots:
|
||||||
void onInsertGBACart();
|
void onInsertGBACart();
|
||||||
void onInsertGBAAddon();
|
void onInsertGBAAddon();
|
||||||
void onEjectGBACart();
|
void onEjectGBACart();
|
||||||
|
void onLuaSaveState(const QString& filename);
|
||||||
void onSaveState();
|
void onSaveState();
|
||||||
|
void onLuaLoadState(const QString& filename);
|
||||||
void onLoadState();
|
void onLoadState();
|
||||||
void onUndoStateLoad();
|
void onUndoStateLoad();
|
||||||
void onImportSavefile();
|
void onImportSavefile();
|
||||||
|
@ -163,6 +165,7 @@ private slots:
|
||||||
void onStop();
|
void onStop();
|
||||||
void onFrameStep();
|
void onFrameStep();
|
||||||
void onOpenPowerManagement();
|
void onOpenPowerManagement();
|
||||||
|
void onOpenLuaScript();
|
||||||
void onOpenDateTime();
|
void onOpenDateTime();
|
||||||
void onEnableCheats(bool checked);
|
void onEnableCheats(bool checked);
|
||||||
void onSetupCheats();
|
void onSetupCheats();
|
||||||
|
@ -300,6 +303,7 @@ public:
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
QAction* actPreferences;
|
QAction* actPreferences;
|
||||||
#endif
|
#endif
|
||||||
|
QAction* actLuaScript;
|
||||||
QAction* actInputConfig;
|
QAction* actInputConfig;
|
||||||
QAction* actVideoSettings;
|
QAction* actVideoSettings;
|
||||||
QAction* actCameraSettings;
|
QAction* actCameraSettings;
|
||||||
|
|
Loading…
Reference in New Issue