For Qt GUI, added initial framework for use of the Qt built-in ECMAScript (javascript based) engine. This scripting capability will allow users to load their own custom UI windows (created using Qt Creator tool) in the GUI. This is intended to serve as a the Qt GUI's functional replacement for building GUI elements using IUP in LUA scripts. This is a work in progress.
This commit is contained in:
parent
b53d087fca
commit
3436e221de
|
@ -10,34 +10,80 @@ if (${PUBLIC_RELEASE})
|
|||
endif()
|
||||
|
||||
if ( ${QT6} )
|
||||
message( STATUS "GUI Frontend: Qt6")
|
||||
set( Qt Qt6 )
|
||||
else()
|
||||
message( STATUS "GUI Frontend: Qt5")
|
||||
set( Qt Qt5 )
|
||||
set( QT 6 )
|
||||
endif()
|
||||
|
||||
if ( ${QHELP} )
|
||||
set(QtHelpModule Help)
|
||||
add_definitions( -D_USE_QHELP )
|
||||
if (NOT DEFINED QT)
|
||||
message( STATUS "Attempting to determine Qt Version...")
|
||||
find_package( Qt6 COMPONENTS Core)
|
||||
|
||||
if (${Qt6Core_FOUND})
|
||||
message( STATUS "Found Qt Version: ${Qt6Core_VERSION}")
|
||||
set( QT 6 )
|
||||
else()
|
||||
find_package( Qt5 COMPONENTS Core)
|
||||
|
||||
if (${Qt5Core_FOUND})
|
||||
message( STATUS "Found Qt Version: ${Qt5Core_VERSION}")
|
||||
set( QT 5 )
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if ( ${FCEU_PROFILER_ENABLE} )
|
||||
message( STATUS "FCEU Profiler Enabled")
|
||||
add_definitions( -D__FCEU_PROFILER_ENABLE__ )
|
||||
endif()
|
||||
|
||||
|
||||
if ( ${QT6} )
|
||||
find_package( Qt6 REQUIRED COMPONENTS Widgets OpenGL OpenGLWidgets ${QtHelpModule})
|
||||
add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6Help_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
|
||||
include_directories( ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Help_INCLUDE_DIRS} ${Qt6OpenGLWidgets_INCLUDE_DIRS} )
|
||||
if ( ${QT} EQUAL 6 )
|
||||
message( STATUS "GUI Frontend: Qt6")
|
||||
set( Qt Qt6 )
|
||||
find_package( Qt6 REQUIRED COMPONENTS Widgets OpenGL OpenGLWidgets)
|
||||
find_package( Qt6 COMPONENTS Help QUIET)
|
||||
find_package( Qt6 COMPONENTS Qml)
|
||||
add_definitions( ${Qt6Widgets_DEFINITIONS} ${Qt6Qml_DEFINITIONS} ${Qt6Help_DEFINITIONS} ${Qt6OpenGLWidgets_DEFINITIONS} )
|
||||
include_directories( ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Qml_INCLUDE_DIRS} ${Qt6Help_INCLUDE_DIRS} ${Qt6OpenGLWidgets_INCLUDE_DIRS} )
|
||||
|
||||
if (${Qt6Help_FOUND})
|
||||
message( STATUS "Qt6 Help Module Found")
|
||||
if (${QHELP})
|
||||
add_definitions( -D_USE_QHELP )
|
||||
endif()
|
||||
else()
|
||||
message( STATUS "Qt6 Help Module Not Found")
|
||||
endif()
|
||||
|
||||
if (${Qt6Qml_FOUND})
|
||||
message( STATUS "Qt6 Qml Module Found")
|
||||
#add_definitions( -D__FCEU_QSCRIPT_ENABLE__ )
|
||||
else()
|
||||
message( STATUS "Qt6 Qml Module Not Found")
|
||||
endif()
|
||||
else()
|
||||
find_package( Qt5 REQUIRED COMPONENTS Widgets OpenGL ${QtHelpModule})
|
||||
add_definitions( ${Qt5Widgets_DEFINITIONS} ${Qt5Help_DEFINITIONS} )
|
||||
include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} )
|
||||
endif()
|
||||
message( STATUS "GUI Frontend: Qt5")
|
||||
set( Qt Qt5 )
|
||||
find_package( Qt5 REQUIRED COMPONENTS Widgets OpenGL)
|
||||
find_package( Qt5 COMPONENTS Help QUIET)
|
||||
find_package( Qt5 COMPONENTS Qml)
|
||||
add_definitions( ${Qt5Widgets_DEFINITIONS} ${Qt5Qml_DEFINITIONS} ${Qt5Help_DEFINITIONS} )
|
||||
include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Qml_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} )
|
||||
|
||||
if (${Qt5Help_FOUND})
|
||||
message( STATUS "Qt5 Help Module Found")
|
||||
if (${QHELP})
|
||||
add_definitions( -D_USE_QHELP )
|
||||
endif()
|
||||
else()
|
||||
message( STATUS "Qt5 Help Module Not Found")
|
||||
endif()
|
||||
|
||||
if (${Qt5Qml_FOUND})
|
||||
message( STATUS "Qt5 Qml Module Found")
|
||||
add_definitions( -D__FCEU_QSCRIPT_ENABLE__ )
|
||||
else()
|
||||
message( STATUS "Qt5 Qml Module Not Found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
@ -579,6 +625,7 @@ set(SRC_DRIVERS_SDL
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/ConsoleSoundConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/StateRecorderConf.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/iNesHeaderEditor.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/QtScriptManager.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/SplashScreen.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TraceLogger.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/AboutWindow.cpp
|
||||
|
@ -666,6 +713,7 @@ target_link_libraries( ${APP_NAME}
|
|||
${ASAN_LDFLAGS} ${GPROF_LDFLAGS}
|
||||
${${Qt}Widgets_LIBRARIES}
|
||||
${${Qt}Help_LIBRARIES}
|
||||
${${Qt}Qml_LIBRARIES}
|
||||
${${Qt}OpenGL_LIBRARIES}
|
||||
${${Qt}OpenGLWidgets_LIBRARIES}
|
||||
${OPENGL_LDFLAGS}
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#include "Qt/main.h"
|
||||
#include "Qt/dface.h"
|
||||
#include "Qt/input.h"
|
||||
#include "Qt/throttle.h"
|
||||
#include "Qt/ColorMenu.h"
|
||||
#include "Qt/ConsoleWindow.h"
|
||||
#include "Qt/InputConf.h"
|
||||
|
@ -86,6 +87,7 @@
|
|||
#include "Qt/TimingConf.h"
|
||||
#include "Qt/FrameTimingStats.h"
|
||||
#include "Qt/LuaControl.h"
|
||||
#include "Qt/QtScriptManager.h"
|
||||
#include "Qt/CheatsConf.h"
|
||||
#include "Qt/GameGenie.h"
|
||||
#include "Qt/HexEditor.h"
|
||||
|
@ -270,6 +272,9 @@ consoleWin_t::consoleWin_t(QWidget *parent)
|
|||
// Create AVI Recording Disk Thread
|
||||
aviDiskThread = new AviRecordDiskThread_t(this);
|
||||
|
||||
#ifdef __FCEU_QSCRIPT_ENABLE__
|
||||
QtScriptManager::create(this);
|
||||
#endif
|
||||
scrHandlerConnected = false;
|
||||
}
|
||||
|
||||
|
@ -1079,7 +1084,7 @@ void consoleWin_t::createMainMenu(void)
|
|||
connect( Hotkeys[ HK_SELECT_STATE_NEXT ].getShortcut(), SIGNAL(activated()), this, SLOT(incrementState(void)) );
|
||||
|
||||
#ifdef _S9XLUA_H
|
||||
// File -> Quick Save
|
||||
// File -> Load Lua
|
||||
loadLuaAct = new QAction(tr("Load &Lua Script"), this);
|
||||
//loadLuaAct->setShortcut( QKeySequence(tr("F5")));
|
||||
loadLuaAct->setStatusTip(tr("Load Lua Script"));
|
||||
|
@ -1090,7 +1095,20 @@ void consoleWin_t::createMainMenu(void)
|
|||
|
||||
fileMenu->addSeparator();
|
||||
#else
|
||||
loadLuaAct = NULL;
|
||||
loadLuaAct = nullptr;
|
||||
#endif
|
||||
|
||||
#ifdef _S9XLUA_H
|
||||
// File -> Load QScript
|
||||
loadJsAct = new QAction(tr("Load &Qt Script"), this);
|
||||
loadJsAct->setStatusTip(tr("Load Qt Script"));
|
||||
connect(loadJsAct, SIGNAL(triggered()), this, SLOT(loadJs(void)) );
|
||||
|
||||
fileMenu->addAction(loadJsAct);
|
||||
|
||||
fileMenu->addSeparator();
|
||||
#else
|
||||
loadJsAct = NULL;
|
||||
#endif
|
||||
|
||||
// File -> Screenshot
|
||||
|
@ -2981,6 +2999,19 @@ void consoleWin_t::loadLua(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
void consoleWin_t::loadJs(void)
|
||||
{
|
||||
#ifdef __FCEU_QSCRIPT_ENABLE__
|
||||
QScriptDialog_t *jsCtrlWin;
|
||||
|
||||
//printf("Open JS Control Window\n");
|
||||
|
||||
jsCtrlWin = new QScriptDialog_t(this);
|
||||
|
||||
jsCtrlWin->show();
|
||||
#endif
|
||||
}
|
||||
|
||||
void consoleWin_t::openInputConfWin(void)
|
||||
{
|
||||
//printf("Open Input Config Window\n");
|
||||
|
@ -4546,21 +4577,30 @@ void consoleWin_t::emuFrameFinish(void)
|
|||
{
|
||||
static bool eventProcessingInProg = false;
|
||||
|
||||
if ( eventProcessingInProg )
|
||||
{ // Prevent recursion as processEvents function can double back on us
|
||||
return;
|
||||
}
|
||||
eventProcessingInProg = true;
|
||||
// Process all events before attempting to render viewport
|
||||
QCoreApplication::processEvents();
|
||||
guiSignalRecvMark();
|
||||
|
||||
eventProcessingInProg = false;
|
||||
//if ( eventProcessingInProg )
|
||||
//{ // Prevent recursion as processEvents function can double back on us
|
||||
// return;
|
||||
//}
|
||||
// Prevent recursion as processEvents function can double back on us
|
||||
if ( !eventProcessingInProg )
|
||||
{
|
||||
eventProcessingInProg = true;
|
||||
// Process all events before attempting to render viewport
|
||||
QCoreApplication::processEvents();
|
||||
eventProcessingInProg = false;
|
||||
}
|
||||
|
||||
// Update Input Devices
|
||||
FCEUD_UpdateInput();
|
||||
|
||||
//printf("EMU Frame Finish\n");
|
||||
|
||||
#ifdef __FCEU_QSCRIPT_ENABLE__
|
||||
QtScriptManager::getInstance()->frameFinishedUpdate();
|
||||
#endif
|
||||
|
||||
transferVideoBuffer();
|
||||
}
|
||||
|
||||
|
@ -4569,15 +4609,18 @@ void consoleWin_t::updatePeriodic(void)
|
|||
FCEU_PROFILE_FUNC(prof, "updatePeriodic");
|
||||
static bool eventProcessingInProg = false;
|
||||
|
||||
if ( eventProcessingInProg )
|
||||
{ // Prevent recursion as processEvents function can double back on us
|
||||
return;
|
||||
//if ( eventProcessingInProg )
|
||||
//{ // Prevent recursion as processEvents function can double back on us
|
||||
// return;
|
||||
//}
|
||||
// Prevent recursion as processEvents function can double back on us
|
||||
if ( !eventProcessingInProg )
|
||||
{
|
||||
eventProcessingInProg = true;
|
||||
// Process all events before attempting to render viewport
|
||||
QCoreApplication::processEvents();
|
||||
eventProcessingInProg = false;
|
||||
}
|
||||
eventProcessingInProg = true;
|
||||
// Process all events before attempting to render viewport
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
eventProcessingInProg = false;
|
||||
|
||||
// Update Input Devices
|
||||
FCEUD_UpdateInput();
|
||||
|
@ -4863,6 +4906,7 @@ void emulatorThread_t::run(void)
|
|||
|
||||
void emulatorThread_t::signalFrameFinished(void)
|
||||
{
|
||||
emuSignalSendMark();
|
||||
emit frameFinished();
|
||||
}
|
||||
|
||||
|
|
|
@ -206,6 +206,7 @@ class consoleWin_t : public QMainWindow
|
|||
QAction *quickLoadAct;
|
||||
QAction *quickSaveAct;
|
||||
QAction *loadLuaAct;
|
||||
QAction *loadJsAct;
|
||||
QAction *scrShotAct;
|
||||
QAction *quitAct;
|
||||
QAction *inputConfig;
|
||||
|
@ -372,6 +373,7 @@ class consoleWin_t : public QMainWindow
|
|||
void incrementState(void);
|
||||
void decrementState(void);
|
||||
void loadLua(void);
|
||||
void loadJs(void);
|
||||
void takeScreenShot(void);
|
||||
void prepareScreenShot(void);
|
||||
void powerConsoleCB(void);
|
||||
|
|
|
@ -89,6 +89,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
|
|||
frameTimeIdlePct = new QTreeWidgetItem();
|
||||
frameLateCount = new QTreeWidgetItem();
|
||||
videoTimeAbs = new QTreeWidgetItem();
|
||||
emuSignalDelay = new QTreeWidgetItem();
|
||||
|
||||
tree->addTopLevelItem(frameTimeAbs);
|
||||
tree->addTopLevelItem(frameTimeDel);
|
||||
|
@ -97,6 +98,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
|
|||
tree->addTopLevelItem(frameTimeWorkPct);
|
||||
tree->addTopLevelItem(frameTimeIdlePct);
|
||||
tree->addTopLevelItem(videoTimeAbs);
|
||||
tree->addTopLevelItem(emuSignalDelay);
|
||||
tree->addTopLevelItem(frameLateCount);
|
||||
|
||||
frameTimeAbs->setFlags(Qt::ItemIsEnabled | Qt::ItemNeverHasChildren);
|
||||
|
@ -109,6 +111,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
|
|||
frameTimeWorkPct->setText(0, tr("Frame Work %"));
|
||||
frameTimeIdlePct->setText(0, tr("Frame Idle %"));
|
||||
frameLateCount->setText(0, tr("Frame Late Count"));
|
||||
emuSignalDelay->setText(0, tr("EMU Signal Delay ms"));
|
||||
videoTimeAbs->setText(0, tr("Video Period ms"));
|
||||
|
||||
frameTimeAbs->setTextAlignment(0, Qt::AlignLeft);
|
||||
|
@ -119,6 +122,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
|
|||
frameTimeIdlePct->setTextAlignment(0, Qt::AlignLeft);
|
||||
frameLateCount->setTextAlignment(0, Qt::AlignLeft);
|
||||
videoTimeAbs->setTextAlignment(0, Qt::AlignLeft);
|
||||
emuSignalDelay->setTextAlignment(0, Qt::AlignLeft);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
|
@ -130,6 +134,7 @@ FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
|
|||
frameTimeIdlePct->setTextAlignment(i + 1, Qt::AlignCenter);
|
||||
frameLateCount->setTextAlignment(i + 1, Qt::AlignCenter);
|
||||
videoTimeAbs->setTextAlignment(i + 1, Qt::AlignCenter);
|
||||
emuSignalDelay->setTextAlignment(i + 1, Qt::AlignCenter);
|
||||
}
|
||||
|
||||
hbox = new QHBoxLayout();
|
||||
|
@ -294,6 +299,19 @@ void FrameTimingDialog_t::updateTimingStats(void)
|
|||
sprintf(stmp, "%.3f", stats.videoTimeDel.max * 1e3);
|
||||
videoTimeAbs->setText(4, tr(stmp));
|
||||
|
||||
// Emulator to GUI Thread Signal Delay
|
||||
sprintf(stmp, "%.3f", stats.emuSignalDelay.tgt * 1e3);
|
||||
emuSignalDelay->setText(1, tr(stmp));
|
||||
|
||||
sprintf(stmp, "%.3f", stats.emuSignalDelay.cur * 1e3);
|
||||
emuSignalDelay->setText(2, tr(stmp));
|
||||
|
||||
sprintf(stmp, "%.3f", stats.emuSignalDelay.min * 1e3);
|
||||
emuSignalDelay->setText(3, tr(stmp));
|
||||
|
||||
sprintf(stmp, "%.3f", stats.emuSignalDelay.max * 1e3);
|
||||
emuSignalDelay->setText(4, tr(stmp));
|
||||
|
||||
// Late Count
|
||||
sprintf(stmp, "%u", stats.lateCount);
|
||||
frameLateCount->setText(1, tr("0"));
|
||||
|
|
|
@ -40,6 +40,7 @@ protected:
|
|||
QTreeWidgetItem *frameTimeIdlePct;
|
||||
QTreeWidgetItem *frameLateCount;
|
||||
QTreeWidgetItem *videoTimeAbs;
|
||||
QTreeWidgetItem *emuSignalDelay;
|
||||
QGroupBox *statFrame;
|
||||
|
||||
QTreeWidget *tree;
|
||||
|
|
|
@ -0,0 +1,653 @@
|
|||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2020 thor
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
// QtScriptManager.cpp
|
||||
//
|
||||
#ifdef __FCEU_QSCRIPT_ENABLE__
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <list>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <QTextEdit>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QSettings>
|
||||
#include <QJSValueIterator>
|
||||
|
||||
#include "../../fceu.h"
|
||||
#include "../../movie.h"
|
||||
|
||||
#include "common/os_utils.h"
|
||||
|
||||
#include "Qt/QtScriptManager.h"
|
||||
#include "Qt/main.h"
|
||||
#include "Qt/input.h"
|
||||
#include "Qt/config.h"
|
||||
#include "Qt/keyscan.h"
|
||||
#include "Qt/fceuWrapper.h"
|
||||
#include "Qt/ConsoleUtilities.h"
|
||||
#include "Qt/ConsoleWindow.h"
|
||||
|
||||
//----------------------------------------------------
|
||||
//---- EMU Script Object
|
||||
//----------------------------------------------------
|
||||
EmuScriptObject::EmuScriptObject(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
//----------------------------------------------------
|
||||
EmuScriptObject::~EmuScriptObject()
|
||||
{
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void EmuScriptObject::print(const QString& msg)
|
||||
{
|
||||
if (dialog != nullptr)
|
||||
{
|
||||
dialog->logOutput(msg);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void EmuScriptObject::softreset()
|
||||
{
|
||||
fceuWrapperSoftReset();
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void EmuScriptObject::pause()
|
||||
{
|
||||
FCEUI_SetEmulationPaused( EMULATIONPAUSED_PAUSED );
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void EmuScriptObject::unpause()
|
||||
{
|
||||
FCEUI_SetEmulationPaused(0);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
//---- Qt Script Instance
|
||||
//----------------------------------------------------
|
||||
QtScriptInstance::QtScriptInstance(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
QScriptDialog_t* win = qobject_cast<QScriptDialog_t*>(parent);
|
||||
|
||||
emu = new EmuScriptObject(this);
|
||||
|
||||
if (win != nullptr)
|
||||
{
|
||||
dialog = win;
|
||||
emu->setDialog(dialog);
|
||||
}
|
||||
engine = new QJSEngine(this);
|
||||
|
||||
configEngine();
|
||||
|
||||
QtScriptManager::getInstance()->addScriptInstance(this);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
QtScriptInstance::~QtScriptInstance()
|
||||
{
|
||||
if (engine != nullptr)
|
||||
{
|
||||
engine->deleteLater();
|
||||
engine = nullptr;
|
||||
}
|
||||
QtScriptManager::getInstance()->removeScriptInstance(this);
|
||||
|
||||
//printf("QtScriptInstance Destroyed\n");
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptInstance::resetEngine()
|
||||
{
|
||||
if (engine != nullptr)
|
||||
{
|
||||
engine->deleteLater();
|
||||
engine = nullptr;
|
||||
}
|
||||
engine = new QJSEngine(this);
|
||||
|
||||
configEngine();
|
||||
}
|
||||
//----------------------------------------------------
|
||||
int QtScriptInstance::configEngine()
|
||||
{
|
||||
engine->installExtensions(QJSEngine::ConsoleExtension);
|
||||
|
||||
QJSValue emuObject = engine->newQObject(emu);
|
||||
|
||||
engine->globalObject().setProperty("emu", emuObject);
|
||||
|
||||
onFrameFinishCallback = QJSValue();
|
||||
|
||||
return 0;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
int QtScriptInstance::loadScriptFile( QString filepath )
|
||||
{
|
||||
QFile scriptFile(filepath);
|
||||
|
||||
if (!scriptFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
QTextStream stream(&scriptFile);
|
||||
QString fileText = stream.readAll();
|
||||
scriptFile.close();
|
||||
|
||||
FCEU_WRAPPER_LOCK();
|
||||
QJSValue evalResult = engine->evaluate(fileText, filepath);
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
|
||||
if (evalResult.isError())
|
||||
{
|
||||
print(evalResult.toString());
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("Script Evaluation Success!\n");
|
||||
}
|
||||
onFrameFinishCallback = engine->globalObject().property("onFrameFinish");
|
||||
|
||||
return 0;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptInstance::print(const QString& msg)
|
||||
{
|
||||
if (dialog)
|
||||
{
|
||||
dialog->logOutput(msg);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptInstance::printSymbols(QJSValue& val, int iter)
|
||||
{
|
||||
int i=0;
|
||||
if (iter > 10)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QJSValueIterator it(val);
|
||||
while (it.hasNext())
|
||||
{
|
||||
it.next();
|
||||
QJSValue child = it.value();
|
||||
qDebug() << iter << ":" << i << " " << it.name() << ": " << child.toString();
|
||||
|
||||
bool isPrototype = it.name() == "prototype";
|
||||
|
||||
if (!isPrototype)
|
||||
{
|
||||
printSymbols(child, iter + 1);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
int QtScriptInstance::call(const QString& funcName, const QJSValueList& args)
|
||||
{
|
||||
if (engine == nullptr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (!engine->globalObject().hasProperty(funcName))
|
||||
{
|
||||
print(QString("No function exists: ") + funcName);
|
||||
return -1;
|
||||
}
|
||||
QJSValue func = engine->globalObject().property(funcName);
|
||||
|
||||
FCEU_WRAPPER_LOCK();
|
||||
QJSValue callResult = func.call(args);
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
|
||||
if (callResult.isError())
|
||||
{
|
||||
print(callResult.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("Script Call Success!\n");
|
||||
}
|
||||
|
||||
QJSValue global = engine->globalObject();
|
||||
|
||||
printSymbols( global );
|
||||
|
||||
return 0;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptInstance::onFrameFinish()
|
||||
{
|
||||
if (onFrameFinishCallback.isCallable())
|
||||
{
|
||||
onFrameFinishCallback.call();
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
bool QtScriptInstance::isRunning()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
//---- Qt Script Manager
|
||||
//----------------------------------------------------
|
||||
QtScriptManager* QtScriptManager::_instance = nullptr;
|
||||
|
||||
QtScriptManager::QtScriptManager(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
_instance = this;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
QtScriptManager::~QtScriptManager()
|
||||
{
|
||||
_instance = nullptr;
|
||||
//printf("QtScriptManager destroyed\n");
|
||||
}
|
||||
//----------------------------------------------------
|
||||
QtScriptManager* QtScriptManager::create(QObject* parent)
|
||||
{
|
||||
QtScriptManager* mgr = new QtScriptManager(parent);
|
||||
|
||||
//printf("QtScriptManager created\n");
|
||||
|
||||
return mgr;
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptManager::addScriptInstance(QtScriptInstance* script)
|
||||
{
|
||||
scriptList.push_back(script);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptManager::removeScriptInstance(QtScriptInstance* script)
|
||||
{
|
||||
auto it = scriptList.begin();
|
||||
|
||||
while (it != scriptList.end())
|
||||
{
|
||||
if (*it == script)
|
||||
{
|
||||
it = scriptList.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QtScriptManager::frameFinishedUpdate()
|
||||
{
|
||||
FCEU_WRAPPER_LOCK();
|
||||
for (auto script : scriptList)
|
||||
{
|
||||
script->onFrameFinish();
|
||||
}
|
||||
FCEU_WRAPPER_UNLOCK();
|
||||
}
|
||||
//----------------------------------------------------
|
||||
//---- Qt Script Dialog Window
|
||||
//----------------------------------------------------
|
||||
QScriptDialog_t::QScriptDialog_t(QWidget *parent)
|
||||
: QDialog(parent, Qt::Window)
|
||||
{
|
||||
QVBoxLayout *mainLayout;
|
||||
QHBoxLayout *hbox;
|
||||
QPushButton *closeButton;
|
||||
QLabel *lbl;
|
||||
std::string filename;
|
||||
QSettings settings;
|
||||
|
||||
resize(512, 512);
|
||||
|
||||
setWindowTitle(tr("Qt Java Script Control"));
|
||||
|
||||
mainLayout = new QVBoxLayout();
|
||||
|
||||
lbl = new QLabel(tr("Script File:"));
|
||||
|
||||
scriptPath = new QLineEdit();
|
||||
scriptArgs = new QLineEdit();
|
||||
|
||||
g_config->getOption("SDL.LastLoadJs", &filename);
|
||||
|
||||
scriptPath->setText( tr(filename.c_str()) );
|
||||
scriptPath->setClearButtonEnabled(true);
|
||||
scriptArgs->setClearButtonEnabled(true);
|
||||
|
||||
jsOutput = new QTextEdit();
|
||||
jsOutput->setReadOnly(true);
|
||||
|
||||
hbox = new QHBoxLayout();
|
||||
|
||||
browseButton = new QPushButton(tr("Browse"));
|
||||
stopButton = new QPushButton(tr("Stop"));
|
||||
|
||||
scriptInstance = new QtScriptInstance(this);
|
||||
|
||||
if (scriptInstance->isRunning())
|
||||
{
|
||||
startButton = new QPushButton(tr("Restart"));
|
||||
}
|
||||
else
|
||||
{
|
||||
startButton = new QPushButton(tr("Start"));
|
||||
}
|
||||
|
||||
stopButton->setEnabled(scriptInstance->isRunning());
|
||||
|
||||
connect(browseButton, SIGNAL(clicked()), this, SLOT(openScriptFile(void)));
|
||||
connect(stopButton, SIGNAL(clicked()), this, SLOT(stopScript(void)));
|
||||
connect(startButton, SIGNAL(clicked()), this, SLOT(startScript(void)));
|
||||
|
||||
hbox->addWidget(browseButton);
|
||||
hbox->addWidget(stopButton);
|
||||
hbox->addWidget(startButton);
|
||||
|
||||
mainLayout->addWidget(lbl);
|
||||
mainLayout->addWidget(scriptPath);
|
||||
mainLayout->addLayout(hbox);
|
||||
|
||||
hbox = new QHBoxLayout();
|
||||
lbl = new QLabel(tr("Arguments:"));
|
||||
|
||||
hbox->addWidget(lbl);
|
||||
hbox->addWidget(scriptArgs);
|
||||
|
||||
mainLayout->addLayout(hbox);
|
||||
|
||||
lbl = new QLabel(tr("Output Console:"));
|
||||
mainLayout->addWidget(lbl);
|
||||
mainLayout->addWidget(jsOutput);
|
||||
|
||||
closeButton = new QPushButton( tr("Close") );
|
||||
closeButton->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton));
|
||||
connect(closeButton, SIGNAL(clicked(void)), this, SLOT(closeWindow(void)));
|
||||
|
||||
hbox = new QHBoxLayout();
|
||||
hbox->addStretch(5);
|
||||
hbox->addWidget( closeButton, 1 );
|
||||
mainLayout->addLayout( hbox );
|
||||
|
||||
setLayout(mainLayout);
|
||||
|
||||
//winList.push_back(this);
|
||||
|
||||
periodicTimer = new QTimer(this);
|
||||
|
||||
connect(periodicTimer, &QTimer::timeout, this, &QScriptDialog_t::updatePeriodic);
|
||||
|
||||
periodicTimer->start(200); // 5hz
|
||||
|
||||
restoreGeometry(settings.value("QScriptWindow/geometry").toByteArray());
|
||||
}
|
||||
|
||||
//----------------------------------------------------
|
||||
QScriptDialog_t::~QScriptDialog_t(void)
|
||||
{
|
||||
QSettings settings;
|
||||
std::list<QScriptDialog_t *>::iterator it;
|
||||
|
||||
//printf("Destroy JS Control Window\n");
|
||||
|
||||
periodicTimer->stop();
|
||||
|
||||
//for (it = winList.begin(); it != winList.end(); it++)
|
||||
//{
|
||||
// if ((*it) == this)
|
||||
// {
|
||||
// winList.erase(it);
|
||||
// //printf("Removing JS Window\n");
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
settings.setValue("QScriptWindow/geometry", saveGeometry());
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QScriptDialog_t::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
//printf("JS Control Close Window Event\n");
|
||||
done(0);
|
||||
deleteLater();
|
||||
event->accept();
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QScriptDialog_t::closeWindow(void)
|
||||
{
|
||||
//printf("JS Control Close Window\n");
|
||||
done(0);
|
||||
deleteLater();
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QScriptDialog_t::updatePeriodic(void)
|
||||
{
|
||||
// TODO
|
||||
//printf("Update JS\n");
|
||||
//if (updateJSDisplay)
|
||||
//{
|
||||
// updateJSWindows();
|
||||
// updateJSDisplay = false;
|
||||
//}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QScriptDialog_t::openJSKillMessageBox(void)
|
||||
{
|
||||
int ret;
|
||||
QMessageBox msgBox(this);
|
||||
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.setText(tr("The JS script running has been running a long time.\nIt may have gone crazy. Kill it? (I won't ask again if you say No)\n"));
|
||||
msgBox.setStandardButtons(QMessageBox::Yes);
|
||||
msgBox.addButton(QMessageBox::No);
|
||||
msgBox.setDefaultButton(QMessageBox::No);
|
||||
|
||||
ret = msgBox.exec();
|
||||
|
||||
if (ret == QMessageBox::Yes)
|
||||
{
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QScriptDialog_t::openScriptFile(void)
|
||||
{
|
||||
int ret, useNativeFileDialogVal;
|
||||
QString filename;
|
||||
std::string last;
|
||||
std::string dir;
|
||||
const char *exePath = nullptr;
|
||||
const char *jsPath = nullptr;
|
||||
QFileDialog dialog(this, tr("Open JS Script"));
|
||||
QList<QUrl> urls;
|
||||
QDir d;
|
||||
|
||||
exePath = fceuExecutablePath();
|
||||
|
||||
//urls = dialog.sidebarUrls();
|
||||
urls << QUrl::fromLocalFile(QDir::rootPath());
|
||||
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first());
|
||||
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first());
|
||||
urls << QUrl::fromLocalFile(QStandardPaths::standardLocations(QStandardPaths::DownloadLocation).first());
|
||||
urls << QUrl::fromLocalFile(QDir(FCEUI_GetBaseDirectory()).absolutePath());
|
||||
|
||||
if (exePath[0] != 0)
|
||||
{
|
||||
d.setPath(QString(exePath) + "/../jsScripts");
|
||||
|
||||
if (d.exists())
|
||||
{
|
||||
urls << QUrl::fromLocalFile(d.absolutePath());
|
||||
}
|
||||
}
|
||||
#ifndef WIN32
|
||||
d.setPath("/usr/share/fceux/jsScripts");
|
||||
|
||||
if (d.exists())
|
||||
{
|
||||
urls << QUrl::fromLocalFile(d.absolutePath());
|
||||
}
|
||||
#endif
|
||||
|
||||
jsPath = getenv("FCEU_QSCRIPT_PATH");
|
||||
|
||||
// Parse LUA_PATH and add to urls
|
||||
if (jsPath)
|
||||
{
|
||||
int i, j;
|
||||
char stmp[2048];
|
||||
|
||||
i = j = 0;
|
||||
while (jsPath[i] != 0)
|
||||
{
|
||||
if (jsPath[i] == ';')
|
||||
{
|
||||
stmp[j] = 0;
|
||||
|
||||
if (j > 0)
|
||||
{
|
||||
d.setPath(stmp);
|
||||
|
||||
if (d.exists())
|
||||
{
|
||||
urls << QUrl::fromLocalFile(d.absolutePath());
|
||||
}
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
stmp[j] = jsPath[i];
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
stmp[j] = 0;
|
||||
|
||||
if (j > 0)
|
||||
{
|
||||
d.setPath(stmp);
|
||||
|
||||
if (d.exists())
|
||||
{
|
||||
urls << QUrl::fromLocalFile(d.absolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
|
||||
dialog.setNameFilter(tr("JS Scripts (*.js *.JS) ;; All files (*)"));
|
||||
|
||||
dialog.setViewMode(QFileDialog::List);
|
||||
dialog.setFilter(QDir::AllEntries | QDir::AllDirs | QDir::Hidden);
|
||||
dialog.setLabelText(QFileDialog::Accept, tr("Load"));
|
||||
|
||||
g_config->getOption("SDL.LastLoadJs", &last);
|
||||
|
||||
if (last.size() == 0)
|
||||
{
|
||||
#ifdef WIN32
|
||||
last.assign(FCEUI_GetBaseDirectory());
|
||||
#else
|
||||
last.assign("/usr/share/fceux/jsScripts");
|
||||
#endif
|
||||
}
|
||||
|
||||
getDirFromFile(last.c_str(), dir);
|
||||
|
||||
dialog.setDirectory(tr(dir.c_str()));
|
||||
|
||||
// Check config option to use native file dialog or not
|
||||
g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
|
||||
|
||||
dialog.setOption(QFileDialog::DontUseNativeDialog, !useNativeFileDialogVal);
|
||||
dialog.setSidebarUrls(urls);
|
||||
|
||||
ret = dialog.exec();
|
||||
|
||||
if (ret)
|
||||
{
|
||||
QStringList fileList;
|
||||
fileList = dialog.selectedFiles();
|
||||
|
||||
if (fileList.size() > 0)
|
||||
{
|
||||
filename = fileList[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (filename.isNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
qDebug() << "selected file path : " << filename.toUtf8();
|
||||
|
||||
g_config->setOption("SDL.LastLoadJs", filename.toStdString().c_str());
|
||||
|
||||
scriptPath->setText(filename);
|
||||
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QScriptDialog_t::startScript(void)
|
||||
{
|
||||
scriptInstance->resetEngine();
|
||||
if (scriptInstance->loadScriptFile(scriptPath->text()))
|
||||
{
|
||||
// Script parsing error
|
||||
return;
|
||||
}
|
||||
// TODO add option to pass options to script main.
|
||||
QJSValue argArray = scriptInstance->getEngine()->newArray(4);
|
||||
argArray.setProperty(0, "arg1");
|
||||
argArray.setProperty(1, "arg2");
|
||||
argArray.setProperty(2, "arg3");
|
||||
|
||||
QJSValueList argList = { argArray };
|
||||
|
||||
scriptInstance->call("main", argList);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QScriptDialog_t::stopScript(void)
|
||||
{
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QScriptDialog_t::refreshState(void)
|
||||
{
|
||||
if (scriptInstance->isRunning())
|
||||
{
|
||||
stopButton->setEnabled(true);
|
||||
startButton->setText(tr("Restart"));
|
||||
}
|
||||
else
|
||||
{
|
||||
stopButton->setEnabled(false);
|
||||
startButton->setText(tr("Start"));
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------
|
||||
void QScriptDialog_t::logOutput(const QString& text)
|
||||
{
|
||||
jsOutput->insertPlainText(text);
|
||||
}
|
||||
//----------------------------------------------------
|
||||
#endif // __FCEU_QSCRIPT_ENABLE__
|
|
@ -0,0 +1,144 @@
|
|||
// QtScriptManager.h
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __FCEU_QSCRIPT_ENABLE__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QFrame>
|
||||
#include <QGroupBox>
|
||||
#include <QLineEdit>
|
||||
#include <QTextEdit>
|
||||
#include <QJSEngine>
|
||||
|
||||
#include "Qt/main.h"
|
||||
#include "utils/timeStamp.h"
|
||||
|
||||
class QScriptDialog_t;
|
||||
|
||||
class EmuScriptObject: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
EmuScriptObject(QObject* parent = nullptr);
|
||||
~EmuScriptObject();
|
||||
|
||||
void setDialog(QScriptDialog_t* _dialog){ dialog = _dialog; }
|
||||
|
||||
private:
|
||||
QScriptDialog_t* dialog = nullptr;
|
||||
|
||||
public slots:
|
||||
Q_INVOKABLE void print(const QString& msg);
|
||||
Q_INVOKABLE void softreset();
|
||||
Q_INVOKABLE void pause();
|
||||
Q_INVOKABLE void unpause();
|
||||
|
||||
};
|
||||
|
||||
class QtScriptInstance : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QtScriptInstance(QObject* parent = nullptr);
|
||||
~QtScriptInstance();
|
||||
|
||||
void resetEngine();
|
||||
int loadScriptFile(QString filepath);
|
||||
|
||||
bool isRunning();
|
||||
|
||||
int call(const QString& funcName, const QJSValueList& args = QJSValueList());
|
||||
void onFrameFinish();
|
||||
|
||||
QJSEngine* getEngine(){ return engine; };
|
||||
private:
|
||||
|
||||
int configEngine();
|
||||
void printSymbols(QJSValue& val, int iter = 0);
|
||||
|
||||
QJSEngine* engine = nullptr;
|
||||
QScriptDialog_t* dialog = nullptr;
|
||||
EmuScriptObject* emu = nullptr;
|
||||
QJSValue onFrameFinishCallback;
|
||||
|
||||
public slots:
|
||||
Q_INVOKABLE void print(const QString& msg);
|
||||
};
|
||||
|
||||
class QtScriptManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QtScriptManager(QObject* parent = nullptr);
|
||||
~QtScriptManager();
|
||||
|
||||
static QtScriptManager* getInstance(){ return _instance; }
|
||||
static QtScriptManager* create(QObject* parent = nullptr);
|
||||
|
||||
void addScriptInstance(QtScriptInstance* script);
|
||||
void removeScriptInstance(QtScriptInstance* script);
|
||||
private:
|
||||
static QtScriptManager* _instance;
|
||||
|
||||
QList<QtScriptInstance*> scriptList;
|
||||
FCEU::timeStampRecord lastFrameUpdate;
|
||||
|
||||
public slots:
|
||||
void frameFinishedUpdate();
|
||||
};
|
||||
|
||||
class QScriptDialog_t : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QScriptDialog_t(QWidget *parent = nullptr);
|
||||
~QScriptDialog_t(void);
|
||||
|
||||
void refreshState(void);
|
||||
void logOutput(const QString& text);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *bar);
|
||||
void openJSKillMessageBox(void);
|
||||
|
||||
QTimer *periodicTimer;
|
||||
QLineEdit *scriptPath;
|
||||
QLineEdit *scriptArgs;
|
||||
QPushButton *browseButton;
|
||||
QPushButton *stopButton;
|
||||
QPushButton *startButton;
|
||||
QTextEdit *jsOutput;
|
||||
QtScriptInstance *scriptInstance;
|
||||
|
||||
private:
|
||||
public slots:
|
||||
void closeWindow(void);
|
||||
private slots:
|
||||
void updatePeriodic(void);
|
||||
void openScriptFile(void);
|
||||
void startScript(void);
|
||||
void stopScript(void);
|
||||
};
|
||||
|
||||
// Formatted print
|
||||
//int LuaPrintfToWindowConsole( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
|
||||
|
||||
//void PrintToWindowConsole(intptr_t hDlgAsInt, const char *str);
|
||||
|
||||
//int LuaKillMessageBox(void);
|
||||
|
||||
#endif // __FCEU_QSCRIPT_ENABLE__
|
|
@ -801,6 +801,7 @@ InitConfig()
|
|||
config->addOption("_lastsavestateas", "SDL.LastSaveStateAs", savPath );
|
||||
config->addOption("_lastopenmovie", "SDL.LastOpenMovie", movPath);
|
||||
config->addOption("_lastloadlua", "SDL.LastLoadLua", "");
|
||||
config->addOption("_lastloadjs", "SDL.LastLoadJs", "");
|
||||
config->addOption("SDL.HelpFilePath", "");
|
||||
config->addOption("SDL.AviFilePath", "");
|
||||
config->addOption("SDL.WavFilePath", "");
|
||||
|
|
|
@ -39,6 +39,7 @@ static const double Normal = 1.0; // 1x speed (around 60 fps on NTSC)
|
|||
static uint32 frameLateCounter = 0;
|
||||
static FCEU::timeStampRecord Lasttime, Nexttime, Latetime;
|
||||
static FCEU::timeStampRecord DesiredFrameTime, HalfFrameTime, QuarterFrameTime, DoubleFrameTime;
|
||||
static FCEU::timeStampRecord emuSignalTx, guiSignalRx, emuSignalLatency;
|
||||
static double desired_frametime = (1.0 / 60.099823);
|
||||
static double desired_frameRate = (60.099823);
|
||||
static double baseframeRate = (60.099823);
|
||||
|
@ -52,6 +53,9 @@ static double videoLastTs = 0.0;
|
|||
static double videoPeriodCur = 0.0;
|
||||
static double videoPeriodMin = 1.0;
|
||||
static double videoPeriodMax = 0.0;
|
||||
static double emuLatencyCur = 0.0;
|
||||
static double emuLatencyMin = 1.0;
|
||||
static double emuLatencyMax = 0.0;
|
||||
static bool keepFrameTimeStats = false;
|
||||
static int InFrame = 0;
|
||||
double g_fpsScale = Normal; // used by sdl.cpp
|
||||
|
@ -193,6 +197,11 @@ int getFrameTimingStats( struct frameTimingStat_t *stats )
|
|||
stats->videoTimeDel.min = videoPeriodMin;
|
||||
stats->videoTimeDel.max = videoPeriodMax;
|
||||
|
||||
stats->emuSignalDelay.tgt = 0.0;
|
||||
stats->emuSignalDelay.cur = emuLatencyCur;
|
||||
stats->emuSignalDelay.min = emuLatencyMin;
|
||||
stats->emuSignalDelay.max = emuLatencyMax;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -216,6 +225,34 @@ void videoBufferSwapMark(void)
|
|||
}
|
||||
}
|
||||
|
||||
void emuSignalSendMark(void)
|
||||
{
|
||||
if ( keepFrameTimeStats )
|
||||
{
|
||||
emuSignalTx.readNew();
|
||||
}
|
||||
}
|
||||
|
||||
void guiSignalRecvMark(void)
|
||||
{
|
||||
if ( keepFrameTimeStats )
|
||||
{
|
||||
guiSignalRx.readNew();
|
||||
emuSignalLatency = guiSignalRx - emuSignalTx;
|
||||
|
||||
emuLatencyCur = emuSignalLatency.toSeconds();
|
||||
|
||||
if ( emuLatencyCur < emuLatencyMin )
|
||||
{
|
||||
emuLatencyMin = emuLatencyCur;
|
||||
}
|
||||
if ( emuLatencyCur > emuLatencyMax )
|
||||
{
|
||||
emuLatencyMax = emuLatencyCur;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resetFrameTiming(void)
|
||||
{
|
||||
frameLateCounter = 0;
|
||||
|
@ -225,6 +262,8 @@ void resetFrameTiming(void)
|
|||
frameIdleMin = 1.0;
|
||||
videoPeriodMin = 1.0;
|
||||
videoPeriodMax = 0.0;
|
||||
emuLatencyMin = 1.0;
|
||||
emuLatencyMax = 0.0;
|
||||
}
|
||||
|
||||
/* LOGMUL = exp(log(2) / 3)
|
||||
|
|
|
@ -43,6 +43,13 @@ struct frameTimingStat_t
|
|||
double max;
|
||||
} videoTimeDel;
|
||||
|
||||
struct {
|
||||
double tgt;
|
||||
double cur;
|
||||
double min;
|
||||
double max;
|
||||
} emuSignalDelay;
|
||||
|
||||
unsigned int lateCount;
|
||||
|
||||
bool enabled;
|
||||
|
@ -52,6 +59,8 @@ void resetFrameTiming(void);
|
|||
void setFrameTimingEnable( bool enable );
|
||||
int getFrameTimingStats( struct frameTimingStat_t *stats );
|
||||
void videoBufferSwapMark(void);
|
||||
void emuSignalSendMark(void);
|
||||
void guiSignalRecvMark(void);
|
||||
double getHighPrecTimeStamp(void);
|
||||
double getFrameRate(void);
|
||||
double getFrameRateAdjustmentRatio(void);
|
||||
|
|
Loading…
Reference in New Issue