Browse Source

Further multi-threading stability/performance updates and various bug fixes

* Imagine: Manage View objects with std::unique_ptr
* Imagine: Add preferred size and non-blocking read mode to Pipe
* Imagine: Add Base::MessagePort for sending messages to another EventLoop
* Imagine: Add Window::setCustomData()
* Imagine: Add Renderer::flush()
* Imagine: Add GfxText::fullHeight()
* Imagine: Fix error handling in GraphicBufferStorage
* Imagine: Require fence sync support to use separate render thread
* Imagine: Prefer regular OpenGL textures over SurfaceTexture on Android if PBOs are supported
* Imagine: Asynchronous support for Texture functions writeAligned(), unlock(), & generateMipmaps()
* Imagine: Add mutexes to ViewController to synchronize state changes & drawing
* Imagine: Add support for canceled input events
* Imagine: Fix crash in XRRGetOutputInfo() on XWayland
* Imagine: Use clang instead of clang++ for Android since C++ libs are linked explicitly
* Imagine: Add support for side-by-side NDK installs from Android Studio 3.5
* Imagine: Use native Choreographer on 64-bit systems with Android 7.0+
* Imagine: Fallback to SimpleFrameTimer on Linux if other timers fail
* Imagine: Move file descriptor utilities into a separate source file
* Imagine: Update Gradle version to 5.6.2
* Imagine: Update bundled XZ Utils to 5.2.4
* Imagine: Change non-standard /usr/lib32 to /usr/lib for 32-bit Linux
* EmuFramework: Simplify EmuView handling so it can be moved between windows
* EmuFramework: Add EmuSystemTask for running emulation on separate thread
* EmuFramework: Add EmuViewController for managing GUI & emulation views
* EmuFramework: Clear EmuVideo when closing a system
* EmuFramework: Use draw times in DetectFrameRateView when frame timestamps aren't supported
* EmuFramework: Use increased brightness for EmuVideoLayer when window is out of focus
* EmuFramework: Change MsgPopup to ToastView and move it into common GUI objects
* NEO.emu: Fix stack overflow in filename code
* Various code clean ups
master
Robert Broglia 1 month ago
parent
commit
1054695c99
100 changed files with 2474 additions and 2002 deletions
  1. 5
    7
      2600.emu/src/main/EmuMenuViews.cc
  2. 1
    1
      2600.emu/src/main/Main.cc
  3. 1
    1
      C64.emu/build.mk
  4. 45
    47
      C64.emu/src/main/EmuMenuViews.cc
  5. 1
    1
      C64.emu/src/main/Main.cc
  6. 1
    0
      C64.emu/src/main/input.cc
  7. 2
    1
      EmuFramework/build.mk
  8. 0
    1
      EmuFramework/include/emuframework/CreditsView.hh
  9. 6
    4
      EmuFramework/include/emuframework/EmuApp.hh
  10. 8
    3
      EmuFramework/include/emuframework/EmuInputView.hh
  11. 1
    2
      EmuFramework/include/emuframework/EmuLoadProgressView.hh
  12. 2
    1
      EmuFramework/include/emuframework/EmuSystem.hh
  13. 3
    0
      EmuFramework/include/emuframework/EmuVideo.hh
  14. 4
    1
      EmuFramework/include/emuframework/EmuVideoLayer.hh
  15. 2
    3
      EmuFramework/include/emuframework/EmuView.hh
  16. 4
    4
      EmuFramework/include/emuframework/FilePicker.hh
  17. 0
    1
      EmuFramework/include/emuframework/InputManagerView.hh
  18. 2
    2
      EmuFramework/include/emuframework/OptionView.hh
  19. 1
    1
      EmuFramework/include/emuframework/Recent.hh
  20. 4
    1
      EmuFramework/include/emuframework/TouchConfigView.hh
  21. 2
    0
      EmuFramework/include/emuframework/TurboInput.hh
  22. 38
    16
      EmuFramework/include/emuframework/VController.hh
  23. 3
    3
      EmuFramework/src/BundledGamesView.cc
  24. 31
    24
      EmuFramework/src/ButtonConfigView.cc
  25. 5
    3
      EmuFramework/src/Cheats.cc
  26. 116
    812
      EmuFramework/src/EmuApp.cc
  27. 43
    77
      EmuFramework/src/EmuInput.cc
  28. 35
    23
      EmuFramework/src/EmuInputView.cc
  29. 48
    56
      EmuFramework/src/EmuMainMenuView.cc
  30. 8
    8
      EmuFramework/src/EmuOptions.cc
  31. 1
    1
      EmuFramework/src/EmuOptions.hh
  32. 8
    11
      EmuFramework/src/EmuSystem.cc
  33. 29
    32
      EmuFramework/src/EmuSystemActionsView.cc
  34. 188
    0
      EmuFramework/src/EmuSystemTask.cc
  35. 37
    17
      EmuFramework/src/EmuVideo.cc
  36. 15
    11
      EmuFramework/src/EmuVideoLayer.cc
  37. 4
    18
      EmuFramework/src/EmuView.cc
  38. 866
    0
      EmuFramework/src/EmuViewController.cc
  39. 13
    13
      EmuFramework/src/FilePicker.cc
  40. 59
    58
      EmuFramework/src/InputManagerView.cc
  41. 0
    137
      EmuFramework/src/MsgPopup.cc
  42. 219
    167
      EmuFramework/src/OptionView.cc
  43. 3
    3
      EmuFramework/src/Recent.cc
  44. 2
    2
      EmuFramework/src/RecentGameView.cc
  45. 65
    62
      EmuFramework/src/TouchConfigView.cc
  46. 76
    76
      EmuFramework/src/VController.cc
  47. 1
    1
      EmuFramework/src/VideoImageEffect.cc
  48. 123
    23
      EmuFramework/src/private.hh
  49. 2
    21
      EmuFramework/src/privateInput.hh
  50. 1
    3
      GBA.emu/src/main/Cheats.cc
  51. 5
    6
      GBA.emu/src/main/EmuMenuViews.cc
  52. 1
    1
      GBA.emu/src/main/Main.cc
  53. 12
    12
      GBA.emu/src/vbam/gba/GBA-thumb.cpp
  54. 6
    6
      GBA.emu/src/vbam/gba/GBA.h
  55. 3
    3
      GBA.emu/src/vbam/gba/GBAcpu.h
  56. 1
    3
      GBC.emu/src/main/Cheats.cc
  57. 7
    8
      GBC.emu/src/main/EmuMenuViews.cc
  58. 1
    1
      GBC.emu/src/main/Main.cc
  59. 1
    1
      MD.emu/src/genplus-gx/m68k/musashi/m68k.h
  60. 2
    2
      MD.emu/src/genplus-gx/system.cc
  61. 1
    1
      MD.emu/src/genplus-gx/z80/z80.cc
  62. 1
    1
      MD.emu/src/genplus-gx/z80/z80.h
  63. 1
    3
      MD.emu/src/main/Cheats.cc
  64. 14
    15
      MD.emu/src/main/EmuMenuViews.cc
  65. 0
    1
      MD.emu/src/main/Main.cc
  66. 1
    1
      MD.emu/src/scd/gfx_cd.cc
  67. 28
    29
      MSX.emu/src/main/EmuMenuViews.cc
  68. 1
    1
      MSX.emu/src/main/Main.cc
  69. 4
    4
      NEO.emu/src/gngeo/fileio.c
  70. 18
    21
      NEO.emu/src/main/EmuMenuViews.cc
  71. 1
    1
      NEO.emu/src/main/Main.cc
  72. 3
    5
      NES.emu/src/main/Cheats.cc
  73. 13
    15
      NES.emu/src/main/EmuMenuViews.cc
  74. 1
    1
      NES.emu/src/main/Main.cc
  75. 2
    2
      NGP.emu/src/main/EmuMenuViews.cc
  76. 1
    1
      NGP.emu/src/main/Main.cc
  77. 7
    8
      PCE.emu/src/main/EmuMenuViews.cc
  78. 2
    2
      PCE.emu/src/main/Main.cc
  79. 5
    5
      Saturn.emu/src/main/EmuMenuViews.cc
  80. 1
    1
      Saturn.emu/src/main/Main.cc
  81. 1
    3
      Snes9x/src/main/Cheats.cc
  82. 5
    6
      Snes9x/src/main/EmuMenuViews.cc
  83. 1
    1
      Snes9x/src/main/Main.cc
  84. 1
    0
      imagine/bundle/all/src/libarchive/common.mk
  85. 1
    0
      imagine/bundle/all/src/libsndfile/common.mk
  86. 2
    1
      imagine/bundle/all/src/xz/common.mk
  87. BIN
      imagine/bundle/all/src/xz/xz-5.2.3.tar.xz
  88. BIN
      imagine/bundle/all/src/xz/xz-5.2.4.tar.xz
  89. 1
    0
      imagine/include/imagine/base/BaseWindow.hh
  90. 117
    0
      imagine/include/imagine/base/MessagePort.hh
  91. 4
    3
      imagine/include/imagine/base/Pipe.hh
  92. 3
    2
      imagine/include/imagine/base/Screen.hh
  93. 28
    59
      imagine/include/imagine/base/Window.hh
  94. 11
    0
      imagine/include/imagine/base/WindowConfig.hh
  95. 0
    1
      imagine/include/imagine/base/android/AndroidGL.hh
  96. 1
    0
      imagine/include/imagine/base/android/android.hh
  97. 12
    0
      imagine/include/imagine/base/baseDefs.hh
  98. 7
    5
      imagine/include/imagine/gfx/Gfx.hh
  99. 1
    0
      imagine/include/imagine/gfx/GfxText.hh
  100. 0
    0
      imagine/include/imagine/gfx/Texture.hh

+ 5
- 7
2600.emu/src/main/EmuMenuViews.cc View File

@@ -221,8 +221,7 @@ private:
{
if(EmuSystem::gameIsRunning())
{
auto &vcsSwitchesView = *new VCSSwitchesView{attachParams()};
pushAndShow(vcsSwitchesView, e);
pushAndShow(makeView<VCSSwitchesView>(), e);
}
}
};
@@ -234,8 +233,7 @@ private:
{
if(EmuSystem::gameIsRunning())
{
auto &optionView = *new ConsoleOptionView{attachParams()};
pushAndShow(optionView, e);
pushAndShow(makeView<ConsoleOptionView>(), e);
}
}
};
@@ -249,12 +247,12 @@ public:
}
};

View *EmuApp::makeCustomView(ViewAttachParams attach, ViewID id)
std::unique_ptr<View> EmuApp::makeCustomView(ViewAttachParams attach, ViewID id)
{
switch(id)
{
case ViewID::VIDEO_OPTIONS: return new CustomVideoOptionView(attach);
case ViewID::SYSTEM_ACTIONS: return new CustomSystemActionsView(attach);
case ViewID::VIDEO_OPTIONS: return std::make_unique<CustomVideoOptionView>(attach);
case ViewID::SYSTEM_ACTIONS: return std::make_unique<CustomSystemActionsView>(attach);
default: return nullptr;
}
}

+ 1
- 1
2600.emu/src/main/Main.cc View File

@@ -153,7 +153,7 @@ void EmuSystem::runFrame(EmuVideo *video, bool renderAudio)
tia.update();
if(video)
{
video->setFormat({{(int)tia.width(), (int)tia.height()}, IG::PIXEL_FMT_RGB565});
video->setFormatLocked({{(int)tia.width(), (int)tia.height()}, IG::PIXEL_FMT_RGB565});
auto img = video->startFrame();
osystem->frameBuffer().render(img.pixmap(), tia);
img.endFrame();

+ 1
- 1
C64.emu/build.mk View File

@@ -5,7 +5,7 @@ include $(IMAGINE_PATH)/make/imagineAppBase.mk

viceSrcPath := $(projectPath)/src/vice

CFLAGS_WARN += -Werror-implicit-function-declaration
CFLAGS_LANG += -Werror-implicit-function-declaration

ifeq ($(ENV),android)
LDLIBS += -ldl

+ 45
- 47
C64.emu/src/main/EmuMenuViews.cc View File

@@ -479,7 +479,8 @@ public:

void addTapeFilePickerView(Input::Event e)
{
auto &fPicker = *EmuFilePicker::makeForMediaChange(attachParams(), e, EmuSystem::gamePath(), hasC64TapeExtension,
EmuApp::pushAndShowModalView(
EmuFilePicker::makeForMediaChange(attachParams(), e, EmuSystem::gamePath(), hasC64TapeExtension,
[this](FSPicker &picker, const char* name, Input::Event e)
{
auto path = picker.makePathString(name);
@@ -488,8 +489,7 @@ public:
onTapeMediaChange();
}
picker.dismiss();
});
EmuApp::pushAndShowModalView(fPicker, e);
}), e);
}

private:
@@ -503,22 +503,22 @@ private:
auto name = plugin.tape_get_file_name();
if(name && strlen(name))
{
auto &multiChoiceView = *new TextTableView{"Tape Drive", attachParams(), IG::size(insertEjectMenuStr)};
multiChoiceView.appendItem(insertEjectMenuStr[0],
auto multiChoiceView = makeViewWithName<TextTableView>("Tape Drive", IG::size(insertEjectMenuStr));
multiChoiceView->appendItem(insertEjectMenuStr[0],
[this](TextMenuItem &, View &, Input::Event e)
{
addTapeFilePickerView(e);
postDraw();
popAndShow();
});
multiChoiceView.appendItem(insertEjectMenuStr[1],
multiChoiceView->appendItem(insertEjectMenuStr[1],
[this](TextMenuItem &, View &, Input::Event e)
{
plugin.tape_image_detach(1);
onTapeMediaChange();
popAndShow();
});
pushAndShow(multiChoiceView, e);
pushAndShow(std::move(multiChoiceView), e);
}
else
{
@@ -559,7 +559,8 @@ public:

void addCartFilePickerView(Input::Event e)
{
auto &fPicker = *EmuFilePicker::makeForMediaChange(attachParams(), e, EmuSystem::gamePath(), hasC64CartExtension,
EmuApp::pushAndShowModalView(
EmuFilePicker::makeForMediaChange(attachParams(), e, EmuSystem::gamePath(), hasC64CartExtension,
[this](FSPicker &picker, const char* name, Input::Event e)
{
auto path = picker.makePathString(name);
@@ -568,8 +569,7 @@ public:
onROMMediaChange();
}
picker.dismiss();
});
EmuApp::pushAndShowModalView(fPicker, e);
}), e);
}

private:
@@ -581,22 +581,22 @@ private:
auto cartFilename = plugin.cartridge_get_file_name(plugin.cart_getid_slotmain());
if(cartFilename && strlen(cartFilename))
{
auto &multiChoiceView = *new TextTableView{"Cartridge Slot", attachParams(), IG::size(insertEjectMenuStr)};
multiChoiceView.appendItem(insertEjectMenuStr[0],
auto multiChoiceView = makeViewWithName<TextTableView>("Cartridge Slot", IG::size(insertEjectMenuStr));
multiChoiceView->appendItem(insertEjectMenuStr[0],
[this](TextMenuItem &, View &, Input::Event e)
{
addCartFilePickerView(e);
postDraw();
popAndShow();
});
multiChoiceView.appendItem(insertEjectMenuStr[1],
multiChoiceView->appendItem(insertEjectMenuStr[1],
[this](TextMenuItem &, View &, Input::Event e)
{
plugin.cartridge_detach_image(-1);
onROMMediaChange();
popAndShow();
});
pushAndShow(multiChoiceView, e);
pushAndShow(std::move(multiChoiceView), e);
}
else
{
@@ -622,7 +622,8 @@ private:

void addDiskFilePickerView(Input::Event e, uint8 slot)
{
auto &fPicker = *EmuFilePicker::makeForMediaChange(attachParams(), e, EmuSystem::gamePath(), hasC64DiskExtension,
EmuApp::pushAndShowModalView(
EmuFilePicker::makeForMediaChange(attachParams(), e, EmuSystem::gamePath(), hasC64DiskExtension,
[this, slot](FSPicker &picker, const char* name, Input::Event e)
{
auto path = picker.makePathString(name);
@@ -632,8 +633,7 @@ private:
onDiskMediaChange(slot);
}
picker.dismiss();
});
EmuApp::pushAndShowModalView(fPicker, e);
}), e);
}

public:
@@ -642,22 +642,22 @@ public:
auto name = plugin.file_system_get_disk_name(slot+8);
if(name && strlen(name))
{
auto &multiChoiceView = *new TextTableView{"Disk Drive", attachParams(), IG::size(insertEjectMenuStr)};
multiChoiceView.appendItem(insertEjectMenuStr[0],
auto multiChoiceView = makeViewWithName<TextTableView>("Disk Drive", IG::size(insertEjectMenuStr));
multiChoiceView->appendItem(insertEjectMenuStr[0],
[this, slot](TextMenuItem &, View &, Input::Event e)
{
addDiskFilePickerView(e, slot);
postDraw();
popAndShow();
});
multiChoiceView.appendItem(insertEjectMenuStr[1],
multiChoiceView->appendItem(insertEjectMenuStr[1],
[this, slot](TextMenuItem &, View &, Input::Event e)
{
plugin.file_system_detach_disk(slot+8);
onDiskMediaChange(slot);
popAndShow();
});
pushAndShow(multiChoiceView, e);
pushAndShow(std::move(multiChoiceView), e);
}
else
{
@@ -978,8 +978,8 @@ class MachineOptionView : public TableView
{
if(!item.active())
return;
auto &multiChoiceView = *new TextTableView{item.t.str, attachParams(), 4};
multiChoiceView.appendItem("NTSC w/ True Drive Emu",
auto multiChoiceView = makeViewWithName<TextTableView>(item.t.str, 4);
multiChoiceView->appendItem("NTSC w/ True Drive Emu",
[this]()
{
popAndShow();
@@ -989,7 +989,7 @@ class MachineOptionView : public TableView
optionModel = defaultNTSCModel[currSystem];
EmuApp::reloadGame();
});
multiChoiceView.appendItem("NTSC",
multiChoiceView->appendItem("NTSC",
[this]()
{
popAndShow();
@@ -999,7 +999,7 @@ class MachineOptionView : public TableView
optionModel = defaultNTSCModel[currSystem];
EmuApp::reloadGame();
});
multiChoiceView.appendItem("PAL w/ True Drive Emu",
multiChoiceView->appendItem("PAL w/ True Drive Emu",
[this]()
{
popAndShow();
@@ -1009,7 +1009,7 @@ class MachineOptionView : public TableView
optionModel = defaultPALModel[currSystem];
EmuApp::reloadGame();
});
multiChoiceView.appendItem("PAL",
multiChoiceView->appendItem("PAL",
[this]()
{
popAndShow();
@@ -1019,7 +1019,7 @@ class MachineOptionView : public TableView
optionModel = defaultPALModel[currSystem];
EmuApp::reloadGame();
});
pushAndShow(multiChoiceView, e);
pushAndShow(std::move(multiChoiceView), e);
}
};

@@ -1078,8 +1078,7 @@ class CustomSystemActionsView : public EmuSystemActionsView
{
if(!item.active())
return;
auto &c64IoMenu = *new C64IOControlView{attachParams()};
pushAndShow(c64IoMenu, e);
pushAndShow(makeView<C64IOControlView>(), e);
}
};

@@ -1090,8 +1089,7 @@ class CustomSystemActionsView : public EmuSystemActionsView
{
if(EmuSystem::gameIsRunning())
{
auto &optionView = *new MachineOptionView{attachParams()};
pushAndShow(optionView, e);
pushAndShow(makeView<MachineOptionView>(), e);
}
}
};
@@ -1138,28 +1136,28 @@ class CustomMainMenuView : public EmuMainMenuView
if(hasSystem)
systems++;
}
auto &multiChoiceView = *new TextTableView{item.t.str, attachParams(), systems};
auto multiChoiceView = makeViewWithName<TextTableView>(item.t.str, systems);
iterateTimes(IG::size(systemPresent), i)
{
if(!systemPresent[i])
{
continue;
}
multiChoiceView.appendItem(VicePlugin::systemName((ViceSystem)i),
multiChoiceView->appendItem(VicePlugin::systemName((ViceSystem)i),
[this, i](TextMenuItem &, View &, Input::Event e)
{
optionViceSystem = i;
popAndShow();
auto &ynAlertView = *new YesNoAlertView{attachParams(), "Changing systems needs app restart, exit now?"};
ynAlertView.setOnYes(
auto ynAlertView = makeView<YesNoAlertView>("Changing systems needs app restart, exit now?");
ynAlertView->setOnYes(
[](TextMenuItem &, View &, Input::Event e)
{
Base::exit();
});
EmuApp::pushAndShowModalView(ynAlertView, e);
EmuApp::pushAndShowModalView(std::move(ynAlertView), e);
});
}
pushAndShow(multiChoiceView, e);
pushAndShow(std::move(multiChoiceView), e);
}
};

@@ -1181,8 +1179,8 @@ class CustomMainMenuView : public EmuMainMenuView
return 1;
}
string_copy(newDiskName, str);
auto &fPicker = *EmuFilePicker::makeForMediaCreation(attachParams(), Input::defaultEvent());
fPicker.setOnClose(
auto fPicker = EmuFilePicker::makeForMediaCreation(attachParams(), Input::defaultEvent());
fPicker->setOnClose(
[this](FSPicker &picker, Input::Event e)
{
auto path = FS::makePathStringPrintf("%s/%s.d64", picker.path().data(), newDiskName.data());
@@ -1209,11 +1207,11 @@ class CustomMainMenuView : public EmuMainMenuView
EmuApp::createSystemWithMedia({}, path.data(), "", e,
[this](Input::Event e)
{
EmuApp::launchSystemWithResumePrompt(renderer(), e, true);
EmuApp::launchSystemWithResumePrompt(e, true);
});
});
view.dismiss();
EmuApp::pushAndShowModalView(fPicker, Input::defaultEvent());
EmuApp::pushAndShowModalView(std::move(fPicker), Input::defaultEvent());
EmuApp::postMessage("Set directory to save disk");
}
else
@@ -1243,15 +1241,15 @@ public:
}
};

View *EmuApp::makeCustomView(ViewAttachParams attach, ViewID id)
std::unique_ptr<View> EmuApp::makeCustomView(ViewAttachParams attach, ViewID id)
{
switch(id)
{
case ViewID::MAIN_MENU: return new CustomMainMenuView(attach);
case ViewID::SYSTEM_ACTIONS: return new CustomSystemActionsView(attach);
case ViewID::VIDEO_OPTIONS: return new CustomVideoOptionView(attach);
case ViewID::AUDIO_OPTIONS: return new CustomAudioOptionView(attach);
case ViewID::SYSTEM_OPTIONS: return new CustomSystemOptionView(attach);
case ViewID::MAIN_MENU: return std::make_unique<CustomMainMenuView>(attach);
case ViewID::SYSTEM_ACTIONS: return std::make_unique<CustomSystemActionsView>(attach);
case ViewID::VIDEO_OPTIONS: return std::make_unique<CustomVideoOptionView>(attach);
case ViewID::AUDIO_OPTIONS: return std::make_unique<CustomAudioOptionView>(attach);
case ViewID::SYSTEM_OPTIONS: return std::make_unique<CustomSystemOptionView>(attach);
default: return nullptr;
}
}

+ 1
- 1
C64.emu/src/main/Main.cc View File

@@ -517,7 +517,7 @@ void EmuSystem::runFrame(EmuVideo *video, bool renderAudio)
execC64Frame();
if(video)
{
video->setFormat(canvasSrcPix);
video->setFormatLocked(canvasSrcPix);
video->startFrame(canvasSrcPix);
}
runningFrame = 0;

+ 1
- 0
C64.emu/src/main/input.cc View File

@@ -502,6 +502,7 @@ void EmuSystem::handleInputAction(uint state, uint emuKey)
if(unlikely((emuKey & 0xFF) == 0xFF))
{
logMsg("pushed restore key");
EmuApp::syncEmulationThread();
plugin.machine_set_restore_key(state == Input::PUSHED);
return;
}

+ 2
- 1
EmuFramework/build.mk View File

@@ -5,9 +5,9 @@ ifneq ($(filter linux ios android webos,$(ENV)),)
endif

SRC += CreditsView.cc \
MsgPopup.cc \
FilePicker.cc \
EmuSystem.cc \
EmuSystemTask.cc \
Screenshot.cc \
ButtonConfigView.cc \
VideoImageOverlay.cc \
@@ -18,6 +18,7 @@ EmuInput.cc \
EmuOptions.cc \
OptionView.cc \
EmuView.cc \
EmuViewController.cc \
ConfigFile.cc \
InputManagerView.cc \
FileUtils.cc \

+ 0
- 1
EmuFramework/include/emuframework/CreditsView.hh View File

@@ -36,5 +36,4 @@ public:
void draw(Gfx::RendererCommands &cmds) final;
void place() final;
bool inputEvent(Input::Event e) final;
void onAddedToController(Input::Event e) final {}
};

+ 6
- 4
EmuFramework/include/emuframework/EmuApp.hh View File

@@ -71,14 +71,13 @@ public:
pushAndShowNewYesNoAlertView(attach, e, label, yesStr, noStr,
TextMenuItem::wrapSelectDelegate(onYes), TextMenuItem::wrapSelectDelegate(onNo));
}
static void pushAndShowModalView(View &v, Input::Event e);
static void pushAndShowModalView(std::unique_ptr<View> v, Input::Event e);
static void popModalViews();
static void popMenuToRoot();
static void restoreMenuFromGame();
static void showSystemActionsViewFromSystem(ViewAttachParams attach, Input::Event e);
static void showLastViewFromSystem(ViewAttachParams attach, Input::Event e);
static void showExitAlert(ViewAttachParams attach, Input::Event e);
static void launchSystemWithResumePrompt(Gfx::Renderer &r, Input::Event e, bool addToRecent);
static void launchSystemWithResumePrompt(Input::Event e, bool addToRecent);
static bool hasArchiveExtension(const char *name);
static void setOnMainMenuItemOptionChanged(OnMainMenuOptionChanged func);
static void refreshCheatViews();
@@ -87,6 +86,8 @@ public:
static void postMessage(const char *msg);
static void postMessage(bool error, const char *msg);
static void postMessage(uint secs, bool error, const char *msg);
static void postErrorMessage(const char *msg);
static void postErrorMessage(uint secs, const char *msg);
static void unpostMessage();
static void saveAutoState();
static bool loadAutoState();
@@ -100,7 +101,7 @@ public:
static FS::PathString mediaSearchPath();
static FS::PathString firmwareSearchPath();
static void setFirmwareSearchPath(const char *path);
static View *makeCustomView(ViewAttachParams attach, ViewID id);
static std::unique_ptr<View> makeCustomView(ViewAttachParams attach, ViewID id);
static void addTurboInputEvent(uint action);
static void removeTurboInputEvent(uint action);
static FS::PathString assetPath();
@@ -116,4 +117,5 @@ public:
static void loadSessionOptions();
static bool hasSavedSessionOptions();
static void deleteSessionOptions();
static void syncEmulationThread();
};

+ 8
- 3
EmuFramework/include/emuframework/EmuInputView.hh View File

@@ -18,20 +18,25 @@
#include <imagine/gui/View.hh>
#include <emuframework/EmuVideo.hh>

class VController;

class EmuInputView : public View
{
public:
EmuInputView(ViewAttachParams attach): View(attach) {}
EmuInputView(ViewAttachParams attach, VController &vCtrl);
IG::WindowRect &viewRect() final { return rect; }
void place() final;
void draw(Gfx::RendererCommands &cmds) final;
bool inputEvent(Input::Event e) final;
void onAddedToController(Input::Event e) final {}
void resetInput();
void setTouchControlsOn(bool on);
bool touchControlsAreOn() const;

private:
bool ffKeyPushed = false, ffToggleActive = false;
VController &vController;
IG::WindowRect rect{};
bool touchControlsOn = false;
bool ffKeyPushed = false, ffToggleActive = false;

void updateFastforward();
};

+ 1
- 2
EmuFramework/include/emuframework/EmuLoadProgressView.hh View File

@@ -38,10 +38,9 @@ public:
void place() final;
bool inputEvent(Input::Event e) final;
void draw(Gfx::RendererCommands &cmds) final;
void onAddedToController(Input::Event e) final {}

// load context vars
Base::Pipe pipe;
Base::MessagePort<EmuSystem::LoadProgressMessage> msgPort;
Input::Event originalEvent{};
EmuApp::CreateSystemCompleteDelegate onComplete{};
};

+ 2
- 1
EmuFramework/include/emuframework/EmuSystem.hh View File

@@ -92,6 +92,7 @@ public:
constexpr LoadProgressMessage() {}
constexpr LoadProgressMessage(LoadProgress progress, int intArg, int intArg2, int intArg3):
intArg{intArg}, intArg2{intArg2}, intArg3{intArg3}, progress{progress} {}
explicit operator bool() const { return progress != LoadProgress::UNSET; }
int intArg{};
int intArg2{};
int intArg3{};
@@ -236,7 +237,7 @@ public:
static void pause();
static void start();
static void closeSystem();
static void closeGame(bool allowAutosaveState = 1);
static void closeRuntimeSystem(bool allowAutosaveState = 1);
[[gnu::format(printf, 1, 2)]]
static Error makeError(const char *msg, ...);
static Error makeError(std::error_code ec);

+ 3
- 0
EmuFramework/include/emuframework/EmuVideo.hh View File

@@ -55,16 +55,19 @@ class EmuVideo
public:
EmuVideo(Gfx::Renderer &r): r{r} {}
void setFormat(IG::PixmapDesc desc);
void setFormatLocked(IG::PixmapDesc desc);
void resetImage();
EmuVideoImage startFrame();
void startFrame(IG::Pixmap pix);
void finishFrame(Gfx::LockedTextureBuffer texBuff);
void finishFrame(IG::Pixmap pix);
void clear();
void takeGameScreenshot();
bool isExternalTexture();
Gfx::PixmapTexture &image();
Gfx::Renderer &renderer() { return r; }
IG::WP size() const;
bool formatIsEqual(IG::PixmapDesc desc) const;

protected:
Gfx::Renderer &r;

+ 4
- 1
EmuFramework/include/emuframework/EmuVideoLayer.hh View File

@@ -21,12 +21,13 @@
#include <emuframework/EmuVideo.hh>

struct AppWindowData;
class EmuInputView;

class EmuVideoLayer
{
public:
EmuVideoLayer(EmuVideo &video);
void place(const IG::WindowRect &viewportRect, const Gfx::ProjectionPlane &projP, bool onScreenControlsOverlay);
void place(const IG::WindowRect &viewportRect, const Gfx::ProjectionPlane &projP, EmuInputView *inputView);
void draw(Gfx::RendererCommands &cmds, const Gfx::ProjectionPlane &projP);
void setOverlay(uint effect);
void setOverlayIntensity(Gfx::GC intensity);
@@ -36,6 +37,7 @@ public:
void placeEffect();
void setLinearFilter(bool on);
void resetImage();
void setBrightness(float b);

const IG::WindowRect &gameRect() const
{
@@ -51,6 +53,7 @@ private:
Gfx::Sprite disp{};
IG::WindowRect gameRect_{};
Gfx::GCRect gameRectG{};
float brightness = 1.f;
bool useLinearFilter = true;

void compileDefaultPrograms();

+ 2
- 3
EmuFramework/include/emuframework/EmuView.hh View File

@@ -23,15 +23,14 @@
class EmuView : public View
{
public:
EmuView(ViewAttachParams attach, EmuVideoLayer *layer, EmuInputView *inputView);
EmuView(ViewAttachParams attach, EmuVideoLayer *layer);
IG::WindowRect &viewRect() final { return rect; }
void place() final;
void prepareDraw() final;
void draw(Gfx::RendererCommands &cmds) final;
bool inputEvent(Input::Event e) final;
void onAddedToController(Input::Event e) final {}
bool hasLayer() const { return layer; }
void swapLayers(EmuView &view);
void setLayoutInputView(EmuInputView *view);
void updateAudioStats(uint underruns, uint overruns, uint callbacks, double avgCallbackFrames, uint frames);
void clearAudioStats();


+ 4
- 4
EmuFramework/include/emuframework/FilePicker.hh View File

@@ -25,10 +25,10 @@ public:
EmuFilePicker(ViewAttachParams attach, const char *startingPath, bool pickingDir,
EmuSystem::NameFilterFunc filter, FS::RootPathInfo rootInfo,
Input::Event e, bool singleDir = false);
static EmuFilePicker *makeForBenchmarking(ViewAttachParams attach, Input::Event e, bool singleDir = false);
static EmuFilePicker *makeForLoading(ViewAttachParams attach, Input::Event e, bool singleDir = false);
static EmuFilePicker *makeForMediaChange(ViewAttachParams attach, Input::Event e, const char *path,
static std::unique_ptr<EmuFilePicker> makeForBenchmarking(ViewAttachParams attach, Input::Event e, bool singleDir = false);
static std::unique_ptr<EmuFilePicker> makeForLoading(ViewAttachParams attach, Input::Event e, bool singleDir = false);
static std::unique_ptr<EmuFilePicker> makeForMediaChange(ViewAttachParams attach, Input::Event e, const char *path,
EmuSystem::NameFilterFunc filter, FSPicker::OnSelectFileDelegate onSelect);
static EmuFilePicker *makeForMediaCreation(ViewAttachParams attach, Input::Event e, bool singleDir = false);
static std::unique_ptr<EmuFilePicker> makeForMediaCreation(ViewAttachParams attach, Input::Event e, bool singleDir = false);
bool inputEvent(Input::Event e) final;
};

+ 0
- 1
EmuFramework/include/emuframework/InputManagerView.hh View File

@@ -44,7 +44,6 @@ public:
void place() final;
bool inputEvent(Input::Event e) final;
void draw(Gfx::RendererCommands &cmds) final;
void onAddedToController(Input::Event e) final {}
};

class InputManagerView : public TableView

+ 2
- 2
EmuFramework/include/emuframework/OptionView.hh View File

@@ -182,8 +182,8 @@ class BiosSelectMenu : public TableView
public:
using BiosChangeDelegate = DelegateFunc<void ()>;

BiosSelectMenu(const char *name, FS::PathString *biosPathStr, BiosChangeDelegate onBiosChange,
EmuSystem::NameFilterFunc fsFilter, ViewAttachParams attach);
BiosSelectMenu(const char *name, ViewAttachParams attach, FS::PathString *biosPathStr, BiosChangeDelegate onBiosChange,
EmuSystem::NameFilterFunc fsFilter);

protected:
TextMenuItem selectFile{};

+ 1
- 1
EmuFramework/include/emuframework/Recent.hh View File

@@ -34,5 +34,5 @@ struct RecentGameInfo
return string_equal(path.data(), rhs.path.data());
}

void handleMenuSelection(Gfx::Renderer &r, TextMenuItem &, Input::Event e);
void handleMenuSelection(TextMenuItem &, Input::Event e);
};

+ 4
- 1
EmuFramework/include/emuframework/TouchConfigView.hh View File

@@ -20,9 +20,12 @@
#include <imagine/gui/TextTableView.hh>
#include <emuframework/EmuSystem.hh>

class VController;

class TouchConfigView : public TableView
{
public:
VController &vController;
#ifdef CONFIG_VCONTROLS_GAMEPAD
TextMenuItem touchCtrlItem[3];
MultiChoiceMenuItem touchCtrl;
@@ -83,7 +86,7 @@ public:
void refreshTouchConfigMenu();

public:
TouchConfigView(ViewAttachParams attach, const char *faceBtnName, const char *centerBtnName);
TouchConfigView(ViewAttachParams attach, VController &vController, const char *faceBtnName, const char *centerBtnName);
void place() final;
void draw(Gfx::RendererCommands &cmds) final;
};

+ 2
- 0
EmuFramework/include/emuframework/TurboInput.hh View File

@@ -32,8 +32,10 @@ struct TurboInput
};

std::array<Action, 5> activeAction{};
uint clock = 0;

constexpr TurboInput() {}
void addEvent(uint action);
void removeEvent(uint action);
void update();
};

+ 38
- 16
EmuFramework/include/emuframework/VController.hh View File

@@ -21,6 +21,19 @@
#include <cmath>

class VController;
struct AppWindowData;

struct VControllerLayoutPosition
{
enum { OFF = 0, SHOWN = 1, HIDDEN = 2 };
_2DOrigin origin{LT2DO};
uint state = OFF;
IG::Point2D<int> pos{};

constexpr VControllerLayoutPosition() {}
constexpr VControllerLayoutPosition(_2DOrigin origin, IG::Point2D<int> pos): origin(origin), pos(pos) {}
constexpr VControllerLayoutPosition(_2DOrigin origin, IG::Point2D<int> pos, uint state): origin(origin), state(state), pos(pos) {}
};

class VControllerDPad
{
@@ -28,13 +41,13 @@ public:
constexpr VControllerDPad() {}
void setImg(Gfx::Renderer &r, Gfx::PixmapTexture &dpadR, Gfx::GTexC texHeight);
void draw(Gfx::RendererCommands &cmds) const;
void setBoundingAreaVisible(Gfx::Renderer &r, bool on);
void setBoundingAreaVisible(Gfx::Renderer &r, bool on, const AppWindowData &winData);
int getInput(IG::WP c) const;
IG::WindowRect bounds() const;
void setPos(IG::Point2D<int> pos);
void setSize(Gfx::Renderer &r, uint sizeInPixels);
void setDeadzone(Gfx::Renderer &r, int newDeadzone);
void setDiagonalSensitivity(Gfx::Renderer &r, float newDiagonalSensitivity);
void setPos(IG::Point2D<int> pos, const AppWindowData &winData);
void setSize(Gfx::Renderer &r, uint sizeInPixels, const AppWindowData &winData);
void setDeadzone(Gfx::Renderer &r, int newDeadzone, const AppWindowData &winData);
void setDiagonalSensitivity(Gfx::Renderer &r, float newDiagonalSensitivity, const AppWindowData &winData);
uint state() const { return state_; }
void setState(uint state) { state_ = state; }

@@ -50,7 +63,7 @@ protected:
bool visualizeBounds = 0;
int btnSizePixels = 0;

void updateBoundingAreaGfx(Gfx::Renderer &r);
void updateBoundingAreaGfx(Gfx::Renderer &r, const AppWindowData &winData);
};

class VControllerKeyboard
@@ -65,7 +78,7 @@ public:
constexpr VControllerKeyboard() {}
void updateImg(Gfx::Renderer &r);
void setImg(Gfx::Renderer &r, Gfx::PixmapTexture *img);
void place(Gfx::GC btnSize, Gfx::GC yOffset);
void place(Gfx::GC btnSize, Gfx::GC yOffset, const AppWindowData &winData);
void draw(Gfx::RendererCommands &cmds, const Gfx::ProjectionPlane &projP) const;
int getInput(IG::WP c) const;
int translateInput(uint idx) const;
@@ -97,23 +110,23 @@ public:
static constexpr uint MAX_FACE_BTNS = 8;

constexpr VControllerGamepad(uint faceButtons): activeFaceBtns{faceButtons} {}
void setBoundingAreaVisible(Gfx::Renderer &r, bool on);
void setBoundingAreaVisible(Gfx::Renderer &r, bool on, const AppWindowData &winData);
bool boundingAreaVisible() const;
void setImg(Gfx::Renderer &r, Gfx::PixmapTexture &pics);
uint rowsForButtons(uint activeButtons);
void setBaseBtnSize(Gfx::Renderer &r, uint sizeInPixels);
void setBaseBtnSize(Gfx::Renderer &r, uint sizeInPixels, const AppWindowData &winData);
IG::WindowRect centerBtnBounds() const;
void setCenterBtnPos(IG::Point2D<int> pos);
void setCenterBtnPos(IG::Point2D<int> pos, const AppWindowData &winData);
IG::WindowRect lTriggerBounds() const;
void setLTriggerPos(IG::Point2D<int> pos);
void setLTriggerPos(IG::Point2D<int> pos, const AppWindowData &winData);
IG::WindowRect rTriggerBounds() const;
void setRTriggerPos(IG::Point2D<int> pos);
void layoutBtnRows(uint a[], uint btns, uint rows, IG::Point2D<int> pos);
void setRTriggerPos(IG::Point2D<int> pos, const AppWindowData &winData);
void layoutBtnRows(uint a[], uint btns, uint rows, IG::Point2D<int> pos, const AppWindowData &winData);
IG::WindowRect faceBtnBounds() const;
void setFaceBtnPos(IG::Point2D<int> pos);
void setFaceBtnPos(IG::Point2D<int> pos, const AppWindowData &winData);
std::array<int, 2> getCenterBtnInput(IG::WP pos) const;
std::array<int, 2> getBtnInput(IG::WP pos) const;
void draw(Gfx::RendererCommands &cmds, bool showHidden) const;
void draw(Gfx::RendererCommands &cmds, bool showHidden, const AppWindowData &winData) const;
VControllerDPad &dPad() { return dp; }
const VControllerDPad &dPad() const { return dp; }
Gfx::GC spacing() const { return btnSpace; }
@@ -168,8 +181,10 @@ public:
static constexpr uint TURBO_BIT = IG::bit(31), ACTION_MASK = 0x7FFFFFFF;
using Map = std::array<uint, D_ELEM+9>;
using KbMap = VControllerKeyboard::KbMap;
using VControllerLayoutPositionArr = std::array<std::array<VControllerLayoutPosition, 7>, 2>;

constexpr VController(Gfx::Renderer &r, uint faceButtons): renderer_{r}
constexpr VController(Gfx::Renderer &r, AppWindowData &winData, uint faceButtons):
renderer_{r}, winData{&winData}
#ifdef CONFIG_VCONTROLS_GAMEPAD
,gp{faceButtons}
#endif
@@ -212,9 +227,14 @@ public:
void setAlpha(float val);
VControllerGamepad &gamePad();
Gfx::Renderer &renderer();
const AppWindowData &windowData() const { return *winData; }
VControllerLayoutPositionArr &layoutPosition() { return layoutPos; };
bool layoutPositionChanged() const { return layoutPosChanged; };
void setLayoutPositionChanged(bool changed = true) { layoutPosChanged = changed; }

private:
Gfx::Renderer &renderer_;
const AppWindowData *winData;

#ifdef CONFIG_VCONTROLS_GAMEPAD
VControllerGamepad gp;
@@ -227,7 +247,9 @@ private:
static constexpr bool useScaledCoordinates = false;
#endif

bool layoutPosChanged = false;
float alpha = 0;
VControllerLayoutPositionArr layoutPos;

// menu button
Gfx::Sprite menuBtnSpr{};

+ 3
- 3
EmuFramework/src/BundledGamesView.cc View File

@@ -38,7 +38,7 @@ BundledGamesView::BundledGamesView(ViewAttachParams attach):
{
auto &info = EmuSystem::bundledGameInfo(0);
game[0] = {info.displayName,
[&info, &r = attach.renderer](TextMenuItem &t, View &view, Input::Event e)
[&info](TextMenuItem &t, View &view, Input::Event e)
{
auto file = EmuApp::openAppAssetIO(info.assetName, IO::AccessHint::ALL);
if(!file)
@@ -47,9 +47,9 @@ BundledGamesView::BundledGamesView(ViewAttachParams attach):
return;
}
EmuApp::createSystemWithMedia(file.makeGeneric(), "", info.assetName, e,
[&r](Input::Event e)
[](Input::Event e)
{
EmuApp::launchSystemWithResumePrompt(r, e, false);
EmuApp::launchSystemWithResumePrompt(e, false);
});
}};
}

+ 31
- 24
EmuFramework/src/ButtonConfigView.cc View File

@@ -52,6 +52,7 @@ void ButtonConfigSetView::initPointerUI()
if(!pointerUIIsInit())
{
logMsg("init pointer UI elements");
auto lock = makeControllerMutexLock();
unbind = {"Unbind", &View::defaultFace};
cancel = {"Cancel", &View::defaultFace};
unbindB.x2 = 1;
@@ -135,19 +136,19 @@ bool ButtonConfigSetView::inputEvent(Input::Event e)
{
if(d == savedDev)
{
popup.clear();
EmuApp::unpostMessage();
auto &rootIMView = this->rootIMView;
auto attach = attachParams();
dismiss();
viewStack.popTo(rootIMView);
auto &imdMenu = *new InputManagerDeviceView{attach, rootIMView, inputDevConf[d->idx]};
imdMenu.setName(rootIMView.deviceName(d->idx));
rootIMView.pushAndShow(imdMenu, e);
emuViewController.popTo(rootIMView);
auto imdMenu = std::make_unique<InputManagerDeviceView>(attach, rootIMView, inputDevConf[d->idx]);
imdMenu->setName(rootIMView.deviceName(d->idx));
rootIMView.pushAndShow(std::move(imdMenu), e);
}
else
{
savedDev = d;
popup.printf(7, 0, "You pushed a key from device:\n%s\nPush another from it to open its config menu", rootIMView.deviceName(d->idx));
EmuApp::printfMessage(7, false, "You pushed a key from device:\n%s\nPush another from it to open its config menu", rootIMView.deviceName(d->idx));
postDraw();
}
return true;
@@ -251,8 +252,11 @@ void ButtonConfigView::onSet(Input::Key mapKey, int keyToSet)
if(!devConf->setKey(mapKey, *cat, keyToSet))
return;
auto &b = btn[keyToSet];
b.str = makeKeyNameStr(mapKey, devConf->dev->keyName(mapKey));
b.item.t2.compile(renderer(), projP);
{
auto lock = makeControllerMutexLock();
b.str = makeKeyNameStr(mapKey, devConf->dev->keyName(mapKey));
b.item.t2.compile(renderer(), projP);
}
keyMapping.buildAll();
}

@@ -306,8 +310,8 @@ ButtonConfigView::ButtonConfigView(ViewAttachParams attach, InputManagerView &ro
"Unbind All",
[this](TextMenuItem &t, View &, Input::Event e)
{
auto &ynAlertView = *new YesNoAlertView{attachParams(), "Really unbind all keys in this category?"};
ynAlertView.setOnYes(
auto ynAlertView = makeView<YesNoAlertView>("Really unbind all keys in this category?");
ynAlertView->setOnYes(
[this](TextMenuItem &, View &view, Input::Event e)
{
view.dismiss();
@@ -315,14 +319,17 @@ ButtonConfigView::ButtonConfigView(ViewAttachParams attach, InputManagerView &ro
if(!conf)
return;
conf->unbindCategory(*cat);
iterateTimes(cat->keys, i)
{
string_copy(btn[i].str, devConf->dev->keyName(devConf->keyConf().key(*cat)[i]));
btn[i].item.t2.compile(renderer(), projP);
auto lock = makeControllerMutexLock();
iterateTimes(cat->keys, i)
{
string_copy(btn[i].str, devConf->dev->keyName(devConf->keyConf().key(*cat)[i]));
btn[i].item.t2.compile(renderer(), projP);
}
}
keyMapping.buildAll();
});
modalViewController.pushAndShow(ynAlertView, e, false);
emuViewController.pushAndShowModal(std::move(ynAlertView), e, false);
}
}
{
@@ -340,7 +347,7 @@ ButtonConfigView::ButtonConfigView(ViewAttachParams attach, InputManagerView &ro
[this, i](DualTextMenuItem &item, View &, Input::Event e)
{
auto keyToSet = i;
auto &btnSetView = *new ButtonConfigSetView{attachParams(), rootIMView,
auto btnSetView = makeView<ButtonConfigSetView>(rootIMView,
*devConf->dev, btn[keyToSet].item.t.str,
[this, keyToSet](Input::Event e)
{
@@ -356,10 +363,10 @@ ButtonConfigView::ButtonConfigView(ViewAttachParams attach, InputManagerView &ro
string_printf(conflictStr, "Key \"%s\" already used for action \"%s\", unbind it before setting?",
devConf->dev->keyName(mapKey),
conflictCat->keyName[conflictKey]);
auto &alertView = *new KeyConflictAlertView{attachParams(), conflictStr.data()};
alertView.ctx = {mapKey, keyToSet, conflictCat, conflictKey};
alertView.setItem(0, "Yes",
[this, ctx = &alertView.ctx](TextMenuItem &, View &view, Input::Event)
auto alertView = makeView<KeyConflictAlertView>(conflictStr.data());
alertView->ctx = {mapKey, keyToSet, conflictCat, conflictKey};
alertView->setItem(0, "Yes",
[this, ctx = &alertView->ctx](TextMenuItem &, View &view, Input::Event)
{
if(ctx->conflictCat == this->cat)
onSet(0, ctx->conflictKey);
@@ -368,19 +375,19 @@ ButtonConfigView::ButtonConfigView(ViewAttachParams attach, InputManagerView &ro
onSet(ctx->mapKey, ctx->keyToSet);
view.dismiss();
});
alertView.setItem(1, "No",
[this, ctx = &alertView.ctx](TextMenuItem &, View &view, Input::Event)
alertView->setItem(1, "No",
[this, ctx = &alertView->ctx](TextMenuItem &, View &view, Input::Event)
{
onSet(ctx->mapKey, ctx->keyToSet);
view.dismiss();
});
modalViewController.pushAndShow(alertView, e, false);
emuViewController.pushAndShowModal(std::move(alertView), e, false);
return;
}
}
onSet(mapKey, keyToSet);
}};
modalViewController.pushAndShow(btnSetView, e, false);
});
emuViewController.pushAndShowModal(std::move(btnSetView), e, false);
});
}
}

+ 5
- 3
EmuFramework/src/Cheats.cc View File

@@ -42,8 +42,7 @@ BaseCheatsView::BaseCheatsView(ViewAttachParams attach):
"Add/Edit",
[this](TextMenuItem &item, View &, Input::Event e)
{
auto &editCheatListView = *makeView(attachParams(), EmuApp::ViewID::EDIT_CHEATS);
pushAndShow(editCheatListView, e);
pushAndShow(makeEmuView(attachParams(), EmuApp::ViewID::EDIT_CHEATS), e);
}
},
onRefreshCheats
@@ -87,7 +86,10 @@ BaseEditCheatView::BaseEditCheatView(const char *viewName, ViewAttachParams atta
{
logMsg("setting cheat name %s", str);
renamed(str);
name.compile(renderer(), projP);
{
auto lock = makeControllerMutexLock();
name.compile(renderer(), projP);
}
window().postDraw();
}
view.dismiss();

+ 116
- 812
EmuFramework/src/EmuApp.cc
File diff suppressed because it is too large
View File


+ 43
- 77
EmuFramework/src/EmuInput.cc View File

@@ -36,11 +36,6 @@ std::vector<InputDeviceConfig> inputDevConf{};
std::list<InputDeviceSavedConfig> savedInputDevList{};
std::list<KeyConfig> customKeyConfig{};
KeyMapping keyMapping{};
bool physicalControlsPresent = false;
bool touchControlsAreOn = false;
VControllerLayoutPosition vControllerLayoutPos[2][7];
bool vControllerLayoutPosChanged = false;
bool fastForwardActive = false;

#ifdef CONFIG_VCONTROLS_GAMEPAD
static Gfx::GC vControllerGCSize()
@@ -48,31 +43,32 @@ static Gfx::GC vControllerGCSize()
return vController.xMMSize(int(optionTouchCtrlSize) / 100.);
}

static int vControllerPixelSize()
static int vControllerPixelSize(const Base::Window &win)
{
return IG::makeEvenRoundedUp(vController.xMMSizeToPixel(mainWin.win, int(optionTouchCtrlSize) / 100.));
return IG::makeEvenRoundedUp(vController.xMMSizeToPixel(win, int(optionTouchCtrlSize) / 100.));
}
#endif

void initVControls(Gfx::Renderer &r)
{
auto &winData = vController.windowData();
#ifdef CONFIG_VCONTROLS_GAMEPAD
auto &gp = vController.gamePad();
gp.dPad().setDeadzone(r, vController.xMMSizeToPixel(mainWin.win, int(optionTouchDpadDeadzone) / 100.));
gp.dPad().setDiagonalSensitivity(r, optionTouchDpadDiagonalSensitivity / 1000.);
gp.dPad().setDeadzone(r, vController.xMMSizeToPixel(winData.win, int(optionTouchDpadDeadzone) / 100.), vController.windowData());
gp.dPad().setDiagonalSensitivity(r, optionTouchDpadDiagonalSensitivity / 1000., vController.windowData());
vController.setBoundingAreaVisible(optionTouchCtrlBoundingBoxes);
vController.init((int)optionTouchCtrlAlpha / 255.0, vControllerPixelSize(), View::defaultFace.nominalHeight()*1.75, mainWin.projectionPlane);
vController.init((int)optionTouchCtrlAlpha / 255.0, vControllerPixelSize(winData.win), View::defaultFace.nominalHeight()*1.75, winData.projectionPlane);
#else
vController.init((int)optionTouchCtrlAlpha / 255.0, IG::makeEvenRoundedUp(vController.xMMSizeToPixel(mainWin.win, 8.5)), View::defaultFace.nominalHeight()*1.75, mainWin.projectionPlane);
vController.init((int)optionTouchCtrlAlpha / 255.0, IG::makeEvenRoundedUp(vController.xMMSizeToPixel(winData.win, 8.5)), View::defaultFace.nominalHeight()*1.75, winData.projectionPlane);
#endif

if(!vControllerLayoutPosChanged) // setup default positions if not provided in config file
if(!vController.layoutPositionChanged()) // setup default positions if not provided in config file
resetVControllerPositions();
#ifdef CONFIG_VCONTROLS_GAMEPAD
if((int)optionTouchCtrl == 2)
EmuControls::updateAutoOnScreenControlVisible();
emuViewController.updateAutoOnScreenControlVisible();
else
EmuControls::setOnScreenControls(optionTouchCtrl);
emuViewController.setOnScreenControls(optionTouchCtrl);
#endif
vController.updateMapping(0);
}
@@ -80,7 +76,7 @@ void initVControls(Gfx::Renderer &r)
void resetVControllerPositions()
{
logMsg("resetting on-screen controls to default positions & states");
auto &win = mainWin.win;
auto &win = vController.windowData().win;
uint initFastForwardState = (Config::envIsIOS || (Config::envIsAndroid && !Base::hasHardwareNavButtons()) || Config::envIsWebOS3)
? VControllerLayoutPosition::SHOWN : VControllerLayoutPosition::OFF;
uint initMenuState = ((Config::envIsWebOS && !Config::envIsWebOS3) || (Config::envIsAndroid && Base::hasHardwareNavButtons()))
@@ -91,13 +87,13 @@ void resetVControllerPositions()
uint initGamepadState = VControllerLayoutPosition::OFF;
#endif
bool isLandscape = true;
for(auto &e : vControllerLayoutPos)
for(auto &e : vController.layoutPosition())
{
#ifdef CONFIG_VCONTROLS_GAMEPAD
int xOffset = isLandscape ? vController.xMMSizeToPixel(win, 2.) : vController.xMMSizeToPixel(win, .5);
e[VCTRL_LAYOUT_DPAD_IDX] = {LB2DO, {xOffset + vController.bounds(0).xSize()/2, (int)(-vControllerPixelSize()) - vController.bounds(0).ySize()/2}, initGamepadState};
e[VCTRL_LAYOUT_DPAD_IDX] = {LB2DO, {xOffset + vController.bounds(0).xSize()/2, (int)(-vControllerPixelSize(win)) - vController.bounds(0).ySize()/2}, initGamepadState};
e[VCTRL_LAYOUT_CENTER_BTN_IDX] = {CB2DO, {0, 0}, initGamepadState};
e[VCTRL_LAYOUT_FACE_BTN_GAMEPAD_IDX] = {RB2DO, {-xOffset - vController.bounds(2).xSize()/2, (int)(-vControllerPixelSize()) - vController.bounds(2).ySize()/2}, initGamepadState};
e[VCTRL_LAYOUT_FACE_BTN_GAMEPAD_IDX] = {RB2DO, {-xOffset - vController.bounds(2).xSize()/2, (int)(-vControllerPixelSize(win)) - vController.bounds(2).ySize()/2}, initGamepadState};
#endif
e[VCTRL_LAYOUT_MENU_IDX] = {RT2DO, {0, 0}, initMenuState};
e[VCTRL_LAYOUT_FF_IDX] = {LT2DO, {0, 0}, initFastForwardState};
@@ -112,7 +108,7 @@ void resetVControllerPositions()
#endif
isLandscape = false;
};
vControllerLayoutPosChanged = false;
vController.setLayoutPositionChanged(false);
}

void resetVControllerOptions()
@@ -145,17 +141,15 @@ void resetAllVControllerOptions()
#endif
resetVControllerOptions();
optionTouchCtrlAlpha.reset();
EmuControls::updateAutoOnScreenControlVisible();
emuViewController.updateAutoOnScreenControlVisible();
vController.updateMapping(pointerInputPlayer);
}

VControllerLayoutPosition vControllerPixelToLayoutPos(IG::Point2D<int> pos, IG::Point2D<int> size)
VControllerLayoutPosition vControllerPixelToLayoutPos(IG::Point2D<int> pos, IG::Point2D<int> size, IG::WindowRect viewBounds)
{
auto &win = mainWin.win;
IG::WindowRect bound { pos.x - size.x/2, pos.y - size.y/2, pos.x + size.x/2, pos.y + size.y/2 };

const auto &viewport = mainWin.viewport();
const auto &rect = viewport.bounds();
const auto &rect = viewBounds;
IG::WindowRect ltQuadrantRect{rect.x, rect.y, rect.xCenter(), rect.yCenter()};
IG::WindowRect rtQuadrantRect{rect.xCenter(), rect.y, rect.x2, rect.yCenter()};
IG::WindowRect lbQuadrantRect{rect.x, rect.yCenter(), rect.xCenter(), rect.y2};
@@ -175,15 +169,14 @@ VControllerLayoutPosition vControllerPixelToLayoutPos(IG::Point2D<int> pos, IG::
else if(lbQuadrant) origin = LB2DO;
else if(rbQuadrant) origin = RB2DO;

int x = (origin.xScaler() == 0) ? pos.x - viewport.width()/2 :
(origin.xScaler() == 1) ? pos.x - viewport.width() : pos.x;
int y = LT2DO.adjustY(pos.y, (int)viewport.height(), origin);
int x = (origin.xScaler() == 0) ? pos.x - rect.xSize()/2 :
(origin.xScaler() == 1) ? pos.x - rect.xSize() : pos.x;
int y = LT2DO.adjustY(pos.y, rect.ySize(), origin);
return {origin, {x, y}};
}

IG::Point2D<int> vControllerLayoutToPixelPos(VControllerLayoutPosition lPos)
IG::Point2D<int> vControllerLayoutToPixelPos(VControllerLayoutPosition lPos, Gfx::Viewport viewport)
{
const auto &viewport = mainWin.viewport();
int x = (lPos.origin.xScaler() == 0) ? lPos.pos.x + viewport.width()/2 :
(lPos.origin.xScaler() == 1) ? lPos.pos.x + viewport.width() : lPos.pos.x;
int y = lPos.origin.adjustY(lPos.pos.y, (int)viewport.height(), LT2DO);
@@ -230,34 +223,35 @@ void commonInitInput()
{
relPtr = {};
turboActions = {};
fastForwardActive = false;
emuSystemTask.setFastForwardActive(false);
}

void commonUpdateInput()
void TurboInput::update()
{
using namespace IG;
static const uint turboFrames = 4;
static uint turboClock = 0;

for(auto e : turboActions.activeAction)
for(auto e : activeAction)
{
if(e.action)
{
if(turboClock == 0)
if(clock == 0)
{
//logMsg("turbo push for player %d, action %d", e.player, e.action);
EmuSystem::handleInputAction(Input::PUSHED, e.action);
}
else if(turboClock == turboFrames/2)
else if(clock == turboFrames/2)
{
//logMsg("turbo release for player %d, action %d", e.player, e.action);
EmuSystem::handleInputAction(Input::RELEASED, e.action);
}
}
}
turboClock++;
if(turboClock == turboFrames) turboClock = 0;
clock++;
if(clock == turboFrames) clock = 0;
}

void commonUpdateInput()
{
#ifdef CONFIG_INPUT_RELATIVE_MOTION_DEVICES
auto applyRelPointerDecel =
[](int val)
@@ -289,7 +283,7 @@ bool isMenuDismissKey(Input::Event e)
dismissKey = Keycode::RCTRL;
if(Config::MACHINE_IS_PANDORA && e.device()->subtype() == Device::SUBTYPE_PANDORA_HANDHELD)
{
if(modalViewController.size()) // make sure not performing text input
if(emuViewController.hasModalView()) // make sure not performing text input
return false;
dismissKey = Keycode::SPACE;
}
@@ -314,11 +308,7 @@ void updateInputDevices()
}
i++;
}
physicalControlsPresent = Input::keyInputIsPresent();
if(physicalControlsPresent)
{
logMsg("Physical controls are present");
}
emuViewController.setPhysicalControlsPresent(Input::keyInputIsPresent());
onUpdateInputDevices.callCopySafe();
keyMapping.buildAll();
}
@@ -524,7 +514,7 @@ KeyConfig *InputDeviceConfig::makeMutableKeyConf()
char name[96];
uniqueCustomConfigName(name);
conf = setKeyConfCopiedFromExisting(name);
popup.printf(3, 0, "Automatically created profile: %s", conf->name);
EmuApp::printfMessage(3, false, "Automatically created profile: %s", conf->name);
}
return conf;
}
@@ -687,13 +677,14 @@ void genericMultiplayerTranspose(KeyConfig::KeyArray &key, uint player, uint sta
#ifdef CONFIG_EMUFRAMEWORK_VCONTROLS
void setupVControllerVars()
{
auto &winData = vController.windowData();
#ifdef CONFIG_VCONTROLS_GAMEPAD
Gfx::GC btnSize = vControllerGCSize();
int btnSizePixels = vControllerPixelSize();
int btnSizePixels = vControllerPixelSize(winData.win);
auto &gp = vController.gamePad();
logMsg("set on-screen button size: %f, %d pixels", (double)btnSize, btnSizePixels);
gp.setSpacing(vController.xMMSize(int(optionTouchCtrlBtnSpace) / 100.));
gp.setSpacingPixels(IG::makeEvenRoundedUp(vController.xMMSizeToPixel(mainWin.win, int(optionTouchCtrlBtnSpace) / 100.)));
gp.setSpacingPixels(IG::makeEvenRoundedUp(vController.xMMSizeToPixel(winData.win, int(optionTouchCtrlBtnSpace) / 100.)));
gp.setRowShift(0);
gp.setRowShiftPixels(0);
gp.setExtraXSize(optionTouchCtrlExtraXBtnSize / 1000.);
@@ -723,46 +714,21 @@ void setupVControllerVars()
gp.setRowShift(-(btnSize + gp.spacing()));
gp.setRowShiftPixels(-(btnSizePixels + gp.spacingPixels()));
}
vController.setBaseBtnSize(vControllerPixelSize(), View::defaultFace.nominalHeight()*1.75, mainWin.projectionPlane);
vController.setBaseBtnSize(vControllerPixelSize(winData.win), View::defaultFace.nominalHeight()*1.75, winData.projectionPlane);
vController.setBoundingAreaVisible(optionTouchCtrlBoundingBoxes);
#else
vController.init((int)optionTouchCtrlAlpha / 255.0, IG::makeEvenRoundedUp(vController.xMMSizeToPixel(mainWin.win, 8.5)), View::defaultFace.nominalHeight()*1.75, mainWin.projectionPlane);
vController.init((int)optionTouchCtrlAlpha / 255.0, IG::makeEvenRoundedUp(vController.xMMSizeToPixel(winData.win, 8.5)), View::defaultFace.nominalHeight()*1.75, winData.projectionPlane);
#endif

auto &layoutPos = vControllerLayoutPos[mainWin.viewport().isPortrait() ? 1 : 0];
auto &layoutPos = vController.layoutPosition()[winData.viewport().isPortrait() ? 1 : 0];
iterateTimes(vController.numElements(), i)
{
vController.setPos(i, vControllerLayoutToPixelPos(layoutPos[i]));
vController.setPos(i, vControllerLayoutToPixelPos(layoutPos[i], winData.viewport()));
vController.setState(i, layoutPos[i].state);
}
}
#endif

void setOnScreenControls(bool on)
{
touchControlsAreOn = on;
placeEmuViews();
}

void updateAutoOnScreenControlVisible()
{
#ifdef CONFIG_VCONTROLS_GAMEPAD
if((uint)optionTouchCtrl == 2)
{
if(touchControlsAreOn && physicalControlsPresent)
{
logMsg("auto-turning off on-screen controls");
setOnScreenControls(0);
}
else if(!touchControlsAreOn && !physicalControlsPresent)
{
logMsg("auto-turning on on-screen controls");
setOnScreenControls(1);
}
}
#endif
}

void updateVControlImg()
{
auto &r = vController.renderer();
@@ -800,7 +766,7 @@ void setActiveFaceButtons(uint btns)
vController.gamePad().setActiveFaceButtons(btns);
setupVControllerVars();
vController.place();
EmuSystem::clearInputBuffers(emuInputView);
EmuSystem::clearInputBuffers(emuViewController.inputView());
#endif
}


+ 35
- 23
EmuFramework/src/EmuInputView.cc View File

@@ -22,11 +22,14 @@
#include "private.hh"
#include "privateInput.hh"

extern bool touchControlsAreOn;
EmuInputView::EmuInputView(ViewAttachParams attach, SysVController &vCtrl)
: View(attach), vController{vCtrl}
{}

void EmuInputView::draw(Gfx::RendererCommands &cmds)
{
vController.draw(cmds, touchControlsAreOn && EmuSystem::touchControlsApplicable(), ffKeyPushed || ffToggleActive);
cmds.loadTransform(projP.makeTranslate());
vController.draw(cmds, touchControlsOn && EmuSystem::touchControlsApplicable(), ffKeyPushed || ffToggleActive);
}

void EmuInputView::place()
@@ -47,7 +50,7 @@ void EmuInputView::resetInput()

void EmuInputView::updateFastforward()
{
fastForwardActive = ffKeyPushed || ffToggleActive;
emuSystemTask.setFastForwardActive(ffKeyPushed || ffToggleActive);
}

bool EmuInputView::inputEvent(Input::Event e)
@@ -65,7 +68,7 @@ bool EmuInputView::inputEvent(Input::Event e)
ffToggleActive ^= true;
updateFastforward();
}
else if((touchControlsAreOn && EmuSystem::touchControlsApplicable())
else if((touchControlsOn && EmuSystem::touchControlsApplicable())
|| vController.isInKeyboardMode())
{
vController.applyInput(e);
@@ -76,14 +79,14 @@ bool EmuInputView::inputEvent(Input::Event e)
//logMsg("game consumed pointer input event");
}
#ifdef CONFIG_VCONTROLS_GAMEPAD
else if(!touchControlsAreOn && (uint)optionTouchCtrl == 2 && optionTouchCtrlShowOnTouch
else if(!touchControlsOn && (uint)optionTouchCtrl == 2 && optionTouchCtrlShowOnTouch
&& !vController.isInKeyboardMode()
&& e.isTouch() && e.pushed()
)
{
logMsg("turning on on-screen controls from touch input");
touchControlsAreOn = 1;
placeEmuViews();
touchControlsOn = true;
emuViewController.placeEmuViews();
}
#endif
return true;
@@ -135,10 +138,8 @@ bool EmuInputView::inputEvent(Input::Event e)
if(e.pushed())
{
logMsg("show load game view from key event");
EmuApp::restoreMenuFromGame();
viewStack.popToRoot();
auto &fPicker = *EmuFilePicker::makeForLoading(attachParams(), e);
pushAndShow(fPicker, e, false);
emuViewController.popToRoot();
pushAndShow(EmuFilePicker::makeForLoading(attachParams(), e), e, false);
return true;
}

@@ -159,34 +160,34 @@ bool EmuInputView::inputEvent(Input::Event e)
if(auto err = EmuApp::saveStateWithSlot(EmuSystem::saveStateSlot);
err)
{
popup.printf(4, true, "Save State: %s", err->what());
EmuApp::printfMessage(4, true, "Save State: %s", err->what());
}
else
popup.post("State Saved");
EmuApp::postMessage("State Saved");
};

if(EmuSystem::shouldOverwriteExistingState())
{
EmuApp::syncEmulationThread();
doSaveState();
}
else
{
auto &ynAlertView = *new YesNoAlertView{attachParams(), "Really Overwrite State?"};
ynAlertView.setOnYes(
auto ynAlertView = makeView<YesNoAlertView>("Really Overwrite State?");
ynAlertView->setOnYes(
[](TextMenuItem &, View &view, Input::Event e)
{
view.dismiss();
doSaveState();
startGameFromMenu();
emuViewController.showEmulation();
});
ynAlertView.setOnNo(
ynAlertView->setOnNo(
[](TextMenuItem &, View &view, Input::Event e)
{
view.dismiss();
startGameFromMenu();
emuViewController.showEmulation();
});
modalViewController.pushAndShow(ynAlertView, e, false);
EmuApp::restoreMenuFromGame();
emuViewController.pushAndShowModal(std::move(ynAlertView), e, false);
}
return true;
}
@@ -194,10 +195,11 @@ bool EmuInputView::inputEvent(Input::Event e)
bcase guiKeyIdxLoadState:
if(e.pushed())
{
EmuApp::syncEmulationThread();
if(auto err = EmuApp::loadStateWithSlot(EmuSystem::saveStateSlot);
err)
{
popup.printf(4, true, "Load State: %s", err->what());
EmuApp::printfMessage(4, true, "Load State: %s", err->what());
}
return true;
}
@@ -208,7 +210,7 @@ bool EmuInputView::inputEvent(Input::Event e)
EmuSystem::saveStateSlot--;
if(EmuSystem::saveStateSlot < -1)
EmuSystem::saveStateSlot = 9;
popup.printf(1, 0, "State Slot: %s", stateNameStr(EmuSystem::saveStateSlot));
EmuApp::printfMessage(1, false, "State Slot: %s", stateNameStr(EmuSystem::saveStateSlot));
}

bcase guiKeyIdxIncStateSlot:
@@ -218,7 +220,7 @@ bool EmuInputView::inputEvent(Input::Event e)
EmuSystem::saveStateSlot++;
if(EmuSystem::saveStateSlot > 9)
EmuSystem::saveStateSlot = -1;
popup.printf(1, 0, "State Slot: %s", stateNameStr(EmuSystem::saveStateSlot));
EmuApp::printfMessage(1, false, "State Slot: %s", stateNameStr(EmuSystem::saveStateSlot));
}

bcase guiKeyIdxGameScreenshot:
@@ -263,3 +265,13 @@ bool EmuInputView::inputEvent(Input::Event e)
return didAction;
}
}

void EmuInputView::setTouchControlsOn(bool on)
{
touchControlsOn = on;
}

bool EmuInputView::touchControlsAreOn() const
{
return touchControlsOn;
}

+ 48
- 56
EmuFramework/src/EmuMainMenuView.cc View File

@@ -29,6 +29,7 @@
#include <emuframework/TouchConfigView.hh>
#include <emuframework/BundledGamesView.hh>
#include "private.hh"
#include "privateInput.hh"
#ifdef CONFIG_BLUETOOTH
#include <imagine/bluetooth/sys.hh>
#include <imagine/bluetooth/BluetoothInputDevScanner.hh>
@@ -63,7 +64,7 @@ public:
{
dismiss();
EmuSystem::reset(EmuSystem::RESET_SOFT);
startGameFromMenu();
emuViewController.showEmulation();
}
},
hard
@@ -73,7 +74,7 @@ public:
{
dismiss();
EmuSystem::reset(EmuSystem::RESET_HARD);
startGameFromMenu();
emuViewController.showEmulation();
}
},
cancel
@@ -113,60 +114,60 @@ static auto onScanStatus =
{
if(Config::envIsIOS)
{
popup.postError("BTstack power on failed, make sure the iOS Bluetooth stack is not active");
EmuApp::postErrorMessage("BTstack power on failed, make sure the iOS Bluetooth stack is not active");
}
}
bcase BluetoothAdapter::SCAN_FAILED:
{
popup.postError("Scan failed");
EmuApp::postErrorMessage("Scan failed");
}
bcase BluetoothAdapter::SCAN_NO_DEVS:
{
popup.post("No devices found");
EmuApp::postMessage("No devices found");
}
bcase BluetoothAdapter::SCAN_PROCESSING:
{
popup.printf(2, 0, "Checking %d device(s)...", arg);
EmuApp::printfMessage(2, 0, "Checking %d device(s)...", arg);
}
bcase BluetoothAdapter::SCAN_NAME_FAILED:
{
popup.postError("Failed reading a device name");
EmuApp::postErrorMessage("Failed reading a device name");
}
bcase BluetoothAdapter::SCAN_COMPLETE:
{
int devs = Bluetooth::pendingDevs();
if(devs)
{
popup.printf(2, 0, "Connecting to %d device(s)...", devs);
EmuApp::printfMessage(2, 0, "Connecting to %d device(s)...", devs);
Bluetooth::connectPendingDevs(bta);
}
else
{
popup.post("Scan complete, no recognized devices");
EmuApp::postMessage("Scan complete, no recognized devices");
}
}
/*bcase BluetoothAdapter::SOCKET_OPEN_FAILED:
{
popup.postError("Failed opening a Bluetooth connection");
EmuApp::postErrorMessage("Failed opening a Bluetooth connection");
}*/
}
};

static void handledFailedBTAdapterInit(ViewAttachParams attach, Input::Event e)
{
popup.postError("Unable to initialize Bluetooth adapter");
EmuApp::postErrorMessage("Unable to initialize Bluetooth adapter");
#ifdef CONFIG_BLUETOOTH_BTSTACK
if(!FS::exists("/var/lib/dpkg/info/ch.ringwald.btstack.list"))
{
auto &ynAlertView = *new YesNoAlertView{attach, "BTstack not found, open Cydia and install?"};
ynAlertView.setOnYes(
auto ynAlertView = std::make_unique<YesNoAlertView>(attach, "BTstack not found, open Cydia and install?");
ynAlertView->setOnYes(
[](TextMenuItem &, View &view, Input::Event)
{
view.dismiss();
logMsg("launching Cydia");
Base::openURL("cydia://package/ch.ringwald.btstack");
});
modalViewController.pushAndShow(ynAlertView, e, false);
emuViewController.pushAndShowModal(std::move(ynAlertView), e, false);
}
#endif
}
@@ -224,8 +225,7 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
"Load Game",
[this](TextMenuItem &, View &, Input::Event e)
{
auto &fPicker = *EmuFilePicker::makeForLoading(attachParams(), e);
pushAndShow(fPicker, e, false);
pushAndShow(EmuFilePicker::makeForLoading(attachParams(), e), e, false);
}
},
systemActions
@@ -235,7 +235,7 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
{
if(!EmuSystem::gameIsRunning())
return;
pushAndShow(*makeView(attachParams(), EmuApp::ViewID::SYSTEM_ACTIONS), e);
pushAndShow(makeEmuView(attachParams(), EmuApp::ViewID::SYSTEM_ACTIONS), e);
}
},
recentGames
@@ -245,8 +245,7 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
{
if(recentGameList.size())
{
auto &rMenu = *new RecentGameView{attachParams()};
pushAndShow(rMenu, e);
pushAndShow(makeView<RecentGameView>(), e);
}
}
},
@@ -255,8 +254,7 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
"Bundled Games",
[this](TextMenuItem &, View &, Input::Event e)
{
auto &bMenu = *new BundledGamesView{attachParams()};
pushAndShow(bMenu, e);
pushAndShow(makeView<BundledGamesView>(), e);
}
},
options
@@ -264,8 +262,7 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
"Options",
[this](TextMenuItem &, View &, Input::Event e)
{
auto &oMenu = *new OptionCategoryView{attachParams()};
pushAndShow(oMenu, e);
pushAndShow(makeView<OptionCategoryView>(), e);
}
},
onScreenInputManager
@@ -273,8 +270,7 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
"On-screen Input Setup",
[this](TextMenuItem &, View &, Input::Event e)
{
auto &tcMenu = *new TouchConfigView{attachParams(), EmuSystem::inputFaceBtnName, EmuSystem::inputCenterBtnName};
pushAndShow(tcMenu, e);
pushAndShow(makeView<TouchConfigView>(vController, EmuSystem::inputFaceBtnName, EmuSystem::inputCenterBtnName), e);
}
},
inputManager
@@ -282,8 +278,7 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
"Key/Gamepad Input Setup",
[this](TextMenuItem &, View &, Input::Event e)
{
auto &menu = *new InputManagerView{attachParams()};
pushAndShow(menu, e);
pushAndShow(makeView<InputManagerView>(), e);
}
},
benchmark
@@ -291,8 +286,7 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
"Benchmark Game",
[this](TextMenuItem &, View &, Input::Event e)
{
auto &fPicker = *EmuFilePicker::makeForBenchmarking(attachParams(), e);
pushAndShow(fPicker, e, false);
pushAndShow(EmuFilePicker::makeForBenchmarking(attachParams(), e), e, false);
}
},
#ifdef CONFIG_BLUETOOTH
@@ -305,11 +299,11 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
{
if(Bluetooth::scanForDevices(*bta, onScanStatus))
{
popup.post("Starting Scan...\n(see website for device-specific help)", 4);
EmuApp::postMessage(4, "Starting Scan...\n(see website for device-specific help)");
}
else
{
popup.post("Still scanning", 1);
EmuApp::postMessage(1, "Still scanning");
}
}
else
@@ -327,14 +321,14 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
if(Bluetooth::devsConnected())
{
string_printf(bluetoothDisconnectStr, "Really disconnect %d Bluetooth device(s)?", Bluetooth::devsConnected());
auto &ynAlertView = *new YesNoAlertView{attachParams(), bluetoothDisconnectStr.data()};
ynAlertView.setOnYes(
auto ynAlertView = makeView<YesNoAlertView>(bluetoothDisconnectStr.data());
ynAlertView->setOnYes(
[](TextMenuItem &, View &view, Input::Event e)
{
view.dismiss();
Bluetooth::closeBT(bta);
});
modalViewController.pushAndShow(ynAlertView, e, false);
emuViewController.pushAndShowModal(std::move(ynAlertView), e, false);
}
}
},
@@ -347,7 +341,7 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
{
if(initBTAdapter())
{
popup.post("Prepare to push the PS button", 4);
EmuApp::postMessage(4, "Prepare to push the PS button");
auto startedScan = Bluetooth::listenForDevices(*bta,
[this](BluetoothAdapter &bta, uint status, int arg)
{
@@ -355,19 +349,21 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
{
bcase BluetoothAdapter::INIT_FAILED:
{
popup.postError(Config::envIsLinux ? "Unable to register server, make sure this executable has cap_net_bind_service enabled and bluetoothd isn't running" :
"Bluetooth setup failed", Config::envIsLinux ? 8 : 2);
EmuApp::postErrorMessage(Config::envIsLinux ? 8 : 2,
Config::envIsLinux ?
"Unable to register server, make sure this executable has cap_net_bind_service enabled and bluetoothd isn't running" :
"Bluetooth setup failed");
}
bcase BluetoothAdapter::SCAN_COMPLETE:
{
popup.post("Push the PS button on your controller\n(see website for pairing help)", 4);
EmuApp::postMessage(4, "Push the PS button on your controller\n(see website for pairing help)");
}
bdefault: onScanStatus(bta, status, arg);
}
});
if(!startedScan)
{
popup.post("Still scanning", 1);
EmuApp::postMessage(1, "Still scanning");
}
}
else
@@ -383,8 +379,7 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
"About",
[this](TextMenuItem &, View &, Input::Event e)
{
auto &credits = *new CreditsView{EmuSystem::creditsViewStr, attachParams()};
pushAndShow(credits, e);
pushAndShow(makeViewWithName<CreditsView>(EmuSystem::creditsViewStr), e);
}
},
exitApp
@@ -403,6 +398,7 @@ EmuMainMenuView::EmuMainMenuView(ViewAttachParams attach, bool customMenu):
EmuApp::setOnMainMenuItemOptionChanged(
[this]()
{
auto lock = makeControllerMutexLock();
item.clear();
loadFileBrowserItems();
loadStandardItems();
@@ -424,32 +420,28 @@ OptionCategoryView::OptionCategoryView(ViewAttachParams attach):
"Video",
[this](TextMenuItem &, View &, Input::Event e)
{
auto &oCategoryMenu = *makeView(attachParams(), EmuApp::ViewID::VIDEO_OPTIONS);
pushAndShow(oCategoryMenu, e);
pushAndShow(makeEmuView(attachParams(), EmuApp::ViewID::VIDEO_OPTIONS), e);
}
},
{
"Audio",
[this](TextMenuItem &, View &, Input::Event e)
{
auto &oCategoryMenu = *makeView(attachParams(), EmuApp::ViewID::AUDIO_OPTIONS);
pushAndShow(oCategoryMenu, e);
pushAndShow(makeEmuView(attachParams(), EmuApp::ViewID::AUDIO_OPTIONS), e);
}
},
{
"System",
[this](TextMenuItem &, View &, Input::Event e)
{
auto &oCategoryMenu = *makeView(attachParams(), EmuApp::ViewID::SYSTEM_OPTIONS);
pushAndShow(oCategoryMenu, e);
pushAndShow(makeEmuView(attachParams(), EmuApp::ViewID::SYSTEM_OPTIONS), e);
}
},
{
"GUI",
[this](TextMenuItem &, View &, Input::Event e)
{
auto &oCategoryMenu = *makeView(attachParams(), EmuApp::ViewID::GUI_OPTIONS);
pushAndShow(oCategoryMenu, e);
pushAndShow(makeEmuView(attachParams(), EmuApp::ViewID::GUI_OPTIONS), e);
}
}
}
@@ -467,19 +459,19 @@ OptionCategoryView::OptionCategoryView(ViewAttachParams attach):
}
}

View *makeView(ViewAttachParams attach, EmuApp::ViewID id)
std::unique_ptr<View> makeEmuView(ViewAttachParams attach, EmuApp::ViewID id)
{
auto view = EmuApp::makeCustomView(attach, id);
if(view)
return view;
switch(id)
{
case EmuApp::ViewID::MAIN_MENU: return new EmuMainMenuView(attach);
case EmuApp::ViewID::SYSTEM_ACTIONS: return new EmuSystemActionsView(attach);
case EmuApp::ViewID::VIDEO_OPTIONS: return new VideoOptionView(attach);
case EmuApp::ViewID::AUDIO_OPTIONS: return new AudioOptionView(attach);
case EmuApp::ViewID::SYSTEM_OPTIONS: return new SystemOptionView(attach);
case EmuApp::ViewID::GUI_OPTIONS: return new GUIOptionView(attach);
case EmuApp::ViewID::MAIN_MENU: return std::make_unique<EmuMainMenuView>(attach);
case EmuApp::ViewID::SYSTEM_ACTIONS: return std::make_unique<EmuSystemActionsView>(attach);
case EmuApp::ViewID::VIDEO_OPTIONS: return std::make_unique<VideoOptionView>(attach);
case EmuApp::ViewID::AUDIO_OPTIONS: return std::make_unique<AudioOptionView>(attach);
case EmuApp::ViewID::SYSTEM_OPTIONS: return std::make_unique<SystemOptionView>(attach);
case EmuApp::ViewID::GUI_OPTIONS: return std::make_unique<GUIOptionView>(attach);
default:
bug_unreachable("Tried to make non-existing view ID:%d", (int)id);
return nullptr;

+ 8
- 8
EmuFramework/src/EmuOptions.cc View File

@@ -372,7 +372,7 @@ void initOptions()

bool OptionVControllerLayoutPosition::isDefault() const
{
return !vControllerLayoutPosChanged;
return !vController.layoutPositionChanged();
}

bool OptionVControllerLayoutPosition::writeToIO(IO &io)
@@ -380,7 +380,7 @@ bool OptionVControllerLayoutPosition::writeToIO(IO &io)
logMsg("writing vcontroller positions");
std::error_code ec{};
io.writeVal(key, &ec);
for(auto &posArr : vControllerLayoutPos)
for(auto &posArr : vController.layoutPosition())
{
for(auto &e : posArr)
{
@@ -402,7 +402,7 @@ bool OptionVControllerLayoutPosition::readFromIO(IO &io, uint readSize_)
{
int readSize = readSize_;

for(auto &posArr : vControllerLayoutPos)
for(auto &posArr : vController.layoutPosition())
{
for(auto &e : posArr)
{
@@ -428,7 +428,7 @@ bool OptionVControllerLayoutPosition::readFromIO(IO &io, uint readSize_)
e.state = state;
e.pos.x = io.readVal<int32>();
e.pos.y = io.readVal<int32>();
vControllerLayoutPosChanged = true;
vController.setLayoutPositionChanged();
readSize -= sizeofVControllerLayoutPositionEntry();
}
}
@@ -443,7 +443,7 @@ bool OptionVControllerLayoutPosition::readFromIO(IO &io, uint readSize_)

uint OptionVControllerLayoutPosition::ioSize()
{
uint positions = IG::size(vControllerLayoutPos[0]) * IG::size(vControllerLayoutPos);
uint positions = IG::size(vController.layoutPosition()[0]) * IG::size(vController.layoutPosition());
return sizeof(key) + positions * sizeofVControllerLayoutPositionEntry();
}

@@ -463,12 +463,12 @@ void setVControllerUseScaledCoordinates(bool on)
#endif
}

void setupFont(Gfx::Renderer &r)
void setupFont(Gfx::Renderer &r, Base::Window &win)
{
float size = optionFontSize / 1000.;
logMsg("setting up font size %f", (double)size);
View::defaultFace.setFontSettings(r, IG::FontSettings(mainWin.win.heightSMMInPixels(size)));
View::defaultBoldFace.setFontSettings(r, IG::FontSettings(mainWin.win.heightSMMInPixels(size)));
View::defaultFace.setFontSettings(r, IG::FontSettings(win.heightSMMInPixels(size)));
View::defaultBoldFace.setFontSettings(r, IG::FontSettings(win.heightSMMInPixels(size)));
}

#ifdef __ANDROID__

+ 1
- 1
EmuFramework/src/EmuOptions.hh View File

@@ -252,4 +252,4 @@ extern Byte1Option optionShowBundledGames;
extern PathOption optionFirmwarePath;

void initOptions();
void setupFont(Gfx::Renderer &r);
void setupFont(Gfx::Renderer &r, Base::Window &win);

+ 8
- 11
EmuFramework/src/EmuSystem.cc View File

@@ -28,6 +28,7 @@
#include <string>
#include <atomic>
#include "private.hh"
#include "privateInput.hh"

struct AudioStats
{
@@ -162,6 +163,7 @@ void EmuSystem::startAutoSaveStateTimer()
[]()
{
logMsg("auto-save state timer fired");
EmuApp::syncEmulationThread();
EmuApp::saveAutoState();
}, secs, secs, {});
}
@@ -516,7 +518,7 @@ FS::PathString EmuSystem::baseDefaultGameSavePath()
return FS::makePathStringPrintf("%s/Game Data/%s", Base::sharedStoragePath().data(), shortSystemName());
}

void EmuSystem::closeGame(bool allowAutosaveState)
void EmuSystem::closeRuntimeSystem(bool allowAutosaveState)
{
if(gameIsRunning())
{
@@ -527,12 +529,6 @@ void EmuSystem::closeGame(bool allowAutosaveState)
logMsg("closing game %s", gameName_.data());
closeSystem();
cancelAutoSaveStateTimer();
viewStack.navView()->showRightBtn(false);
if(int idx = viewStack.viewIdx("System Actions");
idx > 0)
{
viewStack.popTo(viewStack.viewAtIdx(idx - 1));
}
state = State::OFF;
}
clearGamePaths();
@@ -554,7 +550,7 @@ void EmuSystem::pause()
void EmuSystem::start()
{
state = State::ACTIVE;
clearInputBuffers(emuInputView);
clearInputBuffers(emuViewController.inputView());
resetFrameTime();
startSound();
startAutoSaveStateTimer();
@@ -580,6 +576,7 @@ void EmuSystem::skipFrames(uint frames, bool renderAudio)
iterateTimes(frames, i)
{
bool renderAudioThisFrame = renderAudio && audioFramesWritten() <= EmuSystem::audioFramesPerVideoFrame;
turboActions.update();
runFrame(nullptr, renderAudioThisFrame);
}
}
@@ -665,7 +662,7 @@ void EmuSystem::prepareAudioVideo()

static void closeAndSetupNew(const char *path)
{
EmuSystem::closeGame();
emuViewController.closeSystem();
EmuSystem::setupGamePaths(path);
EmuApp::loadSessionOptions();
}
@@ -726,12 +723,12 @@ EmuSystem::Error EmuSystem::loadGameFromFile(GenericIO file, const char *name, O
}
if(ec)
{
//popup.printf(3, true, "Error opening archive: %s", ec.message().c_str());
//EmuApp::printfMessage(3, true, "Error opening archive: %s", ec.message().c_str());
return makeError("Error opening archive: %s", ec.message().c_str());
}
if(!io)
{
//popup.postError("No recognized file extensions in archive");
//EmuApp::postErrorMessage("No recognized file extensions in archive");
return makeError("No recognized file extensions in archive");
}
closeAndSetupNew(name);

+ 29
- 32
EmuFramework/src/EmuSystemActionsView.cc View File

@@ -55,7 +55,7 @@ public:
{
dismiss();
EmuSystem::reset(EmuSystem::RESET_SOFT);
startGameFromMenu();
emuViewController.showEmulation();
}
},
hard
@@ -65,7 +65,7 @@ public:
{
dismiss();
EmuSystem::reset(EmuSystem::RESET_HARD);
startGameFromMenu();
emuViewController.showEmulation();
}
},
cancel
@@ -127,8 +127,7 @@ EmuSystemActionsView::EmuSystemActionsView(ViewAttachParams attach, bool customM
{
if(EmuSystem::gameIsRunning())
{
auto &cheatsMenu = *makeView(attachParams(), EmuApp::ViewID::LIST_CHEATS);
pushAndShow(cheatsMenu, e);
pushAndShow(makeEmuView(attachParams(), EmuApp::ViewID::LIST_CHEATS), e);
}
}
},
@@ -141,20 +140,19 @@ EmuSystemActionsView::EmuSystemActionsView(ViewAttachParams attach, bool customM
{
if(EmuSystem::hasResetModes)
{
auto &resetAlertView = *new ResetAlertView{attachParams(), "Really reset?"};
modalViewController.pushAndShow(resetAlertView, e, false);
emuViewController.pushAndShowModal(makeView<ResetAlertView>("Really reset?"), e, false);
}
else
{
auto &ynAlertView = *new YesNoAlertView{attachParams(), "Really reset?"};
ynAlertView.setOnYes(
auto ynAlertView = makeView<YesNoAlertView>("Really reset?");
ynAlertView->setOnYes(
[](TextMenuItem &, View &view, Input::Event e)
{
view.dismiss();
EmuSystem::reset(EmuSystem::RESET_SOFT);
startGameFromMenu();
emuViewController.showEmulation();
});
modalViewController.pushAndShow(ynAlertView, e, false);
emuViewController.pushAndShowModal(std::move(ynAlertView), e, false);
}
}
}
@@ -166,20 +164,20 @@ EmuSystemActionsView::EmuSystemActionsView(ViewAttachParams attach, bool customM
{
if(item.active() && EmuSystem::gameIsRunning())
{
auto &ynAlertView = *new YesNoAlertView{attachParams(), "Really load state?"};
ynAlertView.setOnYes(