Compare commits

...

6 Commits

Author SHA1 Message Date
Edênis Freindorfer Azevedo
c960fbc117 [WIP-THREAD] Moving code around. 2020-08-11 17:45:26 -03:00
Edênis Freindorfer Azevedo
06313d9df1 [WIP-THREAD] Encapsulate log calls for queueing.
Reasonable, but it could be a lot better.
2020-08-11 17:45:26 -03:00
Edênis Freindorfer Azevedo
ccd9847672 [WIP-THREAD] Encapsulate printer calls for queueing.
VERY ugly and weird...
2020-08-11 17:45:26 -03:00
Edênis Freindorfer Azevedo
24cc810eb6 [WIP-THREAD] Separate thread for emulation. 2020-08-11 17:45:26 -03:00
Edênis Freindorfer Azevedo
d5d01a8b68 Override to avoid emulator detection mechanism. 2020-08-11 17:45:26 -03:00
Edênis Freindorfer Azevedo
2f5219ee8f Set SDL audio buffer to maximum of 3 frames. 2020-08-11 17:45:26 -03:00
9 changed files with 497 additions and 127 deletions

View File

@@ -25,8 +25,9 @@
extern int emulating;
// Hold up to 300 ms of data in the ring buffer
const double SoundSDL::buftime = 0.300;
// Hold up to 50 ms of data in the ring buffer
// 3 frames
const double SoundSDL::buftime = 0.050;
SoundSDL::SoundSDL():
samples_buf(0),

View File

@@ -364,6 +364,10 @@ mirroringEnabled=1
saveType=1
mirroringEnabled=1
# Higurashi no Nakukoroni (Japan)
[HGRS]
saveType=2
# Koro Koro Puzzle - Happy Panechu! (Japan)
[KHPJ]
saveType=4
@@ -494,4 +498,4 @@ flashSize=131072
# Pokemon - Edicion Rojo Fuego (Spain)
[BPRS]
flashSize=131072
flashSize=131072

View File

@@ -22,6 +22,12 @@ include(VbamFunctions)
set(VBAM_LIBS ${VBAMCORE_LIBS})
option(ENABLE_THREAD_MAINLOOP "Enable separate thread for emulator main loop for WX port" OFF)
if(NOT ENABLE_THREAD_MAINLOOP)
add_definitions(-DNO_THREAD_MAINLOOP)
endif()
if(WIN32)
# not yet implemented
option(ENABLE_DIRECT3D "Enable Direct3D rendering for the wxWidgets port" OFF)

View File

@@ -2297,6 +2297,10 @@ EVT_HANDLER(GeneralConfigure, "General options...")
if (ShowModal(dlg) == wxID_OK)
update_opts();
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
if (panel->game_type() != IMAGE_UNKNOWN)
soundSetThrottle(throttle);
@@ -2598,6 +2602,10 @@ EVT_HANDLER_MASK(DisplayConfigure, "Display options...", CMDEN_NREC_ANY)
if (ShowModal(dlg) != wxID_OK)
return;
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
if (frameSkip >= 0)
systemFrameSkip = frameSkip;
@@ -2609,16 +2617,16 @@ EVT_HANDLER_MASK(DisplayConfigure, "Display options...", CMDEN_NREC_ANY)
panel->ShowFullScreen(true);
}
if (panel->panel) {
panel->panel->Destroy();
panel->panel = NULL;
}
panel->DestroyDrawingPanel();
update_opts();
}
EVT_HANDLER_MASK(ChangeFilter, "Change Pixel Filter", CMDEN_NREC_ANY)
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
int filt = gopts.filter;
if ((filt == FF_PLUGIN || ++gopts.filter == FF_PLUGIN) && gopts.filter_plugin.empty()) {
@@ -2627,10 +2635,7 @@ EVT_HANDLER_MASK(ChangeFilter, "Change Pixel Filter", CMDEN_NREC_ANY)
update_opts();
if (panel->panel) {
panel->panel->Destroy();
panel->panel = NULL;
}
panel->DestroyDrawingPanel();
wxString msg;
msg.Printf(_("Using pixel filter #%d"), gopts.filter);
@@ -2639,13 +2644,13 @@ EVT_HANDLER_MASK(ChangeFilter, "Change Pixel Filter", CMDEN_NREC_ANY)
EVT_HANDLER_MASK(ChangeIFB, "Change Interframe Blending", CMDEN_NREC_ANY)
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
gopts.ifb = (gopts.ifb + 1) % 3;
update_opts();
if (panel->panel) {
panel->panel->Destroy();
panel->panel = NULL;
}
panel->DestroyDrawingPanel();
wxString msg;
msg.Printf(_("Using interframe blending #%d"), gopts.ifb);
@@ -2833,13 +2838,13 @@ EVT_HANDLER(Bilinear, "Use bilinear filter with 3d renderer")
EVT_HANDLER(RetainAspect, "Retain aspect ratio when resizing")
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
GetMenuOptionBool("RetainAspect", gopts.retain_aspect);
// Force new panel with new aspect ratio options.
if (panel->panel) {
panel->panel->Destroy();
panel->panel = nullptr;
}
panel->DestroyDrawingPanel();
update_opts();
}

View File

@@ -4028,5 +4028,8 @@ bool MainFrame::BindControls()
panel->SetFrameTitle();
// All OK; activate idle loop
panel->SetExtraStyle(panel->GetExtraStyle() | wxWS_EX_PROCESS_IDLE);
#ifndef NO_THREAD_MAINLOOP
panel->StartEmulationThread();
#endif
return true;
}

View File

@@ -28,35 +28,11 @@ static void clear_input_press();
int emulating;
IMPLEMENT_DYNAMIC_CLASS(GameArea, wxPanel)
GameArea::GameArea()
: wxPanel()
, panel(NULL)
, emusys(NULL)
, was_paused(false)
, rewind_time(0)
, do_rewind(false)
, rewind_mem(0)
, num_rewind_states(0)
, loaded(IMAGE_UNKNOWN)
, basic_width(GBAWidth)
, basic_height(GBAHeight)
, fullscreen(false)
, paused(false)
, pointer_blanked(false)
, mouse_active_time(0)
{
SetSizer(new wxBoxSizer(wxVERTICAL));
// all renderers prefer 32-bit
// well, "simple" prefers 24-bit, but that's not available for filters
systemColorDepth = 32;
hq2x_init(32);
Init_2xSaI(32);
}
void GameArea::LoadGame(const wxString& name)
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
rom_scene_rls = wxT("-");
rom_scene_rls_name = wxT("-");
rom_name = wxT("");
@@ -553,10 +529,7 @@ void GameArea::UnloadGame(bool destruct)
// in destructor, panel should be auto-deleted by wx since all panels
// are derived from a window attached as child to GameArea
if (panel)
panel->Destroy();
panel = NULL;
DestroyDrawingPanel();
// close any game-related viewer windows
// in destructor, viewer windows are in process of being deleted anyway
@@ -595,6 +568,9 @@ bool GameArea::LoadState(int slot)
bool GameArea::LoadState(const wxFileName& fname)
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
// FIXME: first save to backup state if not backup state
bool ret = emusys->emuReadState(UTF8(fname.GetFullPath()));
@@ -642,6 +618,9 @@ bool GameArea::SaveState(int slot)
bool GameArea::SaveState(const wxFileName& fname)
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
// FIXME: first copy to backup state if not backup state
bool ret = emusys->emuWriteState(UTF8(fname.GetFullPath()));
wxGetApp().frame->update_state_ts(true);
@@ -681,6 +660,9 @@ void GameArea::SaveBattery()
void GameArea::AddBorder()
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
if (basic_width != GBWidth)
return;
@@ -693,14 +675,14 @@ void GameArea::AddBorder()
wxGetApp().frame->Fit();
GetSizer()->Detach(panel->GetWindow());
if (panel)
panel->Destroy();
panel = NULL;
DestroyDrawingPanel();
}
void GameArea::DelBorder()
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
if (basic_width != SGBWidth)
return;
@@ -712,10 +694,7 @@ void GameArea::DelBorder()
wxGetApp().frame->Fit();
GetSizer()->Detach(panel->GetWindow());
if (panel)
panel->Destroy();
panel = NULL;
DestroyDrawingPanel();
}
void GameArea::AdjustMinSize()
@@ -751,6 +730,9 @@ void GameArea::LowerMinSize()
void GameArea::AdjustSize(bool force)
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
AdjustMinSize();
if (fullscreen)
@@ -774,6 +756,9 @@ void GameArea::AdjustSize(bool force)
void GameArea::ShowFullScreen(bool full)
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
if (full == fullscreen) {
// in case the tlw somehow lost its mind, force it to proper mode
if (wxGetApp().frame->IsFullScreen() != fullscreen)
@@ -791,10 +776,7 @@ void GameArea::ShowFullScreen(bool full)
// just in case screen mode is going to change, go ahead and preemptively
// delete panel to be recreated immediately after resize
if (panel) {
panel->Destroy();
panel = NULL;
}
DestroyDrawingPanel();
// Windows does not restore old window size/pos
// at least under Wine
@@ -939,6 +921,9 @@ void GameArea::OnKillFocus(wxFocusEvent& ev)
void GameArea::Pause()
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
if (paused)
return;
@@ -961,6 +946,9 @@ void GameArea::Pause()
void GameArea::Resume()
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
if (!paused)
return;
@@ -973,6 +961,307 @@ void GameArea::Resume()
SetFocus();
}
IMPLEMENT_DYNAMIC_CLASS(GameArea, wxPanel)
GameArea::GameArea()
: wxPanel()
, panel(NULL)
, emusys(NULL)
, was_paused(false)
, rewind_time(0)
, do_rewind(false)
, rewind_mem(0)
, num_rewind_states(0)
, loaded(IMAGE_UNKNOWN)
, basic_width(GBAWidth)
, basic_height(GBAHeight)
, fullscreen(false)
, paused(false)
, pointer_blanked(false)
, mouse_active_time(0)
{
SetSizer(new wxBoxSizer(wxVERTICAL));
// all renderers prefer 32-bit
// well, "simple" prefers 24-bit, but that's not available for filters
systemColorDepth = 32;
hq2x_init(32);
Init_2xSaI(32);
#ifndef NO_THREAD_MAINLOOP
Bind(WX_THREAD_REQUEST_UPDATEDRAWPANEL, &GameArea::RequestUpdateDrawPanel, this);
Bind(WX_THREAD_REQUEST_DRAWFRAME, &GameArea::RequestDrawFrame, this);
Bind(WX_THREAD_REQUEST_UPDATESTATUSBAR, &GameArea::RequestUpdateStatusBar, this);
Bind(WX_THREAD_REQUEST_GBPRINTER, &GameArea::ShowPrinter, this);
Bind(WX_THREAD_REQUEST_UPDATELOG, &GameArea::RequestUpdateLog, this);
#endif
}
#ifndef NO_THREAD_MAINLOOP
wxCriticalSection MainFrame::emulationCS;
void GameArea::RequestDraw()
{
wxQueueEvent(this, new wxThreadEvent(WX_THREAD_REQUEST_DRAWFRAME));
}
void GameArea::RequestDrawFrame(wxThreadEvent& WXUNUSED(event))
{
wxCriticalSectionLocker lock(MainFrame::emulationCS);
MainFrame* mf = wxGetApp().frame;
mf->UpdateViewers();
if (panel) {
panel->DrawArea(&pix);
}
}
wxThread::ExitCode GameArea::Entry()
{
while (!GetThread()->TestDestroy()) {
{
wxCriticalSectionLocker lock(MainFrame::emulationCS);
if (emusys) {
wxGetApp().frame->PollJoysticks();
if (!panel) {
wxQueueEvent(this, new wxThreadEvent(WX_THREAD_REQUEST_UPDATEDRAWPANEL));
}
if (!paused && panel) {
emusys->emuMain(emusys->emuCount);
}
}
}
wxMilliSleep(1);
}
return (wxThread::ExitCode)0;
}
void GameArea::StopEmulationThread()
{
if (GetThread() && GetThread()->IsRunning())
GetThread()->Delete(); // it will exit after next `TestDestroy()`
}
void GameArea::StartEmulationThread()
{
if (CreateThread(wxTHREAD_JOINABLE) != wxTHREAD_NO_ERROR)
{
wxLogError(_("Could not create emulation thread!"));
return;
}
if (GetThread()->Run() != wxTHREAD_NO_ERROR)
{
wxLogError(_("Could not run emulation thread!"));
return;
}
}
void GameArea::RequestUpdateDrawPanel(wxThreadEvent& WXUNUSED(event))
{
wxCriticalSectionLocker lock(MainFrame::emulationCS);
if (!panel) {
switch (gopts.render_method) {
case RND_SIMPLE:
panel = new BasicDrawingPanel(this, basic_width, basic_height);
break;
#ifdef __WXMAC__
case RND_QUARTZ2D:
panel = new Quartz2DDrawingPanel(this, basic_width, basic_height);
break;
#endif
#ifndef NO_OGL
case RND_OPENGL:
panel = new GLDrawingPanel(this, basic_width, basic_height);
break;
#endif
#if defined(__WXMSW__) && !defined(NO_D3D)
case RND_DIRECT3D:
panel = new DXDrawingPanel(this, basic_width, basic_height);
break;
#endif
}
wxWindow* w = panel->GetWindow();
// set up event handlers
w->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(GameArea::OnKeyDown), NULL, this);
w->Connect(wxEVT_KEY_UP, wxKeyEventHandler(GameArea::OnKeyUp), NULL, this);
w->Connect(wxEVT_PAINT, wxPaintEventHandler(GameArea::PaintEv), NULL, this);
w->Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(GameArea::EraseBackground), NULL, this);
// set userdata so we know it's the panel and not the frame being resized
// the userdata is freed on disconnect/destruction
this->Connect(wxEVT_SIZE, wxSizeEventHandler(GameArea::OnSize), NULL, this);
// We need to check if the buttons stayed pressed when focus the panel.
w->Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(GameArea::OnKillFocus), NULL, this);
// Update mouse last-used timers on mouse events etc..
w->Connect(wxEVT_MOTION, wxMouseEventHandler(GameArea::MouseEvent), NULL, this);
w->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(GameArea::MouseEvent), NULL, this);
w->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(GameArea::MouseEvent), NULL, this);
w->Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(GameArea::MouseEvent), NULL, this);
w->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(GameArea::MouseEvent), NULL, this);
w->SetBackgroundStyle(wxBG_STYLE_CUSTOM);
w->SetSize(wxSize(basic_width, basic_height));
if (maxScale)
w->SetMaxSize(wxSize(basic_width * maxScale,
basic_height * maxScale));
// if user changed Display/Scale config, this needs to run
AdjustMinSize();
AdjustSize(false);
unsigned frame_priority = gopts.retain_aspect ? 0 : 1;
GetSizer()->Clear();
// add spacers on top and bottom to center panel vertically
// but not on 2.8 which does not handle this correctly
if (gopts.retain_aspect)
#if wxCHECK_VERSION(2, 9, 0)
GetSizer()->Add(0, 0, wxEXPAND);
#else
frame_priority = 1;
#endif
// this triggers an assertion dialog in <= 3.1.2 in debug mode
GetSizer()->Add(w, frame_priority, gopts.retain_aspect ? (wxSHAPED | wxALIGN_CENTER | wxEXPAND) : wxEXPAND);
#if wxCHECK_VERSION(2, 9, 0)
if (gopts.retain_aspect)
GetSizer()->Add(0, 0, wxEXPAND);
#endif
Layout();
#if wxCHECK_VERSION(2, 9, 0)
SendSizeEvent();
#endif
if (pointer_blanked)
w->SetCursor(wxCursor(wxCURSOR_BLANK));
// set focus to panel
w->SetFocus();
// generate system color maps (after output module init)
if (loaded == IMAGE_GBA) utilUpdateSystemColorMaps(gbaLcdFilter);
else if (loaded == IMAGE_GB) utilUpdateSystemColorMaps(gbLcdFilter);
else utilUpdateSystemColorMaps(false);
}
}
void GameArea::RequestStatusBar(int speed, int frames)
{
wxThreadEvent *event = new wxThreadEvent(WX_THREAD_REQUEST_UPDATESTATUSBAR);
event->SetPayload(speed);
event->SetExtraLong(frames); // should probably use payload too
wxQueueEvent(this, event);
}
struct PrinterDataDialog {
uint16_t* to_print;
uint16_t** accum_prdata;
int lines, feed;
int *accum_prdata_len, *accum_prdata_size;
};
PrinterDataDialog printerDataDialog;
void GameArea::RequestGBPrinter(uint16_t* to_print, uint16_t** accum_prdata, int lines, int feed, int *accum_prdata_len, int *accum_prdata_size)
{
wxThreadEvent *event = new wxThreadEvent(WX_THREAD_REQUEST_GBPRINTER);
printerDataDialog = {to_print, accum_prdata, lines, feed, accum_prdata_len, accum_prdata_size};
event->SetPayload(&printerDataDialog);
wxQueueEvent(this, event);
}
void GameArea::ShowPrinter(wxThreadEvent& event)
{
wxCriticalSectionLocker lock(MainFrame::emulationCS);
PrinterDataDialog *pdd = event.GetPayload<PrinterDataDialog*>();
uint16_t* to_print = pdd->to_print;
uint16_t** accum_prdata = pdd->accum_prdata;
int lines = pdd->lines;
int feed = pdd->feed;
int *accum_prdata_len = pdd->accum_prdata_len;
int *accum_prdata_size = pdd->accum_prdata_size;
PrintDialog dlg(to_print, lines, !(feed & 15));
int ret = dlg.ShowModal();
if (ret == wxID_OK) {
*accum_prdata_len = (lines + 1) * 162;
if (to_print != *accum_prdata) {
if (*accum_prdata_size < *accum_prdata_len) {
if (!(*accum_prdata_size))
*accum_prdata = (uint16_t*)calloc(*accum_prdata_len, 2);
else
*accum_prdata = (uint16_t*)realloc(*accum_prdata, *accum_prdata_len * 2);
*accum_prdata_size = *accum_prdata_len;
}
memcpy(*accum_prdata, to_print, *accum_prdata_len * 2);
}
}
}
void GameArea::RequestUpdateStatusBar(wxThreadEvent& event)
{
wxCriticalSectionLocker lock(MainFrame::emulationCS);
MainFrame* f = wxGetApp().frame;
int speed = event.GetPayload<int>();
int frames = event.GetExtraLong(); // should probably use payload too
wxString s;
s.Printf(_("%d%%(%d, %d fps)"), speed, systemFrameSkip, frames * speed / 100);
switch (showSpeed) {
case SS_NONE:
f->GetPanel()->osdstat.clear();
break;
case SS_PERCENT:
f->GetPanel()->osdstat.Printf(_("%d%%"), speed);
break;
case SS_DETAILED:
f->GetPanel()->osdstat = s;
break;
}
wxGetApp().frame->SetStatusText(s, 1);
}
void GameArea::UpdateLog()
{
wxQueueEvent(this, new wxThreadEvent(WX_THREAD_REQUEST_UPDATELOG));
}
void GameArea::RequestUpdateLog(wxThreadEvent& WXUNUSED(event))
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
LogDialog* d = wxGetApp().frame->logdlg;
if (d && d->IsShown()) {
d->Update();
}
}
#endif // NO_THREAD_MAINLOOP
void GameArea::DestroyDrawingPanel()
{
if (panel) {
panel->Destroy();
panel = nullptr;
}
}
void GameArea::OnIdle(wxIdleEvent& event)
{
wxString pl = wxGetApp().pending_load;
@@ -1416,7 +1705,9 @@ void GameArea::OnSDLJoy(wxSDLJoyEvent& ev)
}
BEGIN_EVENT_TABLE(GameArea, wxPanel)
#ifdef NO_THREAD_MAINLOOP
EVT_IDLE(GameArea::OnIdle)
#endif
EVT_SDLJOY(GameArea::OnSDLJoy)
// FIXME: wxGTK does not generate motion events in MainFrame (not sure
// what to do about it)

View File

@@ -86,18 +86,22 @@ void systemDrawScreen()
{
frames++;
MainFrame* mf = wxGetApp().frame;
mf->UpdateViewers();
// FIXME: Sm60FPS crap and sondBufferLow crap
GameArea* ga = mf->GetPanel();
#ifndef NO_FFMPEG
if (ga)
ga->AddFrame(pix);
#endif
#ifndef NO_THREAD_MAINLOOP
if (ga && ga->panel) {
ga->RequestDraw();
}
#else
mf->UpdateViewers();
if (ga && ga->panel)
ga->panel->DrawArea(&pix);
#endif
}
// record a game "movie"
@@ -337,6 +341,9 @@ uint32_t systemReadJoypad(int joy)
void systemShowSpeed(int speed)
{
MainFrame* f = wxGetApp().frame;
#ifndef NO_THREAD_MAINLOOP
f->GetPanel()->RequestStatusBar(speed, frames);
#else
wxString s;
s.Printf(_("%d%%(%d, %d fps)"), speed, systemFrameSkip, frames * speed / 100);
@@ -355,6 +362,7 @@ void systemShowSpeed(int speed)
}
wxGetApp().frame->SetStatusText(s, 1);
#endif // NO_THREAD_MAINLOOP
frames = 0;
}
@@ -658,53 +666,6 @@ int systemGetSensorZ()
return sensorz[gopts.default_stick - 1] / 10;
}
class PrintDialog : public wxEvtHandler, public wxPrintout {
public:
PrintDialog(const uint16_t* data, int lines, bool cont);
~PrintDialog();
int ShowModal()
{
dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER);
if (gopts.keep_on_top)
dlg->SetWindowStyle(dlg->GetWindowStyle() | wxSTAY_ON_TOP);
else
dlg->SetWindowStyle(dlg->GetWindowStyle() & ~wxSTAY_ON_TOP);
CheckPointer(wxGetApp().frame);
return wxGetApp().frame->ShowModal(dlg);
}
private:
void DoSave(wxCommandEvent&);
void DoPrint(wxCommandEvent&);
void ChangeMag(wxCommandEvent&);
void ShowImg(wxPaintEvent&);
bool OnPrintPage(int pno);
void OnPreparePrinting();
bool HasPage(int pno) { return pno <= npw * nph; }
void GetPageInfo(int* minp, int* maxp, int* pfrom, int* pto)
{
*minp = 1;
*maxp = npw * nph;
*pfrom = 1;
*pto = 1;
}
wxDialog* dlg;
wxPanel* p;
wxImage img;
wxBitmap* bmp;
wxControlWithItems* mag;
static wxPrintData* printdata;
static wxPageSetupDialogData* pagedata;
wxRect margins;
int npw, nph;
DECLARE_CLASS(PrintDialog)
};
IMPLEMENT_CLASS(PrintDialog, wxEvtHandler)
PrintDialog::PrintDialog(const uint16_t* data, int lines, bool cont):
@@ -1016,6 +977,9 @@ void systemGbPrint(uint8_t* data, int len, int pages, int feed, int pal, int con
return;
}
#ifndef NO_THREAD_MAINLOOP
panel->RequestGBPrinter(to_print, &accum_prdata, lines, feed, &accum_prdata_len, &accum_prdata_size);
#else
PrintDialog dlg(to_print, lines, !(feed & 15));
int ret = dlg.ShowModal();
@@ -1035,6 +999,7 @@ void systemGbPrint(uint8_t* data, int len, int pages, int feed, int pal, int con
memcpy(accum_prdata, to_print, accum_prdata_len * 2);
}
}
#endif
}
void systemScreenMessage(const wxString& msg)
@@ -1324,12 +1289,15 @@ void log(const char* defaultMsg, ...)
wxGetApp().log.append(msg);
if (wxGetApp().IsMainLoopRunning()) {
#ifndef NO_THREAD_MAINLOOP
wxGetApp().frame->GetPanel()->UpdateLog();
#else
LogDialog* d = wxGetApp().frame->logdlg;
if (d && d->IsShown()) {
d->Update();
}
systemScreenMessage(msg);
#endif
//systemScreenMessage(msg);
}
}

View File

@@ -726,6 +726,9 @@ MainFrame::MainFrame()
MainFrame::~MainFrame()
{
#ifndef NO_THREAD_MAINLOOP
GetPanel()->StopEmulationThread();
#endif
#ifndef NO_LINK
CloseLink();
#endif
@@ -772,6 +775,10 @@ void MainFrame::OnDropFile(wxDropFilesEvent& event)
wxString* f = event.GetFiles();
// ignore all but last
wxGetApp().pending_load = f[event.GetNumberOfFiles() - 1];
#ifndef NO_THREAD_MAINLOOP
GetPanel()->LoadGame(wxGetApp().pending_load);
#endif
}
void MainFrame::OnMenu(wxContextMenuEvent& event)
@@ -845,6 +852,9 @@ void MainFrame::OnSize(wxSizeEvent& event)
int MainFrame::FilterEvent(wxEvent& event)
{
#ifndef NO_THREAD_MAINLOOP
wxCriticalSectionLocker lock(MainFrame::emulationCS);
#endif
if (event.GetEventType() == wxEVT_KEY_DOWN && !menus_opened && !dialog_opened)
{
wxKeyEvent& ke = (wxKeyEvent&)event;
@@ -1081,7 +1091,7 @@ void MainFrame::MenuPopped(wxMenuEvent& evt)
// On Windows nullptr is the system menu.
if (evt.GetEventType() == wxEVT_MENU_CLOSE && (evt.GetMenu() == nullptr || evt.GetMenu()->GetMenuBar() == GetMenuBar()))
SetMenusOpened(false);
else
else if (evt.GetEventType() == wxEVT_MENU_OPEN)
SetMenusOpened(true);
evt.Skip();
@@ -1101,17 +1111,17 @@ void MainFrame::MenuPopped(wxMenuEvent& evt)
void MainFrame::SetMenusOpened(bool state)
{
if ((menus_opened = state)) {
#ifdef __WXMSW__
paused = true;
panel->Pause();
#endif
}
else {
#ifdef __WXMSW__
paused = false;
pause_next = false;
panel->Resume();
#endif
//#ifdef __WXMSW__
// paused = true;
// panel->Pause();
//#endif
// }
// else {
//#ifdef __WXMSW__
// paused = false;
// pause_next = false;
// panel->Resume();
//#endif
}
}

View File

@@ -214,6 +214,10 @@ public:
MainFrame();
~MainFrame();
#ifndef NO_THREAD_MAINLOOP
static wxCriticalSection emulationCS;
#endif
bool BindControls();
void MenuOptionIntMask(const char* menuName, int& field, int mask);
void MenuOptionIntRadioValue(const char* menuName, int& field, int mask);
@@ -500,11 +504,42 @@ class DrawingPanelBase;
#include <windows.h>
#endif
class GameArea : public wxPanel, public HiDPIAware {
#ifndef NO_THREAD_MAINLOOP
#include <wx/thread.h>
wxDEFINE_EVENT(WX_THREAD_REQUEST_UPDATEDRAWPANEL, wxThreadEvent);
wxDEFINE_EVENT(WX_THREAD_REQUEST_DRAWFRAME, wxThreadEvent);
wxDEFINE_EVENT(WX_THREAD_REQUEST_UPDATESTATUSBAR, wxThreadEvent);
wxDEFINE_EVENT(WX_THREAD_REQUEST_GBPRINTER, wxThreadEvent);
wxDEFINE_EVENT(WX_THREAD_REQUEST_UPDATELOG, wxThreadEvent);
#endif // NO_THREAD_MAINLOOP
class GameArea : public wxPanel, public HiDPIAware
#ifndef NO_THREAD_MAINLOOP
, public wxThreadHelper
#endif
{
public:
GameArea();
virtual ~GameArea();
#ifndef NO_THREAD_MAINLOOP
virtual wxThread::ExitCode Entry();
void StartEmulationThread();
void StopEmulationThread();
void RequestUpdateDrawPanel(wxThreadEvent&);
void RequestDrawFrame(wxThreadEvent&);
void RequestUpdateStatusBar(wxThreadEvent&);
void RequestDraw();
void RequestStatusBar(int speed, int frames);
void RequestGBPrinter(uint16_t*, uint16_t**, int, int, int*, int*);
void ShowPrinter(wxThreadEvent&);
void RequestUpdateLog(wxThreadEvent&);
void UpdateLog();
#endif
void DestroyDrawingPanel();
virtual void SetMainFrame(MainFrame* parent) { main_frame = parent; }
// set to game title + link info
@@ -747,6 +782,53 @@ private:
#include "opts.h"
class PrintDialog : public wxEvtHandler, public wxPrintout {
public:
PrintDialog(const uint16_t* data, int lines, bool cont);
~PrintDialog();
int ShowModal()
{
dlg->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER);
if (gopts.keep_on_top)
dlg->SetWindowStyle(dlg->GetWindowStyle() | wxSTAY_ON_TOP);
else
dlg->SetWindowStyle(dlg->GetWindowStyle() & ~wxSTAY_ON_TOP);
CheckPointer(wxGetApp().frame);
return wxGetApp().frame->ShowModal(dlg);
}
private:
void DoSave(wxCommandEvent&);
void DoPrint(wxCommandEvent&);
void ChangeMag(wxCommandEvent&);
void ShowImg(wxPaintEvent&);
bool OnPrintPage(int pno);
void OnPreparePrinting();
bool HasPage(int pno) { return pno <= npw * nph; }
void GetPageInfo(int* minp, int* maxp, int* pfrom, int* pto)
{
*minp = 1;
*maxp = npw * nph;
*pfrom = 1;
*pto = 1;
}
wxDialog* dlg;
wxPanel* p;
wxImage img;
wxBitmap* bmp;
wxControlWithItems* mag;
static wxPrintData* printdata;
static wxPageSetupDialogData* pagedata;
wxRect margins;
int npw, nph;
DECLARE_CLASS(PrintDialog)
};
// I should add this to SoundDriver, but wxArrayString is wx-specific
// I suppose I could make subclass wxSoundDriver. maybe later.