diff --git a/2600.emu/src/main/EmuMenuViews.cc b/2600.emu/src/main/EmuMenuViews.cc index b1c305492..7fe60f96f 100644 --- a/2600.emu/src/main/EmuMenuViews.cc +++ b/2600.emu/src/main/EmuMenuViews.cc @@ -28,6 +28,8 @@ namespace EmuEx { +constexpr SystemLogger log{"2600Menus"}; + template using MainAppHelper = EmuAppHelper; @@ -39,23 +41,23 @@ class CustomAudioOptionView : public AudioOptionView, public MainAppHelper(attachParams(), e, "Input 1 to 20", "", @@ -260,7 +262,7 @@ class ConsoleOptionView : public TableView, public MainAppHelper { BoolMenuItem diff1 { - "Left (P1) Difficulty", &defaultFace(), + "Left (P1) Difficulty", attachParams(), system().p1DiffB, "A", "B", [this](BoolMenuItem &item) @@ -331,7 +333,7 @@ class VCSSwitchesView : public TableView, public MainAppHelper BoolMenuItem diff2 { - "Right (P2) Difficulty", &defaultFace(), + "Right (P2) Difficulty", attachParams(), system().p2DiffB, "A", "B", [this](BoolMenuItem &item) @@ -342,7 +344,7 @@ class VCSSwitchesView : public TableView, public MainAppHelper BoolMenuItem color { - "Color", &defaultFace(), + "Color", attachParams(), system().vcsColor, [this](BoolMenuItem &item) { @@ -381,7 +383,7 @@ class CustomSystemActionsView : public SystemActionsView private: TextMenuItem switches { - "Console Switches", &defaultFace(), + "Console Switches", attachParams(), [this](const Input::Event &e) { if(system().hasContent()) @@ -393,7 +395,7 @@ class CustomSystemActionsView : public SystemActionsView TextMenuItem options { - "Console Options", &defaultFace(), + "Console Options", attachParams(), [this](const Input::Event &e) { if(system().hasContent()) diff --git a/2600.emu/src/main/input.cc b/2600.emu/src/main/input.cc index a6822acb6..428ab4361 100644 --- a/2600.emu/src/main/input.cc +++ b/2600.emu/src/main/input.cc @@ -23,7 +23,7 @@ #undef Debugger #include "MainSystem.hh" #include "MainApp.hh" -#include +#include #include namespace EmuEx diff --git a/C64.emu/src/main/EmuMenuViews.cc b/C64.emu/src/main/EmuMenuViews.cc index 7da6fe447..6415b3b39 100644 --- a/C64.emu/src/main/EmuMenuViews.cc +++ b/C64.emu/src/main/EmuMenuViews.cc @@ -52,6 +52,8 @@ extern "C" namespace EmuEx { +constexpr SystemLogger log{"C64Menus"}; + template using MainAppHelper = EmuAppHelper; @@ -125,7 +127,7 @@ class CustomVideoOptionView : public VideoOptionView, public MainAppHelper= std::size(borderModeItem) ? VICII_NORMAL_BORDERS : (int)system().optionBorderMode, borderModeItem }; @@ -166,7 +168,7 @@ class CustomVideoOptionView : public VideoOptionView, public MainAppHelper= std::size(sidEngineItem)) { return SID_ENGINE_FASTSID; @@ -231,15 +233,15 @@ class CustomAudioOptionView : public AudioOptionView, public MainAppHelper("VICE System Files", @@ -342,7 +344,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper return false; } } - systemFilePath.compile(sysPathMenuEntryStr(path), renderer()); + systemFilePath.compile(sysPathMenuEntryStr(path)); return true; }); view->appendItem(downloadSystemFiles); @@ -352,7 +354,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper TextMenuItem downloadSystemFiles { - "Download VICE System Files", &defaultFace(), + "Download VICE System Files", attachParams(), [this](Input::Event e) { pushAndShowModal(makeView( @@ -390,7 +392,7 @@ class DatasetteControlsView : public TableView, public MainAppHelper menuItem @@ -487,7 +489,7 @@ class DatasetteControlsView : public TableView, public MainAppHelper item; @@ -772,14 +774,14 @@ class C64IOControlView : public TableView, public MainAppHelper(), e); @@ -906,7 +908,7 @@ class MachineOptionView : public TableView, public MainAppHelper paletteName{}; std::vector paletteItem{}; MultiChoiceMenuItem palette { - "Palette", &defaultFace(), + "Palette", attachParams(), [this]() { if(!system().usingExternalPalette()) @@ -970,7 +972,7 @@ class MachineOptionView : public TableView, public MainAppHelper(item, VicePlugin::SYSTEMS); @@ -1266,7 +1268,7 @@ class CustomMainMenuView : public MainMenuView, public MainAppHelper EmuApp::makeCustomView(ViewAttachParams attach, ViewID id) CLINK void ui_display_tape_counter(int port, int counter) { - //logMsg("tape counter:%d", counter); + //log.info("tape counter:{}", counter); EmuEx::tapeCounter = counter; } diff --git a/EmuFramework/include/emuframework/AutosaveManager.hh b/EmuFramework/include/emuframework/AutosaveManager.hh index 7a5d6923e..f2c722026 100644 --- a/EmuFramework/include/emuframework/AutosaveManager.hh +++ b/EmuFramework/include/emuframework/AutosaveManager.hh @@ -16,7 +16,6 @@ along with EmuFramework. If not, see */ #include -#include #include #include #include @@ -25,15 +24,11 @@ #include #include -namespace IG -{ -class MapIO; -class FileIO; -} - namespace EmuEx { +using namespace IG; + class EmuApp; class EmuSystem; diff --git a/EmuFramework/include/emuframework/Cheats.hh b/EmuFramework/include/emuframework/Cheats.hh index 3d36b2ab8..37426f4b1 100644 --- a/EmuFramework/include/emuframework/Cheats.hh +++ b/EmuFramework/include/emuframework/Cheats.hh @@ -70,14 +70,14 @@ public: }, name { - IG_forward(cheatName), &defaultFace(), + IG_forward(cheatName), attach, [this](const Input::Event &e) { app().template pushAndShowNewCollectValueInputView(attachParams(), e, "Input description", static_cast(this)->cheatNameString(), [this](EmuApp &, auto str) { - name.compile(str, renderer()); + name.compile(str); static_cast(this)->renamed(str); onCheatListChanged(); postDraw(); @@ -87,7 +87,7 @@ public: }, remove { - "Delete Cheat", &defaultFace(), + "Delete Cheat", attach, removed }, onCheatListChanged_{onCheatListChanged_} {} diff --git a/EmuFramework/include/emuframework/DataPathSelectView.hh b/EmuFramework/include/emuframework/DataPathSelectView.hh index 8ca2f4a3d..767affbb2 100644 --- a/EmuFramework/include/emuframework/DataPathSelectView.hh +++ b/EmuFramework/include/emuframework/DataPathSelectView.hh @@ -56,7 +56,7 @@ public: TableView{IG_forward(name), attach, item}, selectFolder { - "Select Folder", &defaultFace(), + "Select Folder", attach, [=](View &view, const Input::Event &e) { auto fPicker = view.makeView(FSPicker::Mode::DIR, EmuSystem::NameFilterFunc{}, e); @@ -75,7 +75,7 @@ public: }, selectFile { - mode == DataPathSelectMode::File ? "Select File" : "Select Archive File", &defaultFace(), + mode == DataPathSelectMode::File ? "Select File" : "Select Archive File", attach, [=](View &view, const Input::Event &e) { auto &thisView = asThis(view); @@ -101,7 +101,7 @@ public: }, unset { - "Unset", &defaultFace(), + "Unset", attach, [=](View &view) { onFileChange("", FS::file_type::none); diff --git a/EmuFramework/include/emuframework/EmuApp.hh b/EmuFramework/include/emuframework/EmuApp.hh index 0cc73a9df..5eaec488a 100644 --- a/EmuFramework/include/emuframework/EmuApp.hh +++ b/EmuFramework/include/emuframework/EmuApp.hh @@ -126,6 +126,10 @@ enum class AltSpeedMode fast, slow }; +WISE_ENUM_CLASS((PresentationTimeMode, uint8_t), + off, basic, full +); + WISE_ENUM_CLASS((CPUAffinityMode, uint8_t), Auto, Any, Manual ); @@ -300,7 +304,6 @@ public: uint8_t viewportZoom() { return optionViewportZoom; } auto &showOnSecondScreenOption() { return optionShowOnSecondScreen; } auto &textureBufferModeOption() { return optionTextureBufferMode; } - auto &videoImageBuffersOption() { return optionVideoImageBuffers; } void setContentRotation(IG::Rotation); IG::Rotation contentRotation() const { return contentRotation_; } void updateContentRotation(); @@ -546,7 +549,6 @@ protected: Byte1Option optionViewportZoom; Byte1Option optionShowOnSecondScreen; Byte1Option optionTextureBufferMode; - Byte1Option optionVideoImageBuffers; Gfx::DrawableConfig windowDrawableConf; IG::PixelFormat renderPixelFmt; IG::Rotation contentRotation_{IG::Rotation::ANY}; @@ -566,7 +568,7 @@ public: IG_UseMemberIf(Config::envIsAndroid && Config::DEBUG_BUILD, bool, useNoopThread){}; IG_UseMemberIf(enableFrameTimeStats, bool, showFrameTimeStats){}; IG_UseMemberIf(Gfx::supportsPresentModes, Gfx::PresentMode, presentMode){}; - IG_UseMemberIf(Gfx::supportsPresentationTime, bool, usePresentationTime){true}; + IG_UseMemberIf(Gfx::supportsPresentationTime, PresentationTimeMode, presentationTimeMode){PresentationTimeMode::basic}; bool allowBlankFrameInsertion{}; bool enableBlankFrameInsertion{}; diff --git a/EmuFramework/include/emuframework/EmuVideo.hh b/EmuFramework/include/emuframework/EmuVideo.hh index 3ef8ea2af..29cfea279 100644 --- a/EmuFramework/include/emuframework/EmuVideo.hh +++ b/EmuFramework/include/emuframework/EmuVideo.hh @@ -66,7 +66,6 @@ public: void finishFrame(EmuSystemTaskContext, Gfx::LockedTextureBuffer texBuff); void finishFrame(EmuSystemTaskContext, IG::PixmapView pix); void dispatchFrameFinished(); - bool addFence(Gfx::RendererCommands &cmds); void clear(); void takeGameScreenshot(); bool isExternalTexture() const; @@ -78,33 +77,26 @@ public: void setOnFrameFinished(FrameFinishedDelegate del); void setOnFormatChanged(FormatChangedDelegate del); void setTextureBufferMode(EmuSystem &, Gfx::TextureBufferMode mode); - void setImageBuffers(int num); - int imageBuffers() const; void setSampler(Gfx::TextureSamplerConfig); constexpr auto colorSpace() const { return colSpace; } bool setRenderPixelFormat(EmuSystem &, IG::PixelFormat, Gfx::ColorSpace); IG::PixelFormat renderPixelFormat() const; IG::PixelFormat internalRenderPixelFormat() const; static Gfx::TextureSamplerConfig samplerConfigForLinearFilter(bool useLinearFilter); - void updateNeedsFence(); protected: Gfx::RendererTask *rTask{}; - Gfx::SyncFence fence; Gfx::PixmapBufferTexture vidImg; FrameFinishedDelegate onFrameFinished; FormatChangedDelegate onFormatChanged; IG::PixelFormat renderFmt; Gfx::TextureBufferMode bufferMode{}; bool screenshotNextFrame{}; - bool singleBuffer{}; - bool needsFence{}; Gfx::ColorSpace colSpace{Gfx::ColorSpace::LINEAR}; bool useLinearFilter{true}; void doScreenshot(EmuSystemTaskContext, IG::PixmapView pix); void postFrameFinished(EmuSystemTaskContext); - void syncImageAccess(); Gfx::TextureSamplerConfig samplerConfig() const { return samplerConfigForLinearFilter(useLinearFilter); } }; diff --git a/EmuFramework/include/emuframework/EmuView.hh b/EmuFramework/include/emuframework/EmuView.hh index 71b27f610..1e89e4803 100644 --- a/EmuFramework/include/emuframework/EmuView.hh +++ b/EmuFramework/include/emuframework/EmuView.hh @@ -33,7 +33,6 @@ struct FrameTimeStats; class EmuView : public View { public: - EmuView(); EmuView(ViewAttachParams, EmuVideoLayer *, EmuSystem &); void place() final; void prepareDraw() final; diff --git a/EmuFramework/include/emuframework/OutputTimingManager.hh b/EmuFramework/include/emuframework/OutputTimingManager.hh index dddfe58d1..b7eb82c1e 100644 --- a/EmuFramework/include/emuframework/OutputTimingManager.hh +++ b/EmuFramework/include/emuframework/OutputTimingManager.hh @@ -66,7 +66,7 @@ public: static bool frameTimeOptionIsValid(FrameTime time); bool setFrameTimeOption(VideoSystem, FrameTime frameTime); FrameTime frameTimeOption(VideoSystem vidSys) const { return frameTimeVar(vidSys); } - auto frameTimeOptionAsMenuId(VideoSystem vidSys) const { return MenuItem::Id(frameTimeVar(vidSys).count() > 0 ? 1 : frameTimeVar(vidSys).count()); } + auto frameTimeOptionAsMenuId(VideoSystem vidSys) const { return MenuId(frameTimeVar(vidSys).count() > 0 ? 1 : frameTimeVar(vidSys).count()); } private: FrameTime frameTimeNative{}; diff --git a/EmuFramework/include/emuframework/UserPathSelectView.hh b/EmuFramework/include/emuframework/UserPathSelectView.hh index 361bbca94..2870233a3 100644 --- a/EmuFramework/include/emuframework/UserPathSelectView.hh +++ b/EmuFramework/include/emuframework/UserPathSelectView.hh @@ -34,7 +34,7 @@ public: TableView{IG_forward(name), attach, item}, selectFolder { - "Select Folder", &defaultFace(), + "Select Folder", attach, [=](View &view, const Input::Event &e) { auto fPicker = view.makeView(FSPicker::Mode::DIR, EmuSystem::NameFilterFunc{}, e); @@ -52,7 +52,7 @@ public: }, sameAsContent { - "Same As Content", &defaultFace(), + "Same As Content", attach, [=](View &view) { onPathChange(optionUserPathContentToken); @@ -61,7 +61,7 @@ public: }, sameAsSaves { - "Same As Saves", &defaultFace(), + "Same As Saves", attach, [=](View &view) { onPathChange(""); diff --git a/EmuFramework/include/emuframework/VController.hh b/EmuFramework/include/emuframework/VController.hh index 1324b6ad3..ddea0306f 100755 --- a/EmuFramework/include/emuframework/VController.hh +++ b/EmuFramework/include/emuframework/VController.hh @@ -40,6 +40,7 @@ namespace EmuEx using namespace IG; class VController; +class InputManager; class EmuApp; class EmuViewController; struct SystemInputDeviceDesc; @@ -80,14 +81,14 @@ public: int16_t deadzoneMM100x{defaultDPadDeadzoneMM100x}; bool visualizeBounds{}; - void validate(const EmuApp &); + void validate(const InputManager &); }; constexpr VControllerDPad() = default; constexpr VControllerDPad(std::span keys): config{.keys{keys[0], keys[1], keys[2], keys[3]}} {} constexpr VControllerDPad(const Config &config): config{config} {} - void setImage(Gfx::RendererTask &, Gfx::TextureSpan); + void setImage(Gfx::RendererTask &, Gfx::TextureSpan, const Gfx::IndexBuffer &idxs); void drawButtons(Gfx::RendererCommands &__restrict__) const; void drawBounds(Gfx::RendererCommands &__restrict__) const; void setShowBounds(Gfx::Renderer &r, bool on); @@ -101,9 +102,9 @@ public: auto deadzone() const { return config.deadzoneMM100x; } bool setDiagonalSensitivity(Gfx::Renderer &, float newDiagonalSensitivity); auto diagonalSensitivity() const { return config.diagonalSensitivity; } - std::string name(const EmuApp &) const { return "D-Pad"; } + std::string name(const InputManager &) const { return "D-Pad"; } void updateMeasurements(const Window &win); - void transposeKeysForPlayer(const EmuApp &, int player); + void transposeKeysForPlayer(const InputManager &, int player); void setAlpha(float alpha); static size_t configSize() @@ -191,7 +192,7 @@ public: void setImage(Gfx::TextureSpan, int aR = 1); WRect bounds() const { return bounds_; } WRect realBounds() const { return extendedBounds_; } - std::string name(const EmuApp &) const; + std::string name(const InputManager &) const; bool overlaps(WPt windowPos) const { return enabled && realBounds().overlaps(windowPos); } void setAlpha(float alpha); @@ -265,7 +266,7 @@ public: std::vector keys{}; LayoutConfig layout{}; - void validate(const EmuApp &); + void validate(const InputManager &); }; constexpr VControllerButtonGroup() = default; @@ -287,10 +288,10 @@ public: int rows() const; std::array findButtonIndices(WPt windowPos) const; void drawBounds(Gfx::RendererCommands &__restrict__) const; - std::string name(const EmuApp &) const; + std::string name(const InputManager &) const; void updateMeasurements(const Window &win); - void transposeKeysForPlayer(const EmuApp &, int player); - void setTask(Gfx::RendererTask &task) { quads.setTask(task); boundQuads.setTask(task); } + void transposeKeysForPlayer(const InputManager &, int player); + void setTask(Gfx::RendererTask &task) { quads = {task, {.size = buttons.size()}}; boundQuads = {task, {.size = 0}}; } static size_t layoutConfigSize() { @@ -338,7 +339,7 @@ public: std::vector keys{}; LayoutConfig layout{}; - void validate(const EmuApp &); + void validate(const InputManager &); }; constexpr VControllerUIButtonGroup() = default; @@ -350,8 +351,8 @@ public: auto bounds() const { return bounds_; } WRect realBounds() const { return bounds(); } int rows() const; - std::string name(const EmuApp &) const; - void setTask(Gfx::RendererTask &task) { quads.setTask(task); } + std::string name(const InputManager &) const; + void setTask(Gfx::RendererTask &task) { quads = {task, {.size = buttons.size()}}; } static size_t layoutConfigSize() { @@ -453,9 +454,9 @@ public: }, *this); } - std::string name(const EmuApp &app) const + std::string name(const InputManager &mgr) const { - return visit([&](auto &e){ return e.name(app); }, *this); + return visit([&](auto &e){ return e.name(mgr); }, *this); } void updateMeasurements(const Window &win) @@ -469,13 +470,13 @@ public: }, *this); } - void transposeKeysForPlayer(const EmuApp &app, int player) + void transposeKeysForPlayer(const InputManager &mgr, int player) { visit([&](auto &e) { - if constexpr(requires {e.transposeKeysForPlayer(app, player);}) + if constexpr(requires {e.transposeKeysForPlayer(mgr, player);}) { - e.transposeKeysForPlayer(app, player); + e.transposeKeysForPlayer(mgr, player); } }, *this); } @@ -616,7 +617,7 @@ public: bool updateAutoOnScreenControlVisible(); bool readConfig(EmuApp &, MapIO &, unsigned key, size_t size); void writeConfig(FileIO &) const; - void configure(Window &, Gfx::Renderer &, const Gfx::GlyphTextureSet &face, const Gfx::IndexBuffer &quadIdxs); + void configure(Window &, Gfx::Renderer &, const Gfx::GlyphTextureSet &face); void resetEmulatedDevicePositions(); void resetEmulatedDeviceGroups(); void resetUIPositions(); @@ -646,7 +647,6 @@ private: const Window *win{}; const WindowData *winData{}; const Gfx::GlyphTextureSet *facePtr{}; - const Gfx::IndexBuffer *quadIdxsPtr{}; Gfx::IndexBuffer fanQuadIdxs; Gfx::TextureBinding gamepadTex, uiTex; VControllerKeyboard kb; @@ -685,7 +685,6 @@ private: int uiButtonPixelSize() const; void writeDeviceButtonsConfig(FileIO &) const; void writeUIButtonsConfig(FileIO &) const; - void setIndexArray(Gfx::RendererCommands &__restrict__, const VControllerElement &) const; }; } diff --git a/EmuFramework/include/emuframework/VideoImageOverlay.hh b/EmuFramework/include/emuframework/VideoImageOverlay.hh index 4c68c313a..321f05246 100644 --- a/EmuFramework/include/emuframework/VideoImageOverlay.hh +++ b/EmuFramework/include/emuframework/VideoImageOverlay.hh @@ -18,7 +18,6 @@ #include #include #include -#include namespace EmuEx { @@ -50,7 +49,7 @@ private: glm::vec2 texCoord; }; using Quad = Gfx::BaseQuad; - using Quads = Gfx::ObjectVertexBuffer; + using Quads = Gfx::ObjectVertexArray; Quads quad; Gfx::Texture texture; diff --git a/EmuFramework/include/emuframework/VideoOptionView.hh b/EmuFramework/include/emuframework/VideoOptionView.hh index 63ede3c30..149d893e3 100644 --- a/EmuFramework/include/emuframework/VideoOptionView.hh +++ b/EmuFramework/include/emuframework/VideoOptionView.hh @@ -82,7 +82,8 @@ protected: MultiChoiceMenuItem renderPixelFormat; IG_UseMemberIf(Config::multipleScreenFrameRates, std::vector, screenFrameRateItems); IG_UseMemberIf(Config::multipleScreenFrameRates, MultiChoiceMenuItem, screenFrameRate); - IG_UseMemberIf(Gfx::supportsPresentationTime, BoolMenuItem, presentationTime); + IG_UseMemberIf(Gfx::supportsPresentationTime, TextMenuItem, presentationTimeItems[3]); + IG_UseMemberIf(Gfx::supportsPresentationTime, MultiChoiceMenuItem, presentationTime); BoolMenuItem blankFrameInsertion; TextMenuItem brightnessItem[2]; TextMenuItem redItem[2]; @@ -101,7 +102,7 @@ protected: bool onFrameTimeChange(VideoSystem vidSys, SteadyClockTime time); TextMenuItem::SelectDelegate setVideoBrightnessCustomDel(ImageChannel); - void setAllColorLevelsSelected(MenuItem::Id); + void setAllColorLevelsSelected(MenuId); EmuVideo &emuVideo() const; }; diff --git a/EmuFramework/src/ConfigFile.cc b/EmuFramework/src/ConfigFile.cc index c3256815b..07596d1db 100644 --- a/EmuFramework/src/ConfigFile.cc +++ b/EmuFramework/src/ConfigFile.cc @@ -25,6 +25,8 @@ namespace EmuEx { +constexpr SystemLogger log{"ConfigFile"}; + bool isValidAspectRatio(float val); bool isValidFastSpeed(int16_t); bool isValidSlowSpeed(int16_t); @@ -54,7 +56,7 @@ void EmuApp::saveConfigFile(FileIO &io) { if(!io) { - logMsg("not writing config file"); + log.info("not writing config file"); return; } writeConfigHeader(io); @@ -69,7 +71,6 @@ void EmuApp::saveConfigFile(FileIO &io) optionImgFilter, optionImgEffect, optionImageEffectPixelFormat, - optionVideoImageBuffers, optionOverlayEffect, optionOverlayEffectLevel, optionFontSize, @@ -149,8 +150,8 @@ void EmuApp::saveConfigFile(FileIO &io) writeOptionValueIfNotDefault(io, CFGKEY_CPU_AFFINITY_MODE, cpuAffinityMode, CPUAffinityMode::Auto); if(used(presentMode) && supportsPresentModes()) writeOptionValueIfNotDefault(io, CFGKEY_RENDERER_PRESENT_MODE, presentMode, Gfx::PresentMode::Auto); - if(used(usePresentationTime) && renderer.supportsPresentationTime()) - writeOptionValueIfNotDefault(io, CFGKEY_RENDERER_PRESENTATION_TIME, usePresentationTime, true); + if(used(presentationTimeMode) && renderer.supportsPresentationTime()) + writeOptionValueIfNotDefault(io, CFGKEY_RENDERER_PRESENTATION_TIME, presentationTimeMode, PresentationTimeMode::basic); writeStringOptionValue(io, CFGKEY_LAST_DIR, contentSearchPath()); writeStringOptionValue(io, CFGKEY_SAVE_PATH, system().userSaveDirectory()); writeStringOptionValue(io, CFGKEY_SCREENSHOTS_PATH, userScreenshotPath); @@ -168,7 +169,7 @@ EmuApp::ConfigParams EmuApp::loadConfigFile(IG::ApplicationContext ctx) auto oldConfigFilePath = FS::pathString(ctx.assetPath(), "config"); if(FS::exists(oldConfigFilePath)) { - logMsg("moving config file from app path to support path"); + log.info("moving config file from app path to support path"); FS::rename(oldConfigFilePath, configFilePath); } } @@ -179,12 +180,12 @@ EmuApp::ConfigParams EmuApp::loadConfigFile(IG::ApplicationContext ctx) auto oldConfigFilePath = FS::pathString(oldConfigDir, EmuSystem::configFilename); if(FS::exists(oldConfigFilePath)) { - logMsg("moving config file from prefs path to support path"); + log.info("moving config file from prefs path to support path"); FS::rename(oldConfigFilePath, configFilePath); } if(!FS::directoryItems(oldConfigDir)) { - logMsg("removing old empty config directory"); + log.info("removing old empty config directory"); FS::remove(oldConfigDir); } } @@ -210,7 +211,7 @@ EmuApp::ConfigParams EmuApp::loadConfigFile(IG::ApplicationContext ctx) return true; if(recentContent.readConfig(io, key, size, system())) return true; - logMsg("skipping key %u", (unsigned)key); + log.info("skipping key:{}", key); return false; } case CFGKEY_FRAME_INTERVAL: return optionFrameInterval.readFromIO(io, size);; @@ -232,7 +233,6 @@ EmuApp::ConfigParams EmuApp::loadConfigFile(IG::ApplicationContext ctx) case CFGKEY_RENDER_PIXEL_FORMAT: setRenderPixelFormat(readOptionValue(io, size, renderPixelFormatIsValid)); return true; - case CFGKEY_VIDEO_IMAGE_BUFFERS: return optionVideoImageBuffers.readFromIO(io, size); case CFGKEY_OVERLAY_EFFECT: return optionOverlayEffect.readFromIO(io, size); case CFGKEY_OVERLAY_EFFECT_LEVEL: return optionOverlayEffectLevel.readFromIO(io, size); case CFGKEY_RECENT_CONTENT: return recentContent.readLegacyConfig(io, system()); @@ -278,7 +278,7 @@ EmuApp::ConfigParams EmuApp::loadConfigFile(IG::ApplicationContext ctx) case CFGKEY_RENDERER_PRESENT_MODE: return used(presentMode) && supportsPresentModes() ? readOptionValue(io, size, presentMode, [](auto m){return m <= lastEnum;}) : false; case CFGKEY_RENDERER_PRESENTATION_TIME: - return used(usePresentationTime) ? readOptionValue(io, size, usePresentationTime) : false; + return used(presentationTimeMode) ? readOptionValue(io, size, presentationTimeMode, [](auto m){return m <= lastEnum;}) : false; case CFGKEY_AUDIO_SOLO_MIX: audioManager().setSoloMix(readOptionValue(io, size)); return true; @@ -324,7 +324,7 @@ void EmuApp::saveConfigFile(IG::ApplicationContext ctx) } catch(...) { - logErr("error writing config file"); + log.error("error writing config file"); } } diff --git a/EmuFramework/src/EmuApp.cc b/EmuFramework/src/EmuApp.cc index 54fd5d1c3..2caf2f8e0 100644 --- a/EmuFramework/src/EmuApp.cc +++ b/EmuFramework/src/EmuApp.cc @@ -144,7 +144,6 @@ EmuApp::EmuApp(ApplicationInitParams initParams, ApplicationContext &ctx): optionViewportZoom(CFGKEY_VIEWPORT_ZOOM, 100, 0, optionIsValidWithMinMax<50, 100>), optionShowOnSecondScreen{CFGKEY_SHOW_ON_2ND_SCREEN, 0}, optionTextureBufferMode{CFGKEY_TEXTURE_BUFFER_MODE, 0}, - optionVideoImageBuffers{CFGKEY_VIDEO_IMAGE_BUFFERS, 0, 0, optionIsValidWithMax<2>}, layoutBehindSystemUI{ctx.hasTranslucentSysUI()} { if(ctx.registerInstance(initParams)) @@ -181,15 +180,11 @@ class ExitConfirmAlertView : public AlertView, public EmuAppHelper 2; -} - void EmuApp::startAudio() { audio().start(system().frameTime()); @@ -506,8 +496,6 @@ void EmuApp::mainInitCommon(IG::ApplicationInitParams initParams, IG::Applicatio [this, appConfig](IG::ApplicationContext ctx, IG::Window &win) { renderer.initMainTask(&win, windowDrawableConfig()); - if(!supportsVideoImageBuffersOption(renderer)) - optionVideoImageBuffers.resetToConst(); if(optionTextureBufferMode.val) { auto mode = (Gfx::TextureBufferMode)optionTextureBufferMode.val; @@ -517,7 +505,6 @@ void EmuApp::mainInitCommon(IG::ApplicationInitParams initParams, IG::Applicatio optionTextureBufferMode.reset(); } } - viewManager.quadIndices = {renderer.mainTask, 32}; viewManager.defaultFace = {renderer, fontManager.makeSystem(), fontSettings(win)}; viewManager.defaultBoldFace = {renderer, fontManager.makeBoldSystem(), fontSettings(win)}; ViewAttachParams viewAttach{viewManager, win, renderer.task()}; @@ -527,7 +514,7 @@ void EmuApp::mainInitCommon(IG::ApplicationInitParams initParams, IG::Applicatio win.setAcceptDnd(true); renderer.setWindowValidOrientations(win, menuOrientation()); inputManager.updateInputDevices(ctx); - vController.configure(win, renderer, viewManager.defaultFace, viewManager.quadIndices); + vController.configure(win, renderer, viewManager.defaultFace); if(EmuSystem::inputHasKeyboard) { vController.setKeyboardImage(asset(AssetID::keyboardOverlay)); @@ -553,7 +540,6 @@ void EmuApp::mainInitCommon(IG::ApplicationInitParams initParams, IG::Applicatio }); emuVideo.setRendererTask(renderer.task()); emuVideo.setTextureBufferMode(system(), (Gfx::TextureBufferMode)optionTextureBufferMode.val); - emuVideo.setImageBuffers(optionVideoImageBuffers); emuVideoLayer.setRendererTask(renderer.task()); emuVideoLayer.setLinearFilter(optionImgFilter); // init the texture sampler before setting format applyRenderPixelFormat(); @@ -623,8 +609,11 @@ void EmuApp::mainInitCommon(IG::ApplicationInitParams initParams, IG::Applicatio emuSystemTask.runFrame(videoPtr, audioPtr, frameInfo.advanced, skipForward, altSpeed); if(videoPtr) { - if(usePresentationTime) + if(presentationTimeMode == PresentationTimeMode::full || + (presentationTimeMode == PresentationTimeMode::basic && interval > 1)) + { viewController.presentTime = params.presentTime(interval); + } doIfUsed(frameStartTimePoint, [&](auto &tp) { if(!hasTime(tp)) @@ -1034,7 +1023,7 @@ void EmuApp::promptSystemReloadDueToSetOption(ViewAttachParams attach, const Inp return; viewController().pushAndShowModal(std::make_unique(attach, "This option takes effect next time the system starts. Restart it now?", - YesNoAlertView::Delegates{ .onYes = [this, params] { reloadSystem(params); } }), e, false); + YesNoAlertView::Delegates{ .onYes = [this, params] { reloadSystem(params); return false; } }), e, false); } void EmuApp::unpostMessage() diff --git a/EmuFramework/src/EmuAudio.cc b/EmuFramework/src/EmuAudio.cc index f42efe1d4..1a16ac148 100644 --- a/EmuFramework/src/EmuAudio.cc +++ b/EmuFramework/src/EmuAudio.cc @@ -13,7 +13,6 @@ You should have received a copy of the GNU General Public License along with EmuFramework. If not, see */ -#define LOGTAG "EmuAudio" #include "EmuOptions.hh" #include #include @@ -25,6 +24,8 @@ namespace EmuEx { +constexpr SystemLogger log{"EmuAudio"}; + struct AudioStats { constexpr AudioStats() = default; @@ -107,7 +108,7 @@ static void simpleResample(T * __restrict__ dest, size_t destFrames, const T * _ size_t srcPos = std::floor((float)i * ratio); if(srcPos >= srcFrames) [[unlikely]] { - logMsg("resample pos %zu too high", srcPos); + log.info("resample pos {} too high", srcPos); srcPos = srcFrames-1; } dest[i] = src[srcPos]; @@ -142,9 +143,9 @@ void EmuAudio::resizeAudioBuffer(size_t targetBufferFillBytes) rBuff.setMinCapacity(targetBufferFillBytes + bufferIncrementBytes); if(Config::DEBUG_BUILD && rBuff.capacity() != oldCapacity) { - logMsg("created audio buffer:%zu frames (%.4fs), fill target:%zu frames (%.4fs)", - format().bytesToFrames(rBuff.freeSpace()), format().bytesToTime(rBuff.freeSpace()).count(), - format().bytesToFrames(targetBufferFillBytes), format().bytesToTime(targetBufferFillBytes).count()); + log.info("created audio buffer:{} frames ({}), fill target:{} frames ({})", + format().bytesToFrames(rBuff.freeSpace()), format().bytesToTime(rBuff.freeSpace()), + format().bytesToFrames(targetBufferFillBytes), format().bytesToTime(targetBufferFillBytes)); } } @@ -160,7 +161,7 @@ void EmuAudio::start(FloatSeconds bufferDuration) FloatSeconds targetBufferFillDuration = soundBuffers * bufferDuration; if(!audioStream) { - logMsg("sound is disabled"); + log.info("sound is disabled"); return; } lastUnderrunTime = {}; @@ -193,11 +194,11 @@ void EmuAudio::start(FloatSeconds bufferDuration) { auto padFrames = frames - framesToRead; std::fill_n(frameEndAddr, outputFormat.framesToBytes(padFrames), 0); - //logMsg("underrun, %d bytes ready out of %d", bytesReady, bytes); + //log.info("underrun, {} bytes ready out of {}", bytesReady, bytes); auto now = SteadyClock::now(); if(now - lastUnderrunTime < IG::Seconds(1)) { - //logWarn("multiple underruns within a short time"); + //log.warn("multiple underruns within a short time"); audioWriteState = AudioWriteState::MULTI_UNDERRUN; } else @@ -228,7 +229,7 @@ void EmuAudio::start(FloatSeconds bufferDuration) if(shouldStartAudioWrites()) { if(Config::DEBUG_BUILD) - logMsg("resuming audio writes with buffer fill %zu/%zu bytes", rBuff.size(), rBuff.capacity()); + log.info("resuming audio writes with buffer fill {}/{} bytes", rBuff.size(), rBuff.capacity()); audioWriteState = AudioWriteState::ACTIVE; } else @@ -278,7 +279,7 @@ void EmuAudio::writeFrames(const void *samples, size_t framesToWrite) if(speedMultiplier == 1. && addSoundBuffersOnUnderrun && inputFormat.bytesToTime(rBuff.capacity()).count() <= 1.) // hard cap buffer increase to 1 sec { - logWarn("increasing buffer size due to multiple underruns within a short time"); + log.warn("increasing buffer size due to multiple underruns within a short time"); targetBufferFillBytes += bufferIncrementBytes; resizeAudioBuffer(targetBufferFillBytes); } @@ -309,7 +310,7 @@ void EmuAudio::writeFrames(const void *samples, size_t framesToWrite) } else { - logMsg("overrun, only %zu out of %zu bytes free", freeBytes, bytes); + log.info("overrun, only {} out of {} bytes free", freeBytes, bytes); #ifdef CONFIG_EMUFRAMEWORK_AUDIO_STATS audioStats.overruns++; #endif @@ -323,8 +324,8 @@ void EmuAudio::writeFrames(const void *samples, size_t framesToWrite) { auto bytes = rBuff.size(); auto capacity = rBuff.capacity(); - logMsg("starting audio writes with buffer fill %zu/%zu bytes %.2f/%.2f secs", - bytes, capacity, inputFormat.bytesToTime(bytes).count(), inputFormat.bytesToTime(capacity).count()); + log.info("starting audio writes with buffer fill {}/{} bytes {}/{} secs", + bytes, capacity, inputFormat.bytesToTime(bytes), inputFormat.bytesToTime(capacity)); } audioWriteState = AudioWriteState::ACTIVE; } @@ -338,9 +339,9 @@ void EmuAudio::setRate(int newRate) if(rate_ == newRate) return; if(rate_) - logMsg("set rate:%u -> %u", rate_, newRate); + log.info("set rate:{} -> {}", rate_, newRate); else - logMsg("set rate:%u", newRate); + log.info("set rate:{}", newRate); rate_ = newRate; stop(); } @@ -359,7 +360,7 @@ void EmuAudio::setSpeedMultiplier(double speed) if(speedMultiplier == speed) return; speedMultiplier = speed; - logMsg("set speed multiplier:%f", speed); + log.info("set speed multiplier:{}", speed); updateVolume(); updateAddBuffersOnUnderrun(); diff --git a/EmuFramework/src/EmuSystem.cc b/EmuFramework/src/EmuSystem.cc index 9ee0249ad..2621ac4ee 100644 --- a/EmuFramework/src/EmuSystem.cc +++ b/EmuFramework/src/EmuSystem.cc @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/EmuFramework/src/EmuSystemTask.cc b/EmuFramework/src/EmuSystemTask.cc index 168713d15..47cacf3e8 100644 --- a/EmuFramework/src/EmuSystemTask.cc +++ b/EmuFramework/src/EmuSystemTask.cc @@ -13,7 +13,6 @@ You should have received a copy of the GNU General Public License along with EmuFramework. If not, see */ -#define LOGTAG "EmuSystemTask" #include #include #include @@ -23,6 +22,8 @@ namespace EmuEx { +constexpr SystemLogger log{"EmuSystemTask"}; + EmuSystemTask::EmuSystemTask(EmuApp &app): app{app} {} @@ -60,7 +61,7 @@ void EmuSystemTask::start() }, [&](PauseCommand &) { - //logMsg("got pause command"); + //log.debug("got pause command"); runCmd.frames = fastForwardFrames = 0; assumeExpr(msg.semPtr); msg.semPtr->release(); @@ -80,15 +81,15 @@ void EmuSystemTask::start() if(!runCmd.frames) return true; assumeExpr(runCmd.frames > 0); - //logMsg("running %d frame(s)", runCmd.frames); + //log.debug("running {} frame(s)", runCmd.frames); app.runFrames({this}, runCmd.video, runCmd.audio, runCmd.frames, runCmd.skipForward); return true; }); sem.release(); - logMsg("starting thread event loop"); + log.info("starting thread event loop"); eventLoop.run(started); - logMsg("exiting thread"); + log.info("exiting thread"); commandPort.detach(); }); } @@ -97,7 +98,7 @@ void EmuSystemTask::pause() { if(!taskThread.joinable()) return; - commandPort.send({.command = PauseCommand{}}, true); + commandPort.send({.command = PauseCommand{}}, MessageReplyMode::wait); app.flushMainThreadMessages(); } diff --git a/EmuFramework/src/EmuTiming.cc b/EmuFramework/src/EmuTiming.cc index 3d9106eca..f9c09548d 100644 --- a/EmuFramework/src/EmuTiming.cc +++ b/EmuFramework/src/EmuTiming.cc @@ -15,13 +15,15 @@ #include #include -#include +#include #include #include namespace EmuEx { +constexpr SystemLogger log{"EmuTiming"}; + EmuFrameTimeInfo EmuTiming::advanceFramesWithTime(SteadyClockTimePoint time) { if(!hasTime(startFrameTime)) [[unlikely]] @@ -45,7 +47,7 @@ void EmuTiming::setFrameTime(SteadyClockTime time) { timePerVideoFrame = time; updateScaledFrameTime(); - logMsg("configured frame time:%lldns (%.2f fps)", (long long)timePerVideoFrame.count(), toHz(time)); + log.info("configured frame time:{} ({:g} fps)", timePerVideoFrame, toHz(time)); reset(); } diff --git a/EmuFramework/src/EmuVideo.cc b/EmuFramework/src/EmuVideo.cc index d7c77dfd4..be56f88b6 100644 --- a/EmuFramework/src/EmuVideo.cc +++ b/EmuFramework/src/EmuVideo.cc @@ -71,7 +71,7 @@ bool EmuVideo::setFormat(IG::PixmapDesc desc, EmuSystemTaskContext taskCtx) { Gfx::TextureConfig conf{desc, samplerConfig()}; conf.colorSpace = colSpace; - vidImg = renderer().makePixmapBufferTexture(conf, bufferMode, singleBuffer); + vidImg = renderer().makePixmapBufferTexture(conf, bufferMode); } else { @@ -94,15 +94,9 @@ void EmuVideo::dispatchFormatChanged() onFormatChanged(*this); } -void EmuVideo::syncImageAccess() -{ - rTask->clientWaitSync(std::exchange(fence, {})); -} - EmuVideoImage EmuVideo::startFrame(EmuSystemTaskContext taskCtx) { auto lockedTex = vidImg.lock(); - syncImageAccess(); return {taskCtx, *this, lockedTex}; } @@ -179,19 +173,10 @@ void EmuVideo::finishFrame(EmuSystemTaskContext taskCtx, IG::PixmapView pix) doScreenshot(taskCtx, pix); } app().record(FrameTimeStatEvent::aboutToSubmitFrame); - syncImageAccess(); vidImg.write(pix, {.async = true}); postFrameFinished(taskCtx); } -bool EmuVideo::addFence(Gfx::RendererCommands &cmds) -{ - if(!needsFence) - return false; - fence = cmds.clientWaitSyncReset(fence); - return true; -} - void EmuVideo::clear() { if(!vidImg) @@ -283,12 +268,6 @@ void EmuVideo::setOnFormatChanged(FormatChangedDelegate del) onFormatChanged = del; } -void EmuVideo::updateNeedsFence() -{ - needsFence = singleBuffer && renderer().maxSwapChainImages() > 2; - log.info("{} fence for synchronization", needsFence ? "using" : "not using"); -} - void EmuVideo::setTextureBufferMode(EmuSystem &sys, Gfx::TextureBufferMode mode) { mode = renderer().makeValidTextureBufferMode(mode); @@ -303,27 +282,6 @@ void EmuVideo::setTextureBufferMode(EmuSystem &sys, Gfx::TextureBufferMode mode) resetImage(renderFmt); } -void EmuVideo::setImageBuffers(int num) -{ - assumeExpr(num < 3); - if(!num) - { - num = renderer().maxSwapChainImages() < 3 || renderer().supportsSyncFences() ? 1 : 2; - } - bool useSingleBuffer = num == 1; - bool modeChanged = singleBuffer != useSingleBuffer; - singleBuffer = useSingleBuffer; - updateNeedsFence(); - //log.debug("image buffer count:{} fences:{}", num, needsFence ? "yes" : "no"); - if(modeChanged && vidImg) - resetImage(); -} - -int EmuVideo::imageBuffers() const -{ - return singleBuffer ? 1 : 2; -} - void EmuVideo::setSampler(Gfx::TextureSamplerConfig samplerConf) { useLinearFilter = samplerConf.minLinearFilter; diff --git a/EmuFramework/src/EmuVideoLayer.cc b/EmuFramework/src/EmuVideoLayer.cc index bf1b85012..3e5601be7 100644 --- a/EmuFramework/src/EmuVideoLayer.cc +++ b/EmuFramework/src/EmuVideoLayer.cc @@ -13,7 +13,6 @@ You should have received a copy of the GNU General Public License along with EmuFramework. If not, see */ -#define LOGTAG "VideoLayer" #include #include #include @@ -21,6 +20,7 @@ #include #include "EmuOptions.hh" #include +#include #include #include #include @@ -33,6 +33,8 @@ namespace EmuEx { +constexpr SystemLogger log{"VideoLayer"}; + EmuVideoLayer::EmuVideoLayer(EmuVideo &video, float defaultAspectRatio): video{video}, landscapeAspectRatio{defaultAspectRatio}, @@ -57,12 +59,12 @@ void EmuVideoLayer::place(IG::WindowRect viewRect, IG::WindowRect displayRect, E auto multiresVideoBaseSize = sys.multiresVideoBaseSize(); if(multiresVideoBaseSize.x && x > multiresVideoBaseSize.x) { - logMsg("halving X size for multires content"); + log.info("halving X size for multires content"); x /= 2; } if(multiresVideoBaseSize.y && y > multiresVideoBaseSize.y) { - logMsg("halving Y size for multires content"); + log.info("halving Y size for multires content"); y /= 2; } @@ -71,13 +73,13 @@ void EmuVideoLayer::place(IG::WindowRect viewRect, IG::WindowRect displayRect, E // avoid overly wide images (SNES, etc.) or tall images (2600, etc.) if(aR >= 2.f) { - logMsg("unscaled image too wide, doubling height to compensate"); + log.info("unscaled image too wide, doubling height to compensate"); y *= 2; aR = x / float(y); } else if(aR < 0.8f) { - logMsg("unscaled image too tall, doubling width to compensate"); + log.info("unscaled image too tall, doubling width to compensate"); x *= 2; aR = x / float(y); } @@ -86,12 +88,12 @@ void EmuVideoLayer::place(IG::WindowRect viewRect, IG::WindowRect displayRect, E if(aR > viewportAspectRatio) { scaleFactor = std::max(1, displayRect.xSize() / x); - logMsg("using x scale factor %d", scaleFactor); + log.info("using x scale factor:{}", scaleFactor); } else { scaleFactor = std::max(1, displayRect.ySize() / y); - logMsg("using y scale factor %d", scaleFactor); + log.info("using y scale factor:{}", scaleFactor); } contentRect_.x2 = x * scaleFactor; contentRect_.y2 = y * scaleFactor; @@ -139,7 +141,7 @@ void EmuVideoLayer::place(IG::WindowRect viewRect, IG::WindowRect displayRect, E } contentRect_.fitIn(displayRect); quad.write(0, {.bounds = contentRect_.as(), .textureSpan = texture, .rotation = rotation}); - logMsg("placed game rect, at pixels %d:%d:%d:%d", + log.info("placed game rect at pixels {}:{}:{}:{}", contentRect_.x, contentRect_.y, contentRect_.x2, contentRect_.y2); } placeOverlay(); @@ -174,7 +176,6 @@ void EmuVideoLayer::draw(Gfx::RendererCommands &cmds) if(srgbOutput) cmds.setSrgbFramebufferWrite(true); cmds.basicEffect().drawSprite(cmds, quad, 0, texture); - video.addFence(cmds); vidImgOverlay.draw(cmds, c); if(srgbOutput) cmds.setSrgbFramebufferWrite(false); @@ -236,7 +237,7 @@ void EmuVideoLayer::setEffect(EmuSystem &sys, ImageEffectId effect, IG::PixelFor { userEffect = {}; buildEffectChain(); - logMsg("deleted user effect"); + log.info("deleted user effect"); video.setRenderPixelFormat(sys, video.renderPixelFormat(), videoColorSpace(video.renderPixelFormat())); updateConvertColorSpaceEffect(); } @@ -324,14 +325,14 @@ bool EmuVideoLayer::updateConvertColorSpaceEffect() if(needsConversion && !userEffect) { userEffect = {renderer(), ImageEffectId::DIRECT, IG::PIXEL_RGBA8888, Gfx::ColorSpace::SRGB, samplerConfig(), video.size()}; - logMsg("made sRGB conversion effect"); + log.info("made sRGB conversion effect"); buildEffectChain(); return true; } else if(!needsConversion && userEffect && userEffectId == ImageEffectId::DIRECT) { userEffect = {}; - logMsg("deleted sRGB conversion effect"); + log.info("deleted sRGB conversion effect"); buildEffectChain(); return true; } @@ -364,7 +365,7 @@ void EmuVideoLayer::logOutputFormat() str += " -> effect:"; str += e.imageFormat().name(); } - logMsg("%s", str.data()); + log.info("{}", str); } } diff --git a/EmuFramework/src/KeyConfig.cc b/EmuFramework/src/KeyConfig.cc index f52972850..f81da4643 100644 --- a/EmuFramework/src/KeyConfig.cc +++ b/EmuFramework/src/KeyConfig.cc @@ -13,7 +13,6 @@ You should have received a copy of the GNU General Public License along with EmuFramework. If not, see */ -#define LOGTAG "KeyConfig" #include #include "EmuOptions.hh" #include @@ -23,6 +22,8 @@ namespace EmuEx { +constexpr SystemLogger log{"KeyConfig"}; + KeyConfig KeyConfig::readConfig(MapIO &io) { KeyConfig keyConf; @@ -47,12 +48,12 @@ KeyConfig KeyConfig::readConfig(MapIO &io) { if(k >= keyMax) { - logWarn("key code 0x%X out of range for map type %d", k, (int)keyConf.map); + log.warn("key code {:X} out of range for map type {}", k, (int)keyConf.map); k = 0; } } } - logMsg("read config:%s", keyConf.name.c_str()); + log.info("read config:{}", keyConf.name); return keyConf; } @@ -66,7 +67,7 @@ void KeyConfig::writeConfig(FileIO &io) const bytes += 1; // number of mappings present bytes += keyMap.size() * keyMappingSize; assert(bytes <= 0xFFFF); - logMsg("saving config:%s, %zu bytes", name.c_str(), bytes); + log.info("saving config:{}, {} bytes", name, bytes); io.put(uint16_t(bytes)); io.put(uint16_t(CFGKEY_INPUT_KEY_CONFIGS_V2)); io.put(uint8_t(map)); @@ -91,12 +92,12 @@ void KeyConfig::set(KeyInfo key, MappedKeys mapKey) if(auto it = find(key); it != keyMap.end()) { - logMsg("changing key mapping from:0x%X to 0x%X", it->mapKey[0], mapKey[0]); + log.info("changing key mapping from:{:X} to {:X}", it->mapKey[0], mapKey[0]); it->mapKey = mapKey; } else { - logMsg("adding key mapping:0x%X", mapKey[0]); + log.info("adding key mapping:{:X}", mapKey[0]); keyMap.emplace_back(key, mapKey); } } diff --git a/EmuFramework/src/OutputTimingManager.cc b/EmuFramework/src/OutputTimingManager.cc index c47d9ee84..0784e555e 100644 --- a/EmuFramework/src/OutputTimingManager.cc +++ b/EmuFramework/src/OutputTimingManager.cc @@ -20,6 +20,8 @@ namespace EmuEx { +constexpr SystemLogger log{"OutputTimingManager"}; + bool OutputTimingManager::frameTimeOptionIsValid(FrameTime time) { return time == OutputTimingManager::autoOption || @@ -38,7 +40,7 @@ static FrameTimeConfig bestOutputTimeForScreen(std::span suppor static constexpr double stretchFrameRate = 4.; // accept rates +/- this value do { - logMsg("considering %.2fHz for target %.2fHz", rate, targetRate); + log.info("considering {:g}Hz for target {:g}Hz", rate, targetRate); if(std::abs(rate - targetRate) <= stretchFrameRate) return {rate, refreshMultiplier}; rate /= 2.; // try half the rate until it falls below the target diff --git a/EmuFramework/src/VideoImageEffect.cc b/EmuFramework/src/VideoImageEffect.cc index 85cc11121..28f8e174d 100644 --- a/EmuFramework/src/VideoImageEffect.cc +++ b/EmuFramework/src/VideoImageEffect.cc @@ -13,7 +13,6 @@ You should have received a copy of the GNU General Public License along with EmuFramework. If not, see */ -#define LOGTAG "VideoImageEffect" #include #include #include @@ -27,6 +26,8 @@ namespace EmuEx { +constexpr SystemLogger log{"VideoImageEffect"}; + constexpr VideoImageEffect::EffectDesc directDesc{"direct-v.txt", "direct-f.txt", {1, 1}}; constexpr VideoImageEffect::EffectDesc hq2xDesc{"hq2x-v.txt", "hq2x-f.txt", {2, 2}}; @@ -105,7 +106,7 @@ VideoImageEffect::VideoImageEffect(Gfx::Renderer &r, Id effect, IG::PixelFormat inputImgSize{size}, format{effectFormat(fmt, colSpace)}, colorSpace{colSpace} { quad.write(0, {.bounds = {{-1, -1}, {1, 1}}}); - logMsg("compiling effect:%s", effectName(effect)); + log.info("compiling effect:{}", effectName(effect)); compile(r, effectDesc(effect), samplerConf); } @@ -132,7 +133,7 @@ void VideoImageEffect::compile(Gfx::Renderer &r, EffectDesc desc, Gfx::TextureSa return; // already compiled if(!desc.scale.x) [[unlikely]] { - logErr("invalid effect descriptor"); + log.error("invalid effect descriptor"); return; } renderTargetScale = desc.scale; @@ -146,7 +147,7 @@ void VideoImageEffect::compile(Gfx::Renderer &r, EffectDesc desc, Gfx::TextureSa try { compileEffect(r, desc, true); - logMsg("compiled fallback version of effect"); + log.info("compiled fallback version of effect"); } catch(std::exception &fallbackErr) { diff --git a/EmuFramework/src/VideoImageOverlay.cc b/EmuFramework/src/VideoImageOverlay.cc index c87df833a..379fca13e 100644 --- a/EmuFramework/src/VideoImageOverlay.cc +++ b/EmuFramework/src/VideoImageOverlay.cc @@ -13,7 +13,6 @@ You should have received a copy of the GNU General Public License along with EmuFramework. If not, see */ -#define LOGTAG "VideoImageOverlay" #include #include #include @@ -106,8 +105,7 @@ void VideoImageOverlay::setEffect(Gfx::Renderer &r, ImageOverlayId id, Gfx::Colo texture = {}; return; } - quad.setTask(r.mainTask); - quad.reset({.size = 1}); + quad = {r.mainTask, {.size = 1}}; multiplyBlend = isCrtOverlay(id); auto desc = overlayDesc(id); Gfx::TextureSamplerConfig samplerConf{ .mipFilter = Gfx::MipFilter::NEAREST }; diff --git a/EmuFramework/src/gui/AudioOptionView.cc b/EmuFramework/src/gui/AudioOptionView.cc index 90980304e..f3dcd40ec 100644 --- a/EmuFramework/src/gui/AudioOptionView.cc +++ b/EmuFramework/src/gui/AudioOptionView.cc @@ -24,7 +24,7 @@ AudioOptionView::AudioOptionView(ViewAttachParams attach, bool customMenu): TableView{"Audio Options", attach, item}, snd { - "Sound", &defaultFace(), + "Sound", attach, app().audio().isEnabled(), [this](BoolMenuItem &item) { @@ -33,7 +33,7 @@ AudioOptionView::AudioOptionView(ViewAttachParams attach, bool customMenu): }, soundDuringFastSlowMode { - "Sound During Fast/Slow Mode", &defaultFace(), + "Sound During Fast/Slow Mode", attach, app().audio().isEnabledDuringAltSpeed(), [this](BoolMenuItem &item) { @@ -42,60 +42,60 @@ AudioOptionView::AudioOptionView(ViewAttachParams attach, bool customMenu): }, soundVolumeItem { - {"100%", &defaultFace(), 100}, - {"50%", &defaultFace(), 50}, - {"25%", &defaultFace(), 25}, - {"Custom Value", &defaultFace(), + {"100%", attach, {.id = 100}}, + {"50%", attach, {.id = 50}}, + {"25%", attach, {.id = 25}}, + {"Custom Value", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueRangeInputView(attachParams(), e, "Input 0 to 125", "", [this](EmuApp &app, auto val) { app.audio().setMaxVolume(val); - soundVolume.setSelected((MenuItem::Id)val, *this); + soundVolume.setSelected(MenuId{val}, *this); dismissPrevious(); return true; }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} }, }, soundVolume { - "Volume", &defaultFace(), + "Volume", attach, + MenuId{app().audio().maxVolume()}, + soundVolumeItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { t.resetString(std::format("{}%", app().audio().maxVolume())); return true; }, - .defaultItemOnSelect = [this](TextMenuItem &item) { app().audio().setMaxVolume(item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().audio().setMaxVolume(item.id); } }, - MenuItem::Id(app().audio().maxVolume()), - soundVolumeItem }, soundBuffersItem { - {"1", &defaultFace(), 1}, - {"2", &defaultFace(), 2}, - {"3", &defaultFace(), 3}, - {"4", &defaultFace(), 4}, - {"5", &defaultFace(), 5}, - {"6", &defaultFace(), 6}, - {"7", &defaultFace(), 7}, + {"1", attach, {.id = 1}}, + {"2", attach, {.id = 2}}, + {"3", attach, {.id = 3}}, + {"4", attach, {.id = 4}}, + {"5", attach, {.id = 5}}, + {"6", attach, {.id = 6}}, + {"7", attach, {.id = 7}}, }, soundBuffers { - "Buffer Size In Frames", &defaultFace(), + "Buffer Size In Frames", attach, + MenuId{app().audio().soundBuffers}, + soundBuffersItem, { - .defaultItemOnSelect = [this](TextMenuItem &item) { app().audio().soundBuffers = item.id(); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().audio().soundBuffers = item.id; } }, - MenuItem::Id(app().audio().soundBuffers), - soundBuffersItem }, addSoundBuffersOnUnderrun { - "Auto-increase Buffer Size", &defaultFace(), + "Auto-increase Buffer Size", attach, app().audio().addSoundBuffersOnUnderrunSetting, [this](BoolMenuItem &item) { @@ -107,31 +107,31 @@ AudioOptionView::AudioOptionView(ViewAttachParams attach, bool customMenu): [&] { decltype(audioRateItem) items; - items.emplace_back("Device Native", &defaultFace(), [this](View &view) + items.emplace_back("Device Native", attach, [this](View &view) { app().audio().setRate(0); - audioRate.setSelected(MenuItem::Id(app().audio().rate())); + audioRate.setSelected(MenuId{app().audio().rate()}); view.dismiss(); return false; }); - auto setRateDel = [this](TextMenuItem &item) { app().audio().setRate(item.id()); }; - items.emplace_back("22KHz", &defaultFace(), setRateDel, 22050); - items.emplace_back("32KHz", &defaultFace(), setRateDel, 32000); - items.emplace_back("44KHz", &defaultFace(), setRateDel, 44100); + auto setRateDel = [this](TextMenuItem &item) { app().audio().setRate(item.id); }; + items.emplace_back("22KHz", attach, setRateDel, MenuItem::Config{.id = 22050}); + items.emplace_back("32KHz", attach, setRateDel, MenuItem::Config{.id = 32000}); + items.emplace_back("44KHz", attach, setRateDel, MenuItem::Config{.id = 44100}); if(app().audio().maxRate() >= 48000) - items.emplace_back("48KHz", &defaultFace(), setRateDel, 48000); + items.emplace_back("48KHz", attach, setRateDel, MenuItem::Config{.id = 48000}); return items; }() }, audioRate { - "Sound Rate", &defaultFace(), - MenuItem::Id(app().audio().rate()), + "Sound Rate", attach, + MenuId{app().audio().rate()}, audioRateItem }, audioSoloMix { - "Mix With Other Apps", &defaultFace(), + "Mix With Other Apps", attach, !app().audioManager().soloMix(), [this](BoolMenuItem &item) { @@ -143,28 +143,28 @@ AudioOptionView::AudioOptionView(ViewAttachParams attach, bool customMenu): [this]() { ApiItemContainer items{}; - items.emplace_back("Auto", &defaultFace(), [this](View &view) + items.emplace_back("Auto", attachParams(), [this](View &view) { app().audio().setOutputAPI(Audio::Api::DEFAULT); - doIfUsed(api, [&](auto &api){ api.setSelected(MenuItem::Id(app().audioManager().makeValidAPI())); }); + doIfUsed(api, [&](auto &api){ api.setSelected(MenuId{app().audioManager().makeValidAPI()}); }); view.dismiss(); return false; }); auto &audioManager = app().audioManager(); for(auto desc: audioManager.audioAPIs()) { - items.emplace_back(desc.name, &defaultFace(), [this](TextMenuItem &item) + items.emplace_back(desc.name, attachParams(), [this](TextMenuItem &item) { - app().audio().setOutputAPI(Audio::Api(item.id())); - }, MenuItem::Id(desc.api)); + app().audio().setOutputAPI(Audio::Api(item.id.val)); + }, MenuItem::Config{.id = desc.api}); } return items; }() }, api { - "Audio Driver", &defaultFace(), - MenuItem::Id(app().audioManager().makeValidAPI(app().audio().outputAPI())), + "Audio Driver", attach, + MenuId{app().audioManager().makeValidAPI(app().audio().outputAPI())}, apiItem } { diff --git a/EmuFramework/src/gui/AutosaveSlotView.cc b/EmuFramework/src/gui/AutosaveSlotView.cc index 4e0d0bf8c..5cdc1a4e6 100644 --- a/EmuFramework/src/gui/AutosaveSlotView.cc +++ b/EmuFramework/src/gui/AutosaveSlotView.cc @@ -45,7 +45,7 @@ class EditAutosaveView : public TableView, public EmuAppHelper slotName{slotName_}, rename { - "Rename", &defaultFace(), + "Rename", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, @@ -70,7 +70,7 @@ class EditAutosaveView : public TableView, public EmuAppHelper }, remove { - "Delete", &defaultFace(), + "Delete", attach, [this](const Input::Event &e) { if(slotName == app().autosaveManager().slotName()) @@ -104,14 +104,15 @@ class EditAutosaveView : public TableView, public EmuAppHelper ManageAutosavesView::ManageAutosavesView(ViewAttachParams attach, AutosaveSlotView &srcView, const std::vector &items): TableView{"Manage Save Slots", attach, extraSlotItems}, - srcView{srcView}, extraSlotItems{items} + srcView{srcView} { - for(auto &i : extraSlotItems) + extraSlotItems.reserve(items.size()); + for(auto &i : items) { - i.onSelect = [this](TextMenuItem &item, const Input::Event &e) + extraSlotItems.emplace_back(i.slotName, i.text().stringView(), attach, [this](TextMenuItem &item, const Input::Event &e) { pushAndShow(makeView(*this, static_cast(item).slotName), e); - }; + }); } } @@ -145,7 +146,7 @@ AutosaveSlotView::AutosaveSlotView(ViewAttachParams attach): TableView{"Autosave Slot", attach, menuItems}, newSlot { - "Create New Save Slot", &defaultFace(), [this](const Input::Event &e) + "Create New Save Slot", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, "Save Slot Name", "", [this](EmuApp &app, auto str_) @@ -169,7 +170,7 @@ AutosaveSlotView::AutosaveSlotView(ViewAttachParams attach): }, manageSlots { - "Manage Save Slots", &defaultFace(), [this](const Input::Event &e) + "Manage Save Slots", attach, [this](const Input::Event &e) { if(extraSlotItems.empty()) { @@ -179,7 +180,7 @@ AutosaveSlotView::AutosaveSlotView(ViewAttachParams attach): pushAndShow(makeView(*this, extraSlotItems), e); } }, - actions{"Actions", &defaultBoldFace()} + actions{"Actions", attach} { refreshSlots(); loadItems(); @@ -190,7 +191,7 @@ void AutosaveSlotView::refreshSlots() mainSlot = { std::format("Main: {}", slotDescription(app(), "")), - &defaultFace(), [this]() + attachParams(), [this]() { if(app().autosaveManager().setSlot("")) { @@ -209,7 +210,7 @@ void AutosaveSlotView::refreshSlots() if(e.type() != FS::file_type::directory) return true; auto &item = extraSlotItems.emplace_back(e.name(), std::format("{}: {}", e.name(), slotDescription(app(), e.name())), - &defaultFace(), [this](TextMenuItem &item) + attachParams(), [this](TextMenuItem &item) { if(app().autosaveManager().setSlot(static_cast(item).slotName)) { @@ -224,7 +225,7 @@ void AutosaveSlotView::refreshSlots() noSaveSlot = { "No Save", - &defaultFace(), [this]() + attachParams(), [this]() { if(app().autosaveManager().setSlot(noAutosaveName)) { diff --git a/EmuFramework/src/gui/AutosaveSlotView.hh b/EmuFramework/src/gui/AutosaveSlotView.hh index cdd19e420..d4b97ab34 100644 --- a/EmuFramework/src/gui/AutosaveSlotView.hh +++ b/EmuFramework/src/gui/AutosaveSlotView.hh @@ -32,8 +32,10 @@ public: class SlotTextMenuItem : public TextMenuItem { public: - SlotTextMenuItem(std::string_view slotName, UTF16Convertible auto &&name, Gfx::GlyphTextureSet *face, SelectDelegate selectDel): - TextMenuItem{IG_forward(name), face, selectDel}, + SlotTextMenuItem() = default; + + SlotTextMenuItem(std::string_view slotName, UTF16Convertible auto &&name, ViewAttachParams attach, SelectDelegate selectDel): + TextMenuItem{IG_forward(name), attach, selectDel}, slotName{slotName} {} std::string slotName; diff --git a/EmuFramework/src/gui/BundledGamesView.cc b/EmuFramework/src/gui/BundledGamesView.cc index 03b28170d..43fa9112d 100644 --- a/EmuFramework/src/gui/BundledGamesView.cc +++ b/EmuFramework/src/gui/BundledGamesView.cc @@ -23,6 +23,8 @@ namespace EmuEx { +constexpr SystemLogger log{"BundledGamesView"}; + BundledGamesView::BundledGamesView(ViewAttachParams attach): TableView { @@ -33,14 +35,14 @@ BundledGamesView::BundledGamesView(ViewAttachParams attach): game { { - system().bundledGameInfo(0).displayName, &defaultFace(), + system().bundledGameInfo(0).displayName, attach, [this](const Input::Event &e) { auto &info = system().bundledGameInfo(0); auto file = appContext().openAsset(info.assetName, IOAccessHint::All, {.test = true}); if(!file) { - logErr("error opening bundled game asset: %s", info.assetName); + log.error("error opening bundled game asset:{}", info.assetName); return; } app().createSystemWithMedia(std::move(file), info.assetName, info.assetName, e, {}, attachParams(), diff --git a/EmuFramework/src/gui/ButtonConfigView.cc b/EmuFramework/src/gui/ButtonConfigView.cc index 1cf9541f2..6376b3853 100644 --- a/EmuFramework/src/gui/ButtonConfigView.cc +++ b/EmuFramework/src/gui/ButtonConfigView.cc @@ -28,7 +28,7 @@ namespace EmuEx { -constexpr SystemLogger log; +constexpr SystemLogger log{"ButtonConfigView"}; constexpr int resetItemsSize = 2; static std::string keyNames(MappedKeys keys, const Input::Device &dev) @@ -65,7 +65,7 @@ ButtonConfigView::ButtonConfigView(ViewAttachParams attach, InputManagerView &ro rootIMView{rootIMView_}, reset { - "Unbind All", &defaultFace(), + "Unbind All", attach, [this](const Input::Event &e) { pushAndShowModal(makeView("Really unbind all keys in this category?", @@ -85,7 +85,7 @@ ButtonConfigView::ButtonConfigView(ViewAttachParams attach, InputManagerView &ro }, resetDefaults { - "Reset Defaults", &defaultFace(), + "Reset Defaults", attach, [this](const Input::Event &e) { pushAndShowModal(makeView("Really reset all keys in this category to defaults?", @@ -115,7 +115,7 @@ ButtonConfigView::ButtonConfigView(ViewAttachParams attach, InputManagerView &ro { app().inputManager.toString(key), keyNames(keyConfig.get(key), devConf_.device()), - &defaultFace(), + attach, [this, keyIdxToSet = i](const Input::Event &e) { auto btnSetView = makeView(rootIMView, @@ -138,7 +138,7 @@ void ButtonConfigView::onSet(int catIdx, MappedKeys mapKey) devConf.buildKeyMap(app().inputManager); auto &b = btn[catIdx]; b.set2ndName(keyNames(mapKey, devConf.device())); - b.compile2nd(renderer()); + b.compile2nd(); } bool ButtonConfigView::inputEvent(const Input::Event &e) @@ -168,7 +168,7 @@ void ButtonConfigView::updateKeyNames(const KeyConfig &conf) for(auto &&[i, key]: enumerate(cat.keys)) { btn[i].set2ndName(keyNames(conf.get(key), devConf.device())); - btn[i].compile2nd(renderer()); + btn[i].compile2nd(); } } @@ -176,7 +176,7 @@ ButtonConfigSetView::ButtonConfigSetView(ViewAttachParams attach, InputManagerView &rootIMView, Input::Device &dev, std::string_view actionName, SetDelegate onSet): View{attach}, - text{&defaultFace()}, + text{attach.rendererTask, &defaultFace()}, quads{attach.rendererTask, {.size = 3}}, onSetD{onSet}, dev{dev}, @@ -193,21 +193,21 @@ void ButtonConfigSetView::initPointerUI() if(pointerUIIsInit()) return; log.info("init pointer UI elements"); - unbind = {"Unbind", &defaultFace()}; - cancel = {"Cancel", &defaultFace()}; + unbind = {renderer().mainTask, "Unbind", &defaultFace()}; + cancel = {renderer().mainTask, "Cancel", &defaultFace()}; unbindB.x2 = 1; } void ButtonConfigSetView::place() { - text.compile(renderer(), {.alignment = Gfx::TextAlignment::center}); + text.compile({.alignment = Gfx::TextAlignment::center}); using Quad = decltype(quads)::Type; auto map = quads.map(); Quad{{.bounds = viewRect().as()}}.write(map, 0); if(pointerUIIsInit()) { - unbind.compile(renderer()); - cancel.compile(renderer()); + unbind.compile(); + cancel.compile(); WRect btnFrame; btnFrame.setPosRel(viewRect().pos(LB2DO), unbind.nominalHeight() * 2, LB2DO); unbindB = btnFrame; @@ -320,7 +320,7 @@ void ButtonConfigSetView::draw(Gfx::RendererCommands &__restrict__ cmds) if(pointerUIIsInit()) { cmds.setColor({.2, .2, .2}); - cmds.drawQuads(quadIndices(), 1, 2); // button bg + cmds.drawQuads(1, 2); // button bg } basicEffect.enableAlphaTexture(cmds); if(pointerUIIsInit()) diff --git a/EmuFramework/src/gui/CPUAffinityView.cc b/EmuFramework/src/gui/CPUAffinityView.cc index f4be4fbd1..e14b03a1d 100644 --- a/EmuFramework/src/gui/CPUAffinityView.cc +++ b/EmuFramework/src/gui/CPUAffinityView.cc @@ -15,7 +15,6 @@ #include "CPUAffinityView.hh" #include -#include #include #include @@ -26,25 +25,25 @@ CPUAffinityView::CPUAffinityView(ViewAttachParams attach, int cpuCount): TableView{"Configure CPU Affinity", attach, menuItems}, affinityModeItems { - {"Auto (Use only performance cores or hints for low latency)", &defaultFace(), to_underlying(CPUAffinityMode::Auto)}, - {"Any (Use any core even if it increases latency)", &defaultFace(), to_underlying(CPUAffinityMode::Any)}, - {"Manual (Use cores set in previous menu)", &defaultFace(), to_underlying(CPUAffinityMode::Manual)}, + {"Auto (Use only performance cores or hints for low latency)", attach, {.id = CPUAffinityMode::Auto}}, + {"Any (Use any core even if it increases latency)", attach, {.id = CPUAffinityMode::Any}}, + {"Manual (Use cores set in previous menu)", attach, {.id = CPUAffinityMode::Manual}}, }, affinityMode { - "CPU Affinity Mode", &defaultFace(), + "CPU Affinity Mode", attach, + MenuId{uint8_t(app().cpuAffinityMode)}, + affinityModeItems, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { - t.resetString(wise_enum::to_string(CPUAffinityMode(affinityModeItems[idx].id()))); + t.resetString(wise_enum::to_string(CPUAffinityMode(affinityModeItems[idx].id.val))); return true; }, - .defaultItemOnSelect = [this](TextMenuItem &item) { app().cpuAffinityMode = CPUAffinityMode(item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().cpuAffinityMode = CPUAffinityMode(item.id.val); } }, - MenuItem::Id(uint8_t(app().cpuAffinityMode)), - affinityModeItems }, - cpusHeading{"Manual CPU Affinity", &defaultBoldFace()} + cpusHeading{"Manual CPU Affinity", attach} { menuItems.emplace_back(&affinityMode); menuItems.emplace_back(&cpusHeading); @@ -58,7 +57,7 @@ CPUAffinityView::CPUAffinityView(ViewAttachParams attach, int cpuCount): return std::format("{} (Offline)", i); return std::format("{} ({}MHz)", i, freq / 1000); }(), - &defaultFace(), app().cpuAffinity(i), + attach, app().cpuAffinity(i), [this, i](BoolMenuItem &item) { app().setCPUAffinity(i, item.flipBoolValue(*this)); }); menuItems.emplace_back(&item); } diff --git a/EmuFramework/src/gui/Cheats.cc b/EmuFramework/src/gui/Cheats.cc index 3f62be8c8..a4f04becb 100644 --- a/EmuFramework/src/gui/Cheats.cc +++ b/EmuFramework/src/gui/Cheats.cc @@ -16,7 +16,6 @@ #include #include #include -#include namespace EmuEx { @@ -40,7 +39,7 @@ BaseCheatsView::BaseCheatsView(ViewAttachParams attach): }, edit { - "Add/Edit", &defaultFace(), + "Add/Edit", attach, [this](const Input::Event &e) { auto editCheatsView = EmuApp::makeView(attachParams(), EmuApp::ViewID::EDIT_CHEATS); @@ -54,8 +53,7 @@ BaseCheatsView::BaseCheatsView(ViewAttachParams attach): }); pushAndShow(std::move(editCheatsView), e); } - } -{} + } {} BaseEditCheatListView::BaseEditCheatListView(ViewAttachParams attach, TableView::ItemsDelegate items, TableView::ItemDelegate item): TableView @@ -64,8 +62,7 @@ BaseEditCheatListView::BaseEditCheatListView(ViewAttachParams attach, TableView: attach, items, item - } -{} + } {} void BaseEditCheatListView::setOnCheatListChanged(RefreshCheatsDelegate del) { diff --git a/EmuFramework/src/gui/CreditsView.cc b/EmuFramework/src/gui/CreditsView.cc index d5b36b538..748dbebb4 100644 --- a/EmuFramework/src/gui/CreditsView.cc +++ b/EmuFramework/src/gui/CreditsView.cc @@ -13,12 +13,11 @@ You should have received a copy of the GNU General Public License along with EmuFramework. If not, see */ -#define LOGTAG "CreditsView" #include #include #include #include -#include +#include #include namespace EmuEx @@ -26,7 +25,7 @@ namespace EmuEx CreditsView::CreditsView(ViewAttachParams attach, UTF16String str): View{attach}, - text{std::move(str), &defaultFace()}, + text{attach.rendererTask, std::move(str), &defaultFace()}, animate { [this](IG::FrameParams params) @@ -43,7 +42,7 @@ CreditsView::CreditsView(ViewAttachParams attach, UTF16String str): void CreditsView::prepareDraw() { - text.makeGlyphs(renderer()); + text.makeGlyphs(); } void CreditsView::draw(Gfx::RendererCommands &__restrict__ cmds) @@ -55,7 +54,7 @@ void CreditsView::draw(Gfx::RendererCommands &__restrict__ cmds) void CreditsView::place() { - text.compile(renderer(), {.alignment = Gfx::TextAlignment::center}); + text.compile({.alignment = Gfx::TextAlignment::center}); } bool CreditsView::inputEvent(const Input::Event &e) diff --git a/EmuFramework/src/gui/EmuView.cc b/EmuFramework/src/gui/EmuView.cc index adbd2bc30..8d211afc3 100644 --- a/EmuFramework/src/gui/EmuView.cc +++ b/EmuFramework/src/gui/EmuView.cc @@ -25,17 +25,15 @@ namespace EmuEx { -EmuView::EmuView() {} - EmuView::EmuView(ViewAttachParams attach, EmuVideoLayer *layer, EmuSystem &sys): View{attach}, layer{layer}, sysPtr{&sys}, - frameTimeStats{&defaultFace(), Gfx::IQuads{attach.rendererTask, {.size = 1}}} {} + frameTimeStats{Gfx::Text{attach.rendererTask, &defaultFace()}, Gfx::IQuads{attach.rendererTask, {.size = 1}}} {} void EmuView::prepareDraw() { - doIfUsed(frameTimeStats, [&](auto &stats){ stats.text.makeGlyphs(renderer()); }); + doIfUsed(frameTimeStats, [&](auto &stats){ stats.text.makeGlyphs(); }); #ifdef CONFIG_EMUFRAMEWORK_AUDIO_STATS audioStatsText.makeGlyphs(renderer()); #endif @@ -99,7 +97,7 @@ void EmuView::placeFrameTimeStats() { doIfUsed(frameTimeStats, [&](auto &stats) { - if(stats.text.compile(renderer())) + if(stats.text.compile()) { WRect rect = {{}, {stats.text.pixelSize().x + stats.text.spaceWidth() * 2, stats.text.fullHeight()}}; diff --git a/EmuFramework/src/gui/EmuViewController.cc b/EmuFramework/src/gui/EmuViewController.cc index 361c5401c..1d8c49bc8 100644 --- a/EmuFramework/src/gui/EmuViewController.cc +++ b/EmuFramework/src/gui/EmuViewController.cc @@ -13,7 +13,6 @@ You should have received a copy of the GNU General Public License along with EmuFramework. If not, see */ -#define LOGTAG "EmuViewController" #include #include #include @@ -37,6 +36,8 @@ namespace EmuEx { +constexpr SystemLogger log{"EmuViewController"}; + EmuViewController::EmuViewController(ViewAttachParams viewAttach, VController &vCtrl, EmuVideoLayer &videoLayer, EmuSystem &sys): emuView{viewAttach, &videoLayer, sys}, @@ -48,7 +49,6 @@ EmuViewController::EmuViewController(ViewAttachParams viewAttach, auto &win = viewAttach.window; auto &face = viewAttach.viewManager.defaultFace; auto &screen = *viewAttach.window.screen(); - popup.setFace(face); { auto viewNav = std::make_unique ( @@ -107,7 +107,7 @@ bool EmuMenuViewStack::inputEvent(const Input::Event &e) { if(size() == 1) { - //logMsg("cancel button at view stack root"); + //log.info("cancel button at view stack root"); if(keyEv.repeated()) { return true; @@ -261,7 +261,7 @@ void EmuViewController::placeEmuViews() void EmuViewController::placeElements() { - //logMsg("placing app elements"); + //log.info("placing app elements"); { auto &winData = windowData(popup.window()); winData.applyViewRect(popup); @@ -288,7 +288,7 @@ void EmuViewController::updateMainWindowViewport(IG::Window &win, IG::Viewport v void EmuViewController::updateExtraWindowViewport(IG::Window &win, IG::Viewport viewport, Gfx::RendererTask &task) { - logMsg("view resize for extra window"); + log.info("view resize for extra window"); task.setDefaultViewport(win, viewport); auto &winData = windowData(win); winData.updateWindowViewport(win, viewport, task.renderer()); diff --git a/EmuFramework/src/gui/FilePathOptionView.cc b/EmuFramework/src/gui/FilePathOptionView.cc index 5b087d383..29a5a5a5b 100644 --- a/EmuFramework/src/gui/FilePathOptionView.cc +++ b/EmuFramework/src/gui/FilePathOptionView.cc @@ -28,6 +28,8 @@ namespace EmuEx { +constexpr SystemLogger log{"FilePathOptionView"}; + static FS::FileString savePathStrToDisplayName(IG::ApplicationContext ctx, std::string_view savePathStr) { if(savePathStr.size()) @@ -57,7 +59,7 @@ FilePathOptionView::FilePathOptionView(ViewAttachParams attach, bool customMenu) TableView{"File Path Options", attach, item}, savePath { - savesMenuName(appContext(), system().userSaveDirectory()), &defaultFace(), + savesMenuName(appContext(), system().userSaveDirectory()), attach, [this](const Input::Event &e) { auto multiChoiceView = makeViewWithName("Saves", 4); @@ -139,15 +141,15 @@ FilePathOptionView::FilePathOptionView(ViewAttachParams attach, bool customMenu) }, screenshotPath { - screenshotsMenuName(appContext(), app().userScreenshotPath), &defaultFace(), + screenshotsMenuName(appContext(), app().userScreenshotPath), attach, [this](const Input::Event &e) { pushAndShow(makeViewWithName("Screenshots", app().screenshotDirectory(), [this](CStringView path) { - logMsg("set screenshots path:%s", path.data()); + log.info("set screenshots path:{}", path); app().userScreenshotPath = path; - screenshotPath.compile(screenshotsMenuName(appContext(), path), renderer()); + screenshotPath.compile(screenshotsMenuName(appContext(), path)); }), e); } } @@ -170,7 +172,7 @@ void FilePathOptionView::onSavePathChange(std::string_view path) { app().postMessage(4, false, std::format("App Folder:\n{}", system().fallbackSaveDirectory())); } - savePath.compile(savesMenuName(appContext(), path), renderer()); + savePath.compile(savesMenuName(appContext(), path)); } } diff --git a/EmuFramework/src/gui/FilePicker.cc b/EmuFramework/src/gui/FilePicker.cc index dffb129cf..fcb153977 100644 --- a/EmuFramework/src/gui/FilePicker.cc +++ b/EmuFramework/src/gui/FilePicker.cc @@ -13,7 +13,6 @@ You should have received a copy of the GNU General Public License along with EmuFramework. If not, see */ -#define LOGTAG "FilePicker" #include #include #include @@ -21,7 +20,6 @@ #include #include #include -#include #include namespace EmuEx diff --git a/EmuFramework/src/gui/GUIOptionView.cc b/EmuFramework/src/gui/GUIOptionView.cc index a709bdf58..f865cc999 100644 --- a/EmuFramework/src/gui/GUIOptionView.cc +++ b/EmuFramework/src/gui/GUIOptionView.cc @@ -34,7 +34,7 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): TableView{"GUI Options", attach, item}, pauseUnfocused { - "Pause if unfocused", &defaultFace(), + "Pause if unfocused", attach, app().pauseUnfocused, [this](BoolMenuItem &item) { @@ -43,16 +43,16 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): }, fontSizeItem { - {"2", &defaultFace(), 2000}, - {"3", &defaultFace(), 3000}, - {"4", &defaultFace(), 4000}, - {"5", &defaultFace(), 5000}, - {"6", &defaultFace(), 6000}, - {"7", &defaultFace(), 7000}, - {"8", &defaultFace(), 8000}, - {"9", &defaultFace(), 9000}, - {"10", &defaultFace(), 10000}, - {"Custom Value", &defaultFace(), + {"2", attach, {.id = 2000}}, + {"3", attach, {.id = 3000}}, + {"4", attach, {.id = 4000}}, + {"5", attach, {.id = 5000}}, + {"6", attach, {.id = 6000}}, + {"7", attach, {.id = 7000}}, + {"8", attach, {.id = 8000}}, + {"9", attach, {.id = 9000}}, + {"10", attach, {.id = 10000}}, + {"Custom Value", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, "Input 2.0 to 10.0", "", @@ -61,7 +61,7 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): int scaledIntVal = val * 1000.0; if(app.setFontSize(scaledIntVal)) { - fontSize.setSelected((MenuItem::Id)scaledIntVal, *this); + fontSize.setSelected(MenuId{scaledIntVal}, *this); dismissPrevious(); return true; } @@ -72,26 +72,26 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): } }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} }, }, fontSize { - "Font Size", &defaultFace(), + "Font Size", attach, + MenuId{app().fontSize()}, + fontSizeItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { t.resetString(std::format("{:g}", app().fontSize() / 1000.)); return true; }, - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setFontSize(item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setFontSize(item.id); } }, - (MenuItem::Id)app().fontSize(), - fontSizeItem }, notificationIcon { - "Suspended App Icon", &defaultFace(), + "Suspended App Icon", attach, (bool)app().notificationIconOption().val, [this](BoolMenuItem &item) { @@ -100,55 +100,55 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): }, statusBarItem { - {"Off", &defaultFace(), to_underlying(Tristate::OFF)}, - {"In Emu", &defaultFace(), to_underlying(Tristate::IN_EMU)}, - {"On", &defaultFace(), to_underlying(Tristate::ON)} + {"Off", attach, MenuItem::Config{.id = Tristate::OFF}}, + {"In Emu", attach, MenuItem::Config{.id = Tristate::IN_EMU}}, + {"On", attach, MenuItem::Config{.id = Tristate::ON}} }, statusBar { - "Hide Status Bar", &defaultFace(), - MultiChoiceMenuItem::Delegates + "Hide Status Bar", attach, + MenuId{app().hideStatusBarMode()}, + statusBarItem, + MultiChoiceMenuItem::Config { - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setHideStatusBarMode(Tristate(item.id())); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setHideStatusBarMode(Tristate(item.id.val)); } }, - (MenuItem::Id)app().hideStatusBarMode(), - statusBarItem }, lowProfileOSNavItem { - {"Off", &defaultFace(), to_underlying(Tristate::OFF)}, - {"In Emu", &defaultFace(), to_underlying(Tristate::IN_EMU)}, - {"On", &defaultFace(), to_underlying(Tristate::ON)} + {"Off", attach, MenuItem::Config{.id = Tristate::OFF}}, + {"In Emu", attach, MenuItem::Config{.id = Tristate::IN_EMU}}, + {"On", attach, MenuItem::Config{.id = Tristate::ON}} }, lowProfileOSNav { - "Dim OS UI", &defaultFace(), - MultiChoiceMenuItem::Delegates + "Dim OS UI", attach, + MenuId{app().lowProfileOSNavMode()}, + lowProfileOSNavItem, + MultiChoiceMenuItem::Config { - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setLowProfileOSNavMode(Tristate(item.id())); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setLowProfileOSNavMode(Tristate(item.id.val)); } }, - (MenuItem::Id)app().lowProfileOSNavMode(), - lowProfileOSNavItem }, hideOSNavItem { - {"Off", &defaultFace(), to_underlying(Tristate::OFF)}, - {"In Emu", &defaultFace(), to_underlying(Tristate::IN_EMU)}, - {"On", &defaultFace(), to_underlying(Tristate::ON)} + {"Off", attach, MenuItem::Config{.id = Tristate::OFF}}, + {"In Emu", attach, MenuItem::Config{.id = Tristate::IN_EMU}}, + {"On", attach, MenuItem::Config{.id = Tristate::ON}} }, hideOSNav { - "Hide OS Navigation", &defaultFace(), - MultiChoiceMenuItem::Delegates + "Hide OS Navigation", attach, + MenuId{app().hideOSNavMode()}, + hideOSNavItem, + MultiChoiceMenuItem::Config { - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setHideOSNavMode(Tristate(item.id())); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setHideOSNavMode(Tristate(item.id.val)); } }, - (MenuItem::Id)app().hideOSNavMode(), - hideOSNavItem }, idleDisplayPowerSave { - "Allow Screen Timeout In Emulation", &defaultFace(), + "Allow Screen Timeout In Emulation", attach, app().idleDisplayPowerSave(), [this](BoolMenuItem &item) { @@ -157,7 +157,7 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): }, navView { - "Title Bar", &defaultFace(), + "Title Bar", attach, app().showsTitleBar(), [this](BoolMenuItem &item) { @@ -166,7 +166,7 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): }, backNav { - "Title Back Navigation", &defaultFace(), + "Title Back Navigation", attach, attach.viewManager.needsBackControl, [this](BoolMenuItem &item) { @@ -177,7 +177,7 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): }, systemActionsIsDefaultMenu { - "Default Menu", &defaultFace(), + "Default Menu", attach, app().systemActionsIsDefaultMenu, "Last Used", "System Actions", [this](BoolMenuItem &item) @@ -187,7 +187,7 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): }, showBundledGames { - "Show Bundled Content", &defaultFace(), + "Show Bundled Content", attach, app().showsBundledGames(), [this](BoolMenuItem &item) { @@ -196,7 +196,7 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): }, showBluetoothScan { - "Show Bluetooth Menu Items", &defaultFace(), + "Show Bluetooth Menu Items", attach, app().showsBluetoothScanItems(), [this](BoolMenuItem &item) { @@ -205,7 +205,7 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): }, showHiddenFiles { - "Show Hidden Files", &defaultFace(), + "Show Hidden Files", attach, app().showHiddenFilesInPicker, [this](BoolMenuItem &item) { @@ -214,7 +214,7 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): }, maxRecentContent { - "Max Recent Content Items", std::to_string(app().recentContent.maxRecentContent), &defaultFace(), + "Max Recent Content Items", std::to_string(app().recentContent.maxRecentContent), attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueRangeInputView(attachParams(), e, @@ -229,45 +229,45 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): }, orientationHeading { - "Orientation", &defaultBoldFace() + "Orientation", attach }, menuOrientationItem { - {"Auto", &defaultFace(), Orientations{}}, - {landscapeName, &defaultFace(), Orientations{.landscapeRight = 1}}, - {landscape2Name, &defaultFace(), Orientations{.landscapeLeft = 1}}, - {portraitName, &defaultFace(), Orientations{.portrait = 1}}, - {portrait2Name, &defaultFace(), Orientations{.portraitUpsideDown = 1}}, + {"Auto", attach, {.id = Orientations{}}}, + {landscapeName, attach, {.id = Orientations{.landscapeRight = 1}}}, + {landscape2Name, attach, {.id = Orientations{.landscapeLeft = 1}}}, + {portraitName, attach, {.id = Orientations{.portrait = 1}}}, + {portrait2Name, attach, {.id = Orientations{.portraitUpsideDown = 1}}}, }, menuOrientation { - "In Menu", &defaultFace(), + "In Menu", attach, + MenuId{uint8_t(app().menuOrientation())}, + menuOrientationItem, { - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setMenuOrientation(std::bit_cast(uint8_t(item.id()))); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setMenuOrientation(std::bit_cast(uint8_t(item.id))); } }, - MenuItem::Id(uint8_t(app().menuOrientation())), - menuOrientationItem }, emuOrientationItem { - {"Auto", &defaultFace(), Orientations{}}, - {landscapeName, &defaultFace(), Orientations{.landscapeRight = 1}}, - {landscape2Name, &defaultFace(), Orientations{.landscapeLeft = 1}}, - {portraitName, &defaultFace(), Orientations{.portrait = 1}}, - {portrait2Name, &defaultFace(), Orientations{.portraitUpsideDown = 1}}, + {"Auto", attach, {.id = Orientations{}}}, + {landscapeName, attach, {.id = Orientations{.landscapeRight = 1}}}, + {landscape2Name, attach, {.id = Orientations{.landscapeLeft = 1}}}, + {portraitName, attach, {.id = Orientations{.portrait = 1}}}, + {portrait2Name, attach, {.id = Orientations{.portraitUpsideDown = 1}}}, }, emuOrientation { - "In Emu", &defaultFace(), + "In Emu", attach, + MenuId{uint8_t(app().emuOrientation())}, + emuOrientationItem, { - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setEmuOrientation(std::bit_cast(uint8_t(item.id()))); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setEmuOrientation(std::bit_cast(uint8_t(item.id))); } }, - MenuItem::Id(uint8_t(app().emuOrientation())), - emuOrientationItem }, layoutBehindSystemUI { - "Display Behind OS UI", &defaultFace(), + "Display Behind OS UI", attach, app().doesLayoutBehindSystemUI(), [this](BoolMenuItem &item) { @@ -276,7 +276,7 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): }, setWindowSize { - "Set Window Size", &defaultFace(), + "Set Window Size", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValuePairRangeInputView(attachParams(), e, @@ -290,7 +290,7 @@ GUIOptionView::GUIOptionView(ViewAttachParams attach, bool customMenu): }, toggleFullScreen { - "Toggle Full Screen", &defaultFace(), + "Toggle Full Screen", attach, [this]{ app().emuWindow().toggleFullScreen(); } } { diff --git a/EmuFramework/src/gui/InputManagerView.cc b/EmuFramework/src/gui/InputManagerView.cc index d6ecb4a19..3c22d4acd 100644 --- a/EmuFramework/src/gui/InputManagerView.cc +++ b/EmuFramework/src/gui/InputManagerView.cc @@ -41,13 +41,13 @@ static const char *confirmDeleteProfileStr = "Delete profile from the configurat IdentInputDeviceView::IdentInputDeviceView(ViewAttachParams attach): View(attach), - text{"Push a key on any input device enter its configuration menu", &defaultFace()}, + text{attach.rendererTask, "Push a key on any input device enter its configuration menu", &defaultFace()}, quads{attach.rendererTask, {.size = 1}} {} void IdentInputDeviceView::place() { quads.write(0, {.bounds = displayRect().as()}); - text.compile(renderer(), {.maxLineSize = int(viewRect().xSize() * 0.95f)}); + text.compile({.maxLineSize = int(viewRect().xSize() * 0.95f)}); } bool IdentInputDeviceView::inputEvent(const Input::Event &e) @@ -95,7 +95,7 @@ InputManagerView::InputManagerView(ViewAttachParams attach, inputManager{inputManager_}, deleteDeviceConfig { - "Delete Saved Device Settings", &defaultFace(), + "Delete Saved Device Settings", attach, [this](TextMenuItem &item, View &, const Input::Event &e) { auto &savedInputDevs = inputManager.savedInputDevs; @@ -139,7 +139,7 @@ InputManagerView::InputManagerView(ViewAttachParams attach, }, deleteProfile { - "Delete Saved Key Profile", &defaultFace(), + "Delete Saved Key Profile", attach, [this](TextMenuItem &item, View &, const Input::Event &e) { auto &customKeyConfigs = inputManager.customKeyConfigs; @@ -171,7 +171,7 @@ InputManagerView::InputManagerView(ViewAttachParams attach, }, rescanOSDevices { - "Re-scan OS Input Devices", &defaultFace(), + "Re-scan OS Input Devices", attach, [this](const Input::Event &e) { appContext().enumInputDevices(); @@ -187,7 +187,7 @@ InputManagerView::InputManagerView(ViewAttachParams attach, }, identDevice { - "Auto-detect Device To Setup", &defaultFace(), + "Auto-detect Device To Setup", attach, [this](const Input::Event &e) { auto identView = makeView(); @@ -205,7 +205,7 @@ InputManagerView::InputManagerView(ViewAttachParams attach, }, generalOptions { - "General Options", &defaultFace(), + "General Options", attach, [this](const Input::Event &e) { pushAndShow(makeView(&app().viewController().inputView), e); @@ -213,7 +213,7 @@ InputManagerView::InputManagerView(ViewAttachParams attach, }, deviceListHeading { - "Individual Device Settings", &defaultBoldFace(), + "Individual Device Settings", attach, } { inputManager.onUpdateDevices = [this]() @@ -254,7 +254,7 @@ void InputManagerView::loadItems() inputDevName.reserve(ctx.inputDevices().size()); for(auto &devPtr : ctx.inputDevices()) { - auto &devItem = inputDevName.emplace_back(inputDevData(*devPtr).displayName, &defaultFace(), + auto &devItem = inputDevName.emplace_back(inputDevData(*devPtr).displayName, attachParams(), [this, &dev = *devPtr](const Input::Event &e) { pushAndShowDeviceView(dev, e); @@ -294,7 +294,7 @@ InputManagerOptionsView::InputManagerOptionsView(ViewAttachParams attach, EmuInp TableView{"General Input Options", attach, item}, mogaInputSystem { - "MOGA Controller Support", &defaultFace(), + "MOGA Controller Support", attach, app().mogaManagerIsActive(), [this](BoolMenuItem &item) { @@ -309,7 +309,7 @@ InputManagerOptionsView::InputManagerOptionsView(ViewAttachParams attach, EmuInp }, notifyDeviceChange { - "Notify If Devices Change", &defaultFace(), + "Notify If Devices Change", attach, app().notifyOnInputDeviceChange, [this](BoolMenuItem &item) { @@ -318,11 +318,11 @@ InputManagerOptionsView::InputManagerOptionsView(ViewAttachParams attach, EmuInp }, bluetoothHeading { - "In-app Bluetooth Options", &defaultBoldFace(), + "In-app Bluetooth Options", attach, }, keepBtActive { - "Keep Connections In Background", &defaultFace(), + "Keep Connections In Background", attach, app().keepBluetoothActive, [this](BoolMenuItem &item) { @@ -333,35 +333,35 @@ InputManagerOptionsView::InputManagerOptionsView(ViewAttachParams attach, EmuInp btScanSecsItem { { - "2secs", &defaultFace(), + "2secs", attach, [this]() { setBTScanSecs(2); } }, { - "4secs", &defaultFace(), + "4secs", attach, [this]() { setBTScanSecs(4); } }, { - "6secs", &defaultFace(), + "6secs", attach, [this]() { setBTScanSecs(6); } }, { - "8secs", &defaultFace(), + "8secs", attach, [this]() { setBTScanSecs(8); } }, { - "10secs", &defaultFace(), + "10secs", attach, [this]() { setBTScanSecs(10); @@ -370,7 +370,7 @@ InputManagerOptionsView::InputManagerOptionsView(ViewAttachParams attach, EmuInp }, btScanSecs { - "Scan Time", &defaultFace(), + "Scan Time", attach, []() { switch(BluetoothAdapter::scanSecs) @@ -389,7 +389,7 @@ InputManagerOptionsView::InputManagerOptionsView(ViewAttachParams attach, EmuInp #ifdef CONFIG_BLUETOOTH_SCAN_CACHE_USAGE btScanCache { - "Cache Scan Results", &defaultFace(), + "Cache Scan Results", attach, BluetoothAdapter::scanCacheUsage(), [this](BoolMenuItem &item) { @@ -399,7 +399,7 @@ InputManagerOptionsView::InputManagerOptionsView(ViewAttachParams attach, EmuInp #endif altGamepadConfirm { - "Swap Confirm/Cancel Keys", &defaultFace(), + "Swap Confirm/Cancel Keys", attach, app().swappedConfirmKeys(), [this](BoolMenuItem &item) { @@ -463,7 +463,7 @@ class ProfileSelectMenu : public TextTableView { activeItem = textItem.size(); } - textItem.emplace_back(conf.name, &defaultFace(), + textItem.emplace_back(conf.name, attach, [this, &conf](const Input::Event &e) { auto del = onProfileChange; @@ -478,7 +478,7 @@ class ProfileSelectMenu : public TextTableView continue; if(selectedName == conf.name) activeItem = textItem.size(); - textItem.emplace_back(conf.name, &defaultFace(), + textItem.emplace_back(conf.name, attach, [this, &conf](const Input::Event &e) { auto del = onProfileChange; @@ -501,20 +501,22 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam rootIMView{rootIMView_}, playerItem { - {"Multiple", &defaultFace(), InputDeviceConfig::PLAYER_MULTI}, - {"1", &defaultFace(), 0}, - {"2", &defaultFace(), 1}, - {"3", &defaultFace(), 2}, - {"4", &defaultFace(), 3}, - {"5", &defaultFace(), 4} + {"Multiple", attach, {.id = InputDeviceConfig::PLAYER_MULTI}}, + {"1", attach, {.id = 0}}, + {"2", attach, {.id = 1}}, + {"3", attach, {.id = 2}}, + {"4", attach, {.id = 3}}, + {"5", attach, {.id = 4}} }, player { - "Player", &defaultFace(), + "Player", attach, + MenuId{inputDevData(dev).devConf.player()}, + std::span{playerItem, EmuSystem::maxPlayers + 1uz}, { .defaultItemOnSelect = [this](TextMenuItem &item) { - auto playerVal = item.id(); + auto playerVal = item.id; bool changingMultiplayer = (playerVal == InputDeviceConfig::PLAYER_MULTI && devConf.player() != InputDeviceConfig::PLAYER_MULTI) || (playerVal != InputDeviceConfig::PLAYER_MULTI && devConf.player() == InputDeviceConfig::PLAYER_MULTI); devConf.setPlayer(inputManager, playerVal); @@ -529,12 +531,10 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam onShow(); } }, - MenuItem::Id(inputDevData(dev).devConf.player()), - std::span{playerItem, EmuSystem::maxPlayers + 1uz} }, loadProfile { - u"", &defaultFace(), + u"", attach, [this](const Input::Event &e) { auto profileSelectMenu = makeView(devConf.device(), @@ -551,7 +551,7 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam }, renameProfile { - "Rename Profile", &defaultFace(), + "Rename Profile", attach, [this](const Input::Event &e) { if(!devConf.mutableKeyConf(inputManager)) @@ -577,7 +577,7 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam }, newProfile { - "New Profile", &defaultFace(), + "New Profile", attach, [this](const Input::Event &e) { pushAndShowModal(makeView( @@ -606,7 +606,7 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam }, deleteProfile { - "Delete Profile", &defaultFace(), + "Delete Profile", attach, [this](const Input::Event &e) { if(!devConf.mutableKeyConf(inputManager)) @@ -632,7 +632,7 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam }, iCadeMode { - "iCade Mode", &defaultFace(), + "iCade Mode", attach, inputDevData(dev).devConf.iCadeMode(), [this](BoolMenuItem &item, const Input::Event &e) { @@ -655,7 +655,7 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam }, joystickAxis1DPad { - "Joystick X/Y Axis 1 as D-Pad", &defaultFace(), + "Joystick X/Y Axis 1 as D-Pad", attach, inputDevData(dev).devConf.joystickAxesAsDpad(Input::AxisSetId::stick1), [this](BoolMenuItem &item, const Input::Event &e) { @@ -665,7 +665,7 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam }, joystickAxis2DPad { - "Joystick X/Y Axis 2 as D-Pad", &defaultFace(), + "Joystick X/Y Axis 2 as D-Pad", attach, inputDevData(dev).devConf.joystickAxesAsDpad(Input::AxisSetId::stick2), [this](BoolMenuItem &item, const Input::Event &e) { @@ -675,7 +675,7 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam }, joystickAxisHatDPad { - "Joystick POV Hat as D-Pad", &defaultFace(), + "Joystick POV Hat as D-Pad", attach, inputDevData(dev).devConf.joystickAxesAsDpad(Input::AxisSetId::hat), [this](BoolMenuItem &item, const Input::Event &e) { @@ -685,7 +685,7 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam }, consumeUnboundKeys { - "Handle Unbound Keys", &defaultFace(), + "Handle Unbound Keys", attach, inputDevData(dev).devConf.shouldHandleUnboundKeys, [this](BoolMenuItem &item, const Input::Event &e) { @@ -693,8 +693,8 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam devConf.save(inputManager); } }, - categories{"Action Categories", &defaultBoldFace()}, - options{"Options", &defaultBoldFace()}, + categories{"Action Categories", attach}, + options{"Options", attach}, devConf{inputDevData(dev).devConf} { loadProfile.setName(std::format("Profile: {}", devConf.keyConf(inputManager).name)); @@ -705,7 +705,7 @@ InputManagerDeviceView::InputManagerDeviceView(UTF16String name, ViewAttachParam void InputManagerDeviceView::addCategoryItem(const KeyCategory &cat) { - auto &catItem = inputCategory.emplace_back(cat.name, &defaultFace(), + auto &catItem = inputCategory.emplace_back(cat.name, attachParams(), [this, &cat](const Input::Event &e) { pushAndShow(makeView(rootIMView, cat, devConf), e); @@ -763,7 +763,7 @@ void InputManagerDeviceView::loadItems() void InputManagerDeviceView::onShow() { TableView::onShow(); - loadProfile.compile(std::format("Profile: {}", devConf.keyConf(inputManager).name), renderer()); + loadProfile.compile(std::format("Profile: {}", devConf.keyConf(inputManager).name)); bool keyConfIsMutable = devConf.mutableKeyConf(inputManager); renameProfile.setActive(keyConfIsMutable); deleteProfile.setActive(keyConfIsMutable); diff --git a/EmuFramework/src/gui/LoadProgressView.cc b/EmuFramework/src/gui/LoadProgressView.cc index 3210ab5d8..064ef521b 100644 --- a/EmuFramework/src/gui/LoadProgressView.cc +++ b/EmuFramework/src/gui/LoadProgressView.cc @@ -15,7 +15,7 @@ #include #include -#include +#include #include namespace EmuEx @@ -26,7 +26,7 @@ constexpr SystemLogger log{"LoadProgressView"}; LoadProgressView::LoadProgressView(ViewAttachParams attach, const Input::Event &e, EmuApp::CreateSystemCompleteDelegate onComplete): View{attach}, onComplete{onComplete}, - text{"Loading...", &defaultFace()}, + text{attach.rendererTask, "Loading...", &attach.viewManager.defaultFace}, progessBarQuads{attach.rendererTask, {.size = 1}}, originalEvent{e} { @@ -123,7 +123,7 @@ void LoadProgressView::setPos(int val) void LoadProgressView::place() { - text.compile(renderer()); + text.compile(); updateProgressRect(); } diff --git a/EmuFramework/src/gui/MainMenuView.cc b/EmuFramework/src/gui/MainMenuView.cc index a46fa3f6d..118a6707f 100644 --- a/EmuFramework/src/gui/MainMenuView.cc +++ b/EmuFramework/src/gui/MainMenuView.cc @@ -34,6 +34,8 @@ namespace EmuEx { +constexpr SystemLogger log{"AppMenus"}; + class OptionCategoryView : public TableView, public EmuAppHelper { public: @@ -65,7 +67,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): TableView{EmuApp::mainViewName(), attach, item}, loadGame { - "Open Content", &defaultFace(), + "Open Content", attach, [this](const Input::Event &e) { pushAndShow(FilePicker::forLoading(attachParams(), e), e, false); @@ -73,7 +75,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): }, systemActions { - "System Actions", &defaultFace(), + "System Actions", attach, [this](const Input::Event &e) { if(!system().hasContent()) @@ -83,7 +85,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): }, recentGames { - "Recent Content", &defaultFace(), + "Recent Content", attach, [this](const Input::Event &e) { if(app().recentContent.size()) @@ -94,7 +96,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): }, bundledGames { - "Bundled Content", &defaultFace(), + "Bundled Content", attach, [this](const Input::Event &e) { pushAndShow(makeView(), e); @@ -102,7 +104,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): }, options { - "Options", &defaultFace(), + "Options", attach, [this](const Input::Event &e) { pushAndShow(makeView(*audio, *videoLayer), e); @@ -110,7 +112,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): }, onScreenInputManager { - "On-screen Input Setup", &defaultFace(), + "On-screen Input Setup", attach, [this](const Input::Event &e) { pushAndShow(makeView(app().defaultVController()), e); @@ -118,7 +120,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): }, inputManager { - "Key/Gamepad Input Setup", &defaultFace(), + "Key/Gamepad Input Setup", attach, [this](const Input::Event &e) { pushAndShow(makeView(app().inputManager), e); @@ -126,7 +128,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): }, benchmark { - "Benchmark Content", &defaultFace(), + "Benchmark Content", attach, [this](const Input::Event &e) { pushAndShow(FilePicker::forBenchmarking(attachParams(), e), e, false); @@ -134,7 +136,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): }, scanWiimotes { - "Scan for Wiimotes/iCP/JS1", &defaultFace(), + "Scan for Wiimotes/iCP/JS1", attach, [this](const Input::Event &e) { if(app().bluetoothAdapter()) @@ -161,7 +163,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): }, bluetoothDisconnect { - "Disconnect Bluetooth", &defaultFace(), + "Disconnect Bluetooth", attach, [this](const Input::Event &e) { auto devConnected = Bluetooth::devsConnected(appContext()); @@ -175,7 +177,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): #ifdef CONFIG_BLUETOOTH_SERVER acceptPS3ControllerConnection { - "Scan for PS3 Controller", &defaultFace(), + "Scan for PS3 Controller", attach, [this](const Input::Event &e) { if(app().bluetoothAdapter()) @@ -217,7 +219,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): #endif about { - "About", &defaultFace(), + "About", attach, [this](const Input::Event &e) { pushAndShow(makeView(EmuSystem::creditsViewStr), e); @@ -225,7 +227,7 @@ MainMenuView::MainMenuView(ViewAttachParams attach, bool customMenu): }, exitApp { - "Exit", &defaultFace(), + "Exit", attach, [this]() { appContext().exit(); @@ -294,7 +296,7 @@ static void onScanStatus(EmuApp &app, unsigned status, int arg) void MainMenuView::onShow() { TableView::onShow(); - logMsg("refreshing main menu state"); + log.info("refreshing main menu state"); recentGames.setActive(app().recentContent.size()); systemActions.setActive(system().hasContent()); bluetoothDisconnect.setActive(Bluetooth::devsConnected(appContext())); @@ -353,7 +355,7 @@ OptionCategoryView::OptionCategoryView(ViewAttachParams attach, EmuAudio &audio, subConfig { { - "Video", &defaultFace(), + "Video", attach, [this, &videoLayer](const Input::Event &e) { auto view = EmuApp::makeView(attachParams(), EmuApp::ViewID::VIDEO_OPTIONS); @@ -362,35 +364,35 @@ OptionCategoryView::OptionCategoryView(ViewAttachParams attach, EmuAudio &audio, } }, { - "Audio", &defaultFace(), + "Audio", attach, [this, &audio](const Input::Event &e) { pushAndShow(EmuApp::makeView(attachParams(), EmuApp::ViewID::AUDIO_OPTIONS), e); } }, { - "System", &defaultFace(), + "System", attach, [this](const Input::Event &e) { pushAndShow(EmuApp::makeView(attachParams(), EmuApp::ViewID::SYSTEM_OPTIONS), e); } }, { - "File Paths", &defaultFace(), + "File Paths", attach, [this](const Input::Event &e) { pushAndShow(EmuApp::makeView(attachParams(), EmuApp::ViewID::FILE_PATH_OPTIONS), e); } }, { - "GUI", &defaultFace(), + "GUI", attach, [this](const Input::Event &e) { pushAndShow(EmuApp::makeView(attachParams(), EmuApp::ViewID::GUI_OPTIONS), e); } }, { - "Online Documentation", &defaultFace(), + "Online Documentation", attach, [this] { appContext().openURL("https://www.explusalpha.com/contents/emuex/documentation"); @@ -400,9 +402,9 @@ OptionCategoryView::OptionCategoryView(ViewAttachParams attach, EmuAudio &audio, { if(EmuApp::hasGooglePlayStoreFeatures()) { - subConfig[std::size(subConfig)-1] = + subConfig[lastIndex(subConfig)] = { - "Beta Testing Opt-in/out", &defaultFace(), + "Beta Testing Opt-in/out", attach, [this]() { appContext().openURL(std::format("https://play.google.com/apps/testing/{}", appContext().applicationId)); diff --git a/EmuFramework/src/gui/PlaceVControlsView.cc b/EmuFramework/src/gui/PlaceVControlsView.cc index 7cf488bde..c4cb02daa 100644 --- a/EmuFramework/src/gui/PlaceVControlsView.cc +++ b/EmuFramework/src/gui/PlaceVControlsView.cc @@ -27,11 +27,11 @@ constexpr std::array snapPxSizes{0, 2, 4, 8, 16, 32, 64}; PlaceVControlsView::PlaceVControlsView(ViewAttachParams attach, VController &vController_): View{attach}, - exitText{"Exit", &defaultFace()}, - snapText{"Snap: 0px", &defaultFace()}, + exitText{attach.rendererTask, "Exit", &defaultFace()}, + snapText{attach.rendererTask, "Snap: 0px", &defaultFace()}, vController{vController_}, - quads{attach.rendererTask, {.size = 4}}, - gridIdxs{attach.rendererTask, 2, 2} + gridIdxs{attach.rendererTask, 2, 2}, + quads{attach.rendererTask, {.size = 4}, gridIdxs} { app().applyOSNavStyle(appContext(), true); } @@ -44,8 +44,8 @@ PlaceVControlsView::~PlaceVControlsView() void PlaceVControlsView::place() { dragTracker.reset(); - exitText.compile(renderer()); - snapText.compile(renderer()); + exitText.compile(); + snapText.compile(); exitBtnRect = WRect{{}, exitText.pixelSize()} + (viewRect().pos(C2DO) - exitText.pixelSize() / 2) + WPt{0, exitText.height()}; snapBtnRect = WRect{{}, snapText.pixelSize()} + (viewRect().pos(C2DO) - snapText.pixelSize() / 2) - WPt{0, exitText.height()}; const int lineSize = 1; @@ -79,7 +79,7 @@ void PlaceVControlsView::place() {xPos + lineSize, viewRect().y2}}.as()}}.write(map, 2 + hLines + i); } } - gridIdxs.reset(hLines + vLines, 2); + gridIdxs.reset(2 + hLines + vLines); } bool PlaceVControlsView::inputEvent(const Input::Event &e) @@ -179,11 +179,11 @@ void PlaceVControlsView::draw(Gfx::RendererCommands &__restrict__ cmds) cmds.setColor({.5, .5, .5}); auto &basicEffect = cmds.basicEffect(); basicEffect.disableTexture(cmds); - cmds.drawQuads(quads, gridIdxs, 0, quads.size() - 2); // grid + cmds.drawQuads(quads, 2, quads.size() - 2); // grid vController.draw(cmds, true); cmds.setColor({0, 0, 0, .5}); basicEffect.disableTexture(cmds); - cmds.drawQuads(quads, quadIndices(), 0, 2); // button bg + cmds.drawQuads(quads, 0, 2); // button bg basicEffect.enableAlphaTexture(cmds); exitText.draw(cmds, exitBtnRect.pos(C2DO), C2DO, ColorName::WHITE); snapText.draw(cmds, snapBtnRect.pos(C2DO), C2DO, ColorName::WHITE); diff --git a/EmuFramework/src/gui/PlaceVControlsView.hh b/EmuFramework/src/gui/PlaceVControlsView.hh index 3bdcfa058..541e67a0f 100644 --- a/EmuFramework/src/gui/PlaceVControlsView.hh +++ b/EmuFramework/src/gui/PlaceVControlsView.hh @@ -52,8 +52,8 @@ private: WRect snapBtnRect{}; Input::DragTracker dragTracker; size_t snapPxIdx{}; - Gfx::IQuads quads; Gfx::QuadIndexArray gridIdxs; + Gfx::IQuads quads; }; } diff --git a/EmuFramework/src/gui/PlaceVideoView.cc b/EmuFramework/src/gui/PlaceVideoView.cc index 50705d4cb..e001df3f3 100644 --- a/EmuFramework/src/gui/PlaceVideoView.cc +++ b/EmuFramework/src/gui/PlaceVideoView.cc @@ -25,8 +25,8 @@ PlaceVideoView::PlaceVideoView(ViewAttachParams attach, EmuVideoLayer &layer, VC View(attach), layer{layer}, vController{vController}, - exitText{"Exit", &defaultFace()}, - resetText{"Reset", &defaultFace()}, + exitText{attach.rendererTask, "Exit", &defaultFace()}, + resetText{attach.rendererTask, "Reset", &defaultFace()}, quads{attach.rendererTask, {.size = 4}} { app().applyOSNavStyle(appContext(), true); @@ -44,8 +44,8 @@ void PlaceVideoView::place() auto offsetLimit = viewRect().size() - layer.contentRect().size(); posOffsetLimit = viewRect().isLandscape() ? offsetLimit.x : offsetLimit.y; dragState = {}; - exitText.compile(renderer()); - resetText.compile(renderer()); + exitText.compile(); + resetText.compile(); WRect btnBounds{{0, 0}, {viewRect().xSize(), exitText.nominalHeight() * 2}}; btnBounds.setPos(viewRect().pos(LB2DO), LB2DO); exitBounds = btnBounds; @@ -161,9 +161,9 @@ void PlaceVideoView::draw(Gfx::RendererCommands &__restrict__ cmds) auto &basicEffect = cmds.basicEffect(); basicEffect.disableTexture(cmds); cmds.setVertexArray(quads); - cmds.drawQuads(quadIndices(), 0, 2); // centering lines + cmds.drawQuads(0, 2); // centering lines cmds.setColor({.2, .2, .2, .5}); - cmds.drawQuads(quadIndices(), 2, 2); // button bg + cmds.drawQuads(2, 2); // button bg basicEffect.enableAlphaTexture(cmds); cmds.setColor(ColorName::WHITE); exitText.draw(cmds, exitBounds.pos(C2DO), C2DO); diff --git a/EmuFramework/src/gui/RecentContentView.cc b/EmuFramework/src/gui/RecentContentView.cc index 93ae76c4b..4f15688b0 100644 --- a/EmuFramework/src/gui/RecentContentView.cc +++ b/EmuFramework/src/gui/RecentContentView.cc @@ -25,8 +25,7 @@ namespace EmuEx RecentContentView::RecentContentView(ViewAttachParams attach, RecentContent &recentContent_): TableView { - "Recent Content", - attach, + "Recent Content", attach, [this](const TableView &) { return 1 + recentItems.size(); @@ -38,7 +37,7 @@ RecentContentView::RecentContentView(ViewAttachParams attach, RecentContent &rec }, clear { - "Clear List", &defaultFace(), + "Clear List", attach, [this](const Input::Event &e) { pushAndShowModal(makeView("Really clear the list?", @@ -57,7 +56,7 @@ RecentContentView::RecentContentView(ViewAttachParams attach, RecentContent &rec recentItems.reserve(recentContent_.size()); for(auto &entry : recentContent_) { - auto &recentItem = recentItems.emplace_back(entry.name, &defaultFace(), + auto &recentItem = recentItems.emplace_back(entry.name, attach, [this, &entry](const Input::Event &e) { app().createSystemWithMedia({}, entry.path, appContext().fileUriDisplayName(entry.path), e, {}, attachParams(), diff --git a/EmuFramework/src/gui/ResetAlertView.hh b/EmuFramework/src/gui/ResetAlertView.hh index e91ea8892..87ac82844 100644 --- a/EmuFramework/src/gui/ResetAlertView.hh +++ b/EmuFramework/src/gui/ResetAlertView.hh @@ -29,7 +29,7 @@ public: { TextMenuItem { - "Soft Reset", &defaultFace(), + "Soft Reset", attach, [this, &app]() { app.system().reset(app, EmuSystem::ResetMode::SOFT); @@ -38,14 +38,14 @@ public: }, TextMenuItem { - "Hard Reset", &defaultFace(), + "Hard Reset", attach, [this, &app]() { app.system().reset(app, EmuSystem::ResetMode::HARD); app.showEmulation(); } }, - TextMenuItem{"Cancel", &defaultFace(), [](){}} + TextMenuItem{"Cancel", attach, [](){}} } {} protected: diff --git a/EmuFramework/src/gui/StateSlotView.cc b/EmuFramework/src/gui/StateSlotView.cc index a30e0f300..2f112af5e 100644 --- a/EmuFramework/src/gui/StateSlotView.cc +++ b/EmuFramework/src/gui/StateSlotView.cc @@ -23,6 +23,8 @@ namespace EmuEx { +constexpr SystemLogger log{"StateSlotView"}; + static auto slotHeadingName(EmuSystem &sys) { return std::format("Set State Slot ({})", sys.stateSlot()); @@ -32,7 +34,7 @@ StateSlotView::StateSlotView(ViewAttachParams attach): TableView{"Save States", attach, menuItems}, load { - "Load State", &defaultFace(), + "Load State", attach, [this](TextMenuItem &item, View &, const Input::Event &e) { if(!item.active()) @@ -50,7 +52,7 @@ StateSlotView::StateSlotView(ViewAttachParams attach): }, save { - "Save State", &defaultFace(), + "Save State", attach, [this](const Input::Event &e) { if(app().shouldOverwriteExistingState()) @@ -64,7 +66,7 @@ StateSlotView::StateSlotView(ViewAttachParams attach): } } }, - slotHeading{slotHeadingName(system()), &defaultBoldFace()}, + slotHeading{slotHeadingName(system()), attach}, menuItems { &load, &save, &slotHeading, @@ -96,21 +98,19 @@ void StateSlotView::refreshSlot(int slot) return std::format("{}", sys.stateSlotName(slot)); }; auto &s = stateSlot[slot]; - s = {str(), &defaultFace(), nullptr}; + s = {str(), attachParams(), [this, slot](View &view) + { + auto &sys = system(); + stateSlot[sys.stateSlot()].setHighlighted(false); + stateSlot[slot].setHighlighted(true); + sys.setStateSlot(slot); + log.info("set state slot:{}", sys.stateSlot()); + slotHeading.compile(slotHeadingName(sys)); + load.setActive(sys.stateExists(sys.stateSlot())); + postDraw(); + }}; if(slot == sys.stateSlot()) load.setActive(fileExists); - s.onSelect = - [this, slot](View &view) - { - auto &sys = system(); - stateSlot[sys.stateSlot()].setHighlighted(false); - stateSlot[slot].setHighlighted(true); - sys.setStateSlot(slot); - logMsg("set state slot:%d", sys.stateSlot()); - slotHeading.compile(slotHeadingName(sys), renderer()); - load.setActive(sys.stateExists(sys.stateSlot())); - postDraw(); - }; } void StateSlotView::refreshSlots() diff --git a/EmuFramework/src/gui/SystemActionsView.cc b/EmuFramework/src/gui/SystemActionsView.cc index a90d392c8..48fa6f80d 100644 --- a/EmuFramework/src/gui/SystemActionsView.cc +++ b/EmuFramework/src/gui/SystemActionsView.cc @@ -32,6 +32,8 @@ namespace EmuEx { +constexpr SystemLogger log{"SystemActionsView"}; + static auto autoSaveName(EmuApp &app) { return std::format("Autosave Slot ({})", app.autosaveManager().slotFullName()); @@ -50,7 +52,7 @@ SystemActionsView::SystemActionsView(ViewAttachParams attach, bool customMenu): TableView{"System Actions", attach, item}, cheats { - "Cheats", &defaultFace(), + "Cheats", attach, [this](const Input::Event &e) { if(system().hasContent()) @@ -61,7 +63,7 @@ SystemActionsView::SystemActionsView(ViewAttachParams attach, bool customMenu): }, reset { - "Reset", &defaultFace(), + "Reset", attach, [this](const Input::Event &e) { if(!system().hasContent()) @@ -71,12 +73,12 @@ SystemActionsView::SystemActionsView(ViewAttachParams attach, bool customMenu): }, autosaveSlot { - autoSaveName(app()), &defaultFace(), + autoSaveName(app()), attach, [this](const Input::Event &e) { pushAndShow(makeView(), e); } }, autosaveNow { - saveAutosaveName(app()), &defaultFace(), + saveAutosaveName(app()), attach, [this](TextMenuItem &item, const Input::Event &e) { if(!item.active()) @@ -94,7 +96,7 @@ SystemActionsView::SystemActionsView(ViewAttachParams attach, bool customMenu): }, revertAutosave { - "Load Autosave State", &defaultFace(), + "Load Autosave State", attach, [this](TextMenuItem &item, const Input::Event &e) { if(!item.active()) @@ -118,7 +120,7 @@ SystemActionsView::SystemActionsView(ViewAttachParams attach, bool customMenu): }, stateSlot { - "Manual Save States", &defaultFace(), + "Manual Save States", attach, [this](const Input::Event &e) { pushAndShow(makeView(), e); @@ -126,7 +128,7 @@ SystemActionsView::SystemActionsView(ViewAttachParams attach, bool customMenu): }, addLauncherIcon { - "Add Content Shortcut To Launcher", &defaultFace(), + "Add Content Shortcut To Launcher", attach, [this](const Input::Event &e) { if(!system().hasContent()) @@ -147,7 +149,7 @@ SystemActionsView::SystemActionsView(ViewAttachParams attach, bool customMenu): }, screenshot { - "Screenshot Next Frame", &defaultFace(), + "Screenshot Next Frame", attach, [this](const Input::Event &e) { if(!system().hasContent()) @@ -171,7 +173,7 @@ SystemActionsView::SystemActionsView(ViewAttachParams attach, bool customMenu): }, resetSessionOptions { - "Reset Saved Options", &defaultFace(), + "Reset Saved Options", attach, [this](const Input::Event &e) { if(!app().hasSavedSessionOptions()) @@ -190,7 +192,7 @@ SystemActionsView::SystemActionsView(ViewAttachParams attach, bool customMenu): }, close { - "Close Content", &defaultFace(), + "Close Content", attach, [this](const Input::Event &e) { pushAndShowModal(makeView("Really close current content?", @@ -212,10 +214,10 @@ void SystemActionsView::onShow() if(app().viewController().isShowingEmulation()) return; TableView::onShow(); - logMsg("refreshing action menu state"); + log.info("refreshing action menu state"); assert(system().hasContent()); - autosaveSlot.compile(autoSaveName(app()), renderer()); - autosaveNow.compile(saveAutosaveName(app()), renderer()); + autosaveSlot.compile(autoSaveName(app())); + autosaveNow.compile(saveAutosaveName(app())); autosaveNow.setActive(app().autosaveManager().slotName() != noAutosaveName); revertAutosave.setActive(app().autosaveManager().slotName() != noAutosaveName); resetSessionOptions.setActive(app().hasSavedSessionOptions()); diff --git a/EmuFramework/src/gui/SystemOptionView.cc b/EmuFramework/src/gui/SystemOptionView.cc index a051362b0..d161a41a5 100644 --- a/EmuFramework/src/gui/SystemOptionView.cc +++ b/EmuFramework/src/gui/SystemOptionView.cc @@ -29,39 +29,39 @@ SystemOptionView::SystemOptionView(ViewAttachParams attach, bool customMenu): TableView{"System Options", attach, item}, autosaveTimerItem { - {"Off", &defaultFace(), 0}, - {"5mins", &defaultFace(), 5}, - {"10mins", &defaultFace(), 10}, - {"15mins", &defaultFace(), 15}, + {"Off", attach, {.id = 0}}, + {"5mins", attach, {.id = 5}}, + {"10mins", attach, {.id = 10}}, + {"15mins", attach, {.id = 15}}, }, autosaveTimer { - "Autosave Timer", &defaultFace(), + "Autosave Timer", attach, + MenuId{app().autosaveManager().saveTimer.frequency.count()}, + autosaveTimerItem, { - .defaultItemOnSelect = [this](TextMenuItem &item) { app().autosaveManager().saveTimer.frequency = IG::Minutes{item.id()}; } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().autosaveManager().saveTimer.frequency = IG::Minutes{item.id}; } }, - MenuItem::Id(app().autosaveManager().saveTimer.frequency.count()), - autosaveTimerItem }, autosaveLaunchItem { - {"Main Slot", &defaultFace(), to_underlying(AutosaveLaunchMode::Load)}, - {"Main Slot (No State)", &defaultFace(), to_underlying(AutosaveLaunchMode::LoadNoState)}, - {"No Save Slot", &defaultFace(), to_underlying(AutosaveLaunchMode::NoSave)}, - {"Select Slot", &defaultFace(), to_underlying(AutosaveLaunchMode::Ask)}, + {"Main Slot", attach, {.id = AutosaveLaunchMode::Load}}, + {"Main Slot (No State)", attach, {.id = AutosaveLaunchMode::LoadNoState}}, + {"No Save Slot", attach, {.id = AutosaveLaunchMode::NoSave}}, + {"Select Slot", attach, {.id = AutosaveLaunchMode::Ask}}, }, autosaveLaunch { - "Autosave Launch Mode", &defaultFace(), + "Autosave Launch Mode", attach, + MenuId{app().autosaveManager().autosaveLaunchMode}, + autosaveLaunchItem, { - .defaultItemOnSelect = [this](TextMenuItem &item) { app().autosaveManager().autosaveLaunchMode = AutosaveLaunchMode(item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().autosaveManager().autosaveLaunchMode = AutosaveLaunchMode(item.id.val); } }, - (MenuItem::Id)app().autosaveManager().autosaveLaunchMode, - autosaveLaunchItem }, autosaveContent { - "Autosave Content", &defaultFace(), + "Autosave Content", attach, app().autosaveManager().saveOnlyBackupMemory, "State & Backup RAM", "Only Backup RAM", [this](BoolMenuItem &item) @@ -71,7 +71,7 @@ SystemOptionView::SystemOptionView(ViewAttachParams attach, bool customMenu): }, confirmOverwriteState { - "Confirm Overwrite State", &defaultFace(), + "Confirm Overwrite State", attach, app().confirmOverwriteState, [this](BoolMenuItem &item) { @@ -80,12 +80,12 @@ SystemOptionView::SystemOptionView(ViewAttachParams attach, bool customMenu): }, fastModeSpeedItem { - {"1.5x", &defaultFace(), 150}, - {"2x", &defaultFace(), 200}, - {"4x", &defaultFace(), 400}, - {"8x", &defaultFace(), 800}, - {"16x", &defaultFace(), 1600}, - {"Custom Value", &defaultFace(), + {"1.5x", attach, {.id = 150}}, + {"2x", attach, {.id = 200}}, + {"4x", attach, {.id = 400}}, + {"8x", attach, {.id = 800}}, + {"16x", attach, {.id = 1600}}, + {"Custom Value", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, "Input above 1.0 to 20.0", "", @@ -94,7 +94,7 @@ SystemOptionView::SystemOptionView(ViewAttachParams attach, bool customMenu): auto valAsInt = std::round(val * 100.f); if(app.setAltSpeed(AltSpeedMode::fast, valAsInt)) { - fastModeSpeed.setSelected((MenuItem::Id)valAsInt, *this); + fastModeSpeed.setSelected(MenuId{valAsInt}, *this); dismissPrevious(); return true; } @@ -105,28 +105,28 @@ SystemOptionView::SystemOptionView(ViewAttachParams attach, bool customMenu): } }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} }, }, fastModeSpeed { - "Fast-forward Speed", &defaultFace(), + "Fast-forward Speed", attach, + MenuId{app().altSpeed(AltSpeedMode::fast)}, + fastModeSpeedItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { t.resetString(std::format("{:g}x", app().altSpeedAsDouble(AltSpeedMode::fast))); return true; }, - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setAltSpeed(AltSpeedMode::fast, item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setAltSpeed(AltSpeedMode::fast, item.id); } }, - (MenuItem::Id)app().altSpeed(AltSpeedMode::fast), - fastModeSpeedItem }, slowModeSpeedItem { - {"0.25x", &defaultFace(), 25}, - {"0.50x", &defaultFace(), 50}, - {"Custom Value", &defaultFace(), + {"0.25x", attach, {.id = 25}}, + {"0.50x", attach, {.id = 50}}, + {"Custom Value", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, "Input 0.05 up to 1.0", "", @@ -135,7 +135,7 @@ SystemOptionView::SystemOptionView(ViewAttachParams attach, bool customMenu): auto valAsInt = std::round(val * 100.f); if(app.setAltSpeed(AltSpeedMode::slow, valAsInt)) { - slowModeSpeed.setSelected((MenuItem::Id)valAsInt, *this); + slowModeSpeed.setSelected(MenuId{valAsInt}, *this); dismissPrevious(); return true; } @@ -146,29 +146,29 @@ SystemOptionView::SystemOptionView(ViewAttachParams attach, bool customMenu): } }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} }, }, slowModeSpeed { - "Slow-motion Speed", &defaultFace(), + "Slow-motion Speed", attach, + MenuId{app().altSpeed(AltSpeedMode::slow)}, + slowModeSpeedItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { t.resetString(std::format("{:g}x", app().altSpeedAsDouble(AltSpeedMode::slow))); return true; }, - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setAltSpeed(AltSpeedMode::slow, item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setAltSpeed(AltSpeedMode::slow, item.id); } }, - (MenuItem::Id)app().altSpeed(AltSpeedMode::slow), - slowModeSpeedItem }, rewindStatesItem { - {"0", &defaultFace(), 0}, - {"30", &defaultFace(), 30}, - {"60", &defaultFace(), 60}, - {"Custom Value", &defaultFace(), [this](const Input::Event &e) + {"0", attach, {.id = 0}}, + {"30", attach, {.id = 30}}, + {"60", attach, {.id = 60}}, + {"Custom Value", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueRangeInputView(attachParams(), e, "Input 0 to 50000", std::to_string(app().rewindManager.maxStates), @@ -180,26 +180,26 @@ SystemOptionView::SystemOptionView(ViewAttachParams attach, bool customMenu): return true; }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} }, }, rewindStates { - "Rewind States", &defaultFace(), + "Rewind States", attach, + MenuId{app().rewindManager.maxStates}, + rewindStatesItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { t.resetString(std::format("{}", app().rewindManager.maxStates)); return true; }, - .defaultItemOnSelect = [this](TextMenuItem &item) { app().rewindManager.updateMaxStates(item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().rewindManager.updateMaxStates(item.id); } }, - MenuItem::Id(app().rewindManager.maxStates), - rewindStatesItem }, rewindTimeInterval { - "Rewind State Interval (Seconds)", std::to_string(app().rewindManager.saveTimer.frequency.count()), &defaultFace(), + "Rewind State Interval (Seconds)", std::to_string(app().rewindManager.saveTimer.frequency.count()), attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueRangeInputView(attachParams(), e, @@ -214,7 +214,7 @@ SystemOptionView::SystemOptionView(ViewAttachParams attach, bool customMenu): }, performanceMode { - "Performance Mode", &defaultFace(), + "Performance Mode", attach, app().useSustainedPerformanceMode, "Normal", "Sustained", [this](BoolMenuItem &item) @@ -224,7 +224,7 @@ SystemOptionView::SystemOptionView(ViewAttachParams attach, bool customMenu): }, noopThread { - "No-op Thread (Experimental)", &defaultFace(), + "No-op Thread (Experimental)", attach, (bool)app().useNoopThread, [this](BoolMenuItem &item) { @@ -233,7 +233,7 @@ SystemOptionView::SystemOptionView(ViewAttachParams attach, bool customMenu): }, cpuAffinity { - "Configure CPU Affinity", &defaultFace(), + "Configure CPU Affinity", attach, [this](const Input::Event &e) { pushAndShow(makeView(appContext().cpuCount()), e); diff --git a/EmuFramework/src/gui/TouchConfigView.cc b/EmuFramework/src/gui/TouchConfigView.cc index bd151a4d2..a299beb20 100644 --- a/EmuFramework/src/gui/TouchConfigView.cc +++ b/EmuFramework/src/gui/TouchConfigView.cc @@ -20,7 +20,6 @@ #include #include #include -#include #include "PlaceVideoView.hh" #include "PlaceVControlsView.hh" #include @@ -75,10 +74,10 @@ class DPadElementConfigView : public TableView, public EmuAppHelper(attachParams(), e, "Input 1.0 to 3.0", "", @@ -87,7 +86,7 @@ class DPadElementConfigView : public TableView, public EmuAppHelpersetDeadzone(renderer(), scaledIntVal, window())) { - deadzone.setSelected((MenuItem::Id)scaledIntVal, *this); + deadzone.setSelected(MenuId{scaledIntVal}, *this); dismissPrevious(); return true; } @@ -98,31 +97,31 @@ class DPadElementConfigView : public TableView, public EmuAppHelperdeadzone()}, + deadzoneItems, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { t.resetString(std::format("{:g}mm", elem.dPad()->deadzone() / 100.)); return true; }, - .defaultItemOnSelect = [this](TextMenuItem &item) { elem.dPad()->setDeadzone(renderer(), item.id(), window()); } + .defaultItemOnSelect = [this](TextMenuItem &item) { elem.dPad()->setDeadzone(renderer(), item.id, window()); } }, - MenuItem::Id{elem.dPad()->deadzone()}, - deadzoneItems }, diagonalSensitivityItems { - {"None", &defaultFace(), 1000}, - {"33% (Low)", &defaultFace(), 667}, - {"43% (Medium-Low)", &defaultFace(), 570}, - {"50% (Medium)", &defaultFace(), 500}, - {"60% (High)", &defaultFace(), 400}, - {"Custom Value", &defaultFace(), + {"None", attach, {.id = 1000}}, + {"33% (Low)", attach, {.id = 667}}, + {"43% (Medium-Low)", attach, {.id = 570}}, + {"50% (Medium)", attach, {.id = 500}}, + {"60% (High)", attach, {.id = 400}}, + {"Custom Value", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, "Input 0 to 99.0", "", @@ -133,7 +132,7 @@ class DPadElementConfigView : public TableView, public EmuAppHelpersetDiagonalSensitivity(renderer(), val)) { - diagonalSensitivity.setSelected((MenuItem::Id)scaledIntVal, *this); + diagonalSensitivity.setSelected(MenuId{scaledIntVal}, *this); dismissPrevious(); return true; } @@ -144,45 +143,45 @@ class DPadElementConfigView : public TableView, public EmuAppHelperdiagonalSensitivity() * 1000.f}, + diagonalSensitivityItems, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { t.resetString(std::format("{:g}%", 100.f - elem.dPad()->diagonalSensitivity() * 100.f)); return true; }, - .defaultItemOnSelect = [this](TextMenuItem &item) { elem.dPad()->setDiagonalSensitivity(renderer(), float(item.id()) / 1000.f); } + .defaultItemOnSelect = [this](TextMenuItem &item) { elem.dPad()->setDiagonalSensitivity(renderer(), float(item.id) / 1000.f); } }, - MenuItem::Id(elem.dPad()->diagonalSensitivity() * 1000.f), - diagonalSensitivityItems }, stateItems { - {ctrlStateStr[0], &defaultFace(), to_underlying(VControllerState::OFF)}, - {ctrlStateStr[1], &defaultFace(), to_underlying(VControllerState::SHOWN)}, - {ctrlStateStr[2], &defaultFace(), to_underlying(VControllerState::HIDDEN)}, + {ctrlStateStr[0], attach, {.id = VControllerState::OFF}}, + {ctrlStateStr[1], attach, {.id = VControllerState::SHOWN}}, + {ctrlStateStr[2], attach, {.id = VControllerState::HIDDEN}}, }, state { - "State", &defaultFace(), + "State", attach, + MenuId{elem.state}, + stateItems, { .defaultItemOnSelect = [this](TextMenuItem &item) { - elem.state = VControllerState(item.id()); + elem.state = VControllerState(item.id.val); vCtrl.place(); } }, - MenuItem::Id(elem.state), - stateItems }, showBoundingArea { - "Show Bounding Area", &defaultFace(), + "Show Bounding Area", attach, elem.dPad()->showBounds(), [this](BoolMenuItem &item) { @@ -193,7 +192,7 @@ class DPadElementConfigView : public TableView, public EmuAppHelper("Really remove this d-pad?", @@ -209,23 +208,23 @@ class DPadElementConfigView : public TableView, public EmuAppHelperconfig.keys[0]), &defaultFace(), + "Up", app().inputManager.toString(elem.dPad()->config.keys[0]), attach, [this](const Input::Event &e) { assignAction(0, e); } }, { - "Right", app().inputManager.toString(elem.dPad()->config.keys[1]), &defaultFace(), + "Right", app().inputManager.toString(elem.dPad()->config.keys[1]), attach, [this](const Input::Event &e) { assignAction(1, e); } }, { - "Down", app().inputManager.toString(elem.dPad()->config.keys[2]), &defaultFace(), + "Down", app().inputManager.toString(elem.dPad()->config.keys[2]), attach, [this](const Input::Event &e) { assignAction(2, e); } }, { - "Left", app().inputManager.toString(elem.dPad()->config.keys[3]), &defaultFace(), + "Left", app().inputManager.toString(elem.dPad()->config.keys[3]), attach, [this](const Input::Event &e) { assignAction(3, e); } } } {} @@ -268,10 +267,10 @@ class DPadElementConfigView : public TableView, public EmuAppHelperappendItem(app().inputManager.toString(k), [this, k](TextMenuItem &item, View &parentView, const Input::Event &) { - elem.dPad()->config.keys[item.id()] = k; - actions[item.id()].set2ndName(app().inputManager.toString(k)); + elem.dPad()->config.keys[item.id] = k; + actions[item.id].set2ndName(app().inputManager.toString(k)); parentView.dismiss(); - }).setId(idx); + }).id = idx; } }); pushAndShow(std::move(multiChoiceView), e); @@ -291,7 +290,7 @@ class ButtonElementConfigView : public TableView, public EmuAppHelper("Assign Action", 16); @@ -319,31 +318,31 @@ class ButtonElementConfigView : public TableView, public EmuAppHelper("Really remove this button?", @@ -397,51 +396,51 @@ class ButtonGroupElementConfigView : public TableView, public EmuAppHelper(attachParams(), e, "Input 0 to 8", "", @@ -449,17 +448,19 @@ class ButtonGroupElementConfigView : public TableView, public EmuAppHelpersetSpacing(val, window()); vCtrl.place(); - space.setSelected(MenuItem::Id(val), *this); + space.setSelected(MenuId{val}, *this); dismissPrevious(); return true; }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} }, }, space { - "Spacing", &defaultFace(), + "Spacing", attach, + MenuId{elem.buttonGroup() ? elem.buttonGroup()->spacing() : 0}, + spaceItems, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -468,78 +469,76 @@ class ButtonGroupElementConfigView : public TableView, public EmuAppHelpersetSpacing(item.id(), window()); + elem.buttonGroup()->setSpacing(item.id, window()); vCtrl.place(); } }, - MenuItem::Id{elem.buttonGroup() ? elem.buttonGroup()->spacing() : 0}, - spaceItems }, staggerItems { - {"-0.75x V", &defaultFace(), 0}, - {"-0.5x V", &defaultFace(), 1}, - {"0", &defaultFace(), 2}, - {"0.5x V", &defaultFace(), 3}, - {"0.75x V", &defaultFace(), 4}, - {"1x H&V", &defaultFace(), 5}, + {"-0.75x V", attach, {.id = 0}}, + {"-0.5x V", attach, {.id = 1}}, + {"0", attach, {.id = 2}}, + {"0.5x V", attach, {.id = 3}}, + {"0.75x V", attach, {.id = 4}}, + {"1x H&V", attach, {.id = 5}}, }, stagger { - "Stagger", &defaultFace(), + "Stagger", attach, + MenuId{elem.buttonGroup() ? elem.buttonGroup()->stagger() : 0}, + staggerItems, { .defaultItemOnSelect = [this](TextMenuItem &item) { - elem.buttonGroup()->setStaggerType(item.id()); + elem.buttonGroup()->setStaggerType(item.id); vCtrl.place(); } }, - MenuItem::Id{elem.buttonGroup() ? elem.buttonGroup()->stagger() : 0}, - staggerItems }, extraXSizeItems { - {touchCtrlExtraBtnSizeMenuName[0], &defaultFace(), touchCtrlExtraBtnSizeMenuVal[0]}, - {touchCtrlExtraBtnSizeMenuName[1], &defaultFace(), touchCtrlExtraBtnSizeMenuVal[1]}, - {touchCtrlExtraBtnSizeMenuName[2], &defaultFace(), touchCtrlExtraBtnSizeMenuVal[2]}, - {touchCtrlExtraBtnSizeMenuName[3], &defaultFace(), touchCtrlExtraBtnSizeMenuVal[3]}, + {touchCtrlExtraBtnSizeMenuName[0], attach, {.id = touchCtrlExtraBtnSizeMenuVal[0]}}, + {touchCtrlExtraBtnSizeMenuName[1], attach, {.id = touchCtrlExtraBtnSizeMenuVal[1]}}, + {touchCtrlExtraBtnSizeMenuName[2], attach, {.id = touchCtrlExtraBtnSizeMenuVal[2]}}, + {touchCtrlExtraBtnSizeMenuName[3], attach, {.id = touchCtrlExtraBtnSizeMenuVal[3]}}, }, extraXSize { - "Extended H Bounds", &defaultFace(), + "Extended H Bounds", attach, + MenuId{elem.buttonGroup() ? elem.buttonGroup()->layout.xPadding : 0}, + extraXSizeItems, { .defaultItemOnSelect = [this](TextMenuItem &item) { - elem.buttonGroup()->layout.xPadding = item.id(); + elem.buttonGroup()->layout.xPadding = item.id; vCtrl.place(); } }, - MenuItem::Id{elem.buttonGroup() ? elem.buttonGroup()->layout.xPadding : 0}, - extraXSizeItems }, extraYSizeItems { - {touchCtrlExtraBtnSizeMenuName[0], &defaultFace(), touchCtrlExtraBtnSizeMenuVal[0]}, - {touchCtrlExtraBtnSizeMenuName[1], &defaultFace(), touchCtrlExtraBtnSizeMenuVal[1]}, - {touchCtrlExtraBtnSizeMenuName[2], &defaultFace(), touchCtrlExtraBtnSizeMenuVal[2]}, - {touchCtrlExtraBtnSizeMenuName[3], &defaultFace(), touchCtrlExtraBtnSizeMenuVal[3]}, + {touchCtrlExtraBtnSizeMenuName[0], attach, {.id = touchCtrlExtraBtnSizeMenuVal[0]}}, + {touchCtrlExtraBtnSizeMenuName[1], attach, {.id = touchCtrlExtraBtnSizeMenuVal[1]}}, + {touchCtrlExtraBtnSizeMenuName[2], attach, {.id = touchCtrlExtraBtnSizeMenuVal[2]}}, + {touchCtrlExtraBtnSizeMenuName[3], attach, {.id = touchCtrlExtraBtnSizeMenuVal[3]}}, }, extraYSize { - "Extended V Bounds", &defaultFace(), + "Extended V Bounds", attach, + MenuId{elem.buttonGroup() ? elem.buttonGroup()->layout.yPadding : 0}, + extraYSizeItems, { .defaultItemOnSelect = [this](TextMenuItem &item) { - elem.buttonGroup()->layout.yPadding = item.id(); + elem.buttonGroup()->layout.yPadding = item.id; vCtrl.place(); } }, - MenuItem::Id{elem.buttonGroup() ? elem.buttonGroup()->layout.yPadding : 0}, - extraYSizeItems }, showBoundingArea { - "Show Bounding Area", &defaultFace(), + "Show Bounding Area", attach, elem.buttonGroup() ? elem.buttonGroup()->showsBounds() : false, [this](BoolMenuItem &item) { @@ -550,7 +549,7 @@ class ButtonGroupElementConfigView : public TableView, public EmuAppHelper("Add Button", 16); @@ -575,7 +574,7 @@ class ButtonGroupElementConfigView : public TableView, public EmuAppHelper("Really remove this button group?", @@ -591,7 +590,7 @@ class ButtonGroupElementConfigView : public TableView, public EmuAppHelper([this]() @@ -677,14 +676,14 @@ class AddNewButtonView : public TableView, public EmuAppHelper for(const auto &c : system().inputDeviceDesc(0).components) { buttons.emplace_back( - c.name, &defaultFace(), + c.name, attach, [this, &c](const Input::Event &e){ add(c); }); } buttons.emplace_back( - rightUIComponents.name, &defaultFace(), + rightUIComponents.name, attach, [this](const Input::Event &e){ add(rightUIComponents); }); buttons.emplace_back( - leftUIComponents.name, &defaultFace(), + leftUIComponents.name, attach, [this](const Input::Event &e){ add(leftUIComponents); }); } @@ -716,11 +715,11 @@ void TouchConfigView::place() void TouchConfigView::refreshTouchConfigMenu() { - alpha.setSelected((MenuItem::Id)vController.buttonAlpha(), *this); + alpha.setSelected(MenuId{vController.buttonAlpha()}, *this); touchCtrl.setSelected((int)vController.gamepadControlsVisibility(), *this); if(EmuSystem::maxPlayers > 1) pointerInput.setSelected((int)vController.inputPlayer(), *this); - size.setSelected((MenuItem::Id)vController.buttonSize(), *this); + size.setSelected(MenuId{vController.buttonSize()}, *this); if(app().vibrationManager().hasVibrator()) { vibrate.setBoolValue(vController.vibrateOnTouchInput(), *this); @@ -733,49 +732,49 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): vController{vCtrl}, touchCtrlItem { - {"Off", &defaultFace(), to_underlying(VControllerVisibility::OFF)}, - {"On", &defaultFace(), to_underlying(VControllerVisibility::ON)}, - {"Auto", &defaultFace(), to_underlying(VControllerVisibility::AUTO)} + {"Off", attach, {.id = VControllerVisibility::OFF}}, + {"On", attach, {.id = VControllerVisibility::ON}}, + {"Auto", attach, {.id = VControllerVisibility::AUTO}} }, touchCtrl { - "Use Virtual Gamepad", &defaultFace(), + "Use Virtual Gamepad", attach, + int(vCtrl.gamepadControlsVisibility()), + touchCtrlItem, { - .defaultItemOnSelect = [this](TextMenuItem &item){ vController.setGamepadControlsVisibility(VControllerVisibility(item.id())); } + .defaultItemOnSelect = [this](TextMenuItem &item){ vController.setGamepadControlsVisibility(VControllerVisibility(item.id.val)); } }, - int(vCtrl.gamepadControlsVisibility()), - touchCtrlItem }, pointerInputItem { - {"1", &defaultFace(), 0}, - {"2", &defaultFace(), 1}, - {"3", &defaultFace(), 2}, - {"4", &defaultFace(), 3}, - {"5", &defaultFace(), 4}, + {"1", attach, {.id = 0}}, + {"2", attach, {.id = 1}}, + {"3", attach, {.id = 2}}, + {"4", attach, {.id = 3}}, + {"5", attach, {.id = 4}}, }, pointerInput { - "Virtual Gamepad Player", &defaultFace(), + "Virtual Gamepad Player", attach, + int(vCtrl.inputPlayer()), + std::span{pointerInputItem, size_t(EmuSystem::maxPlayers)}, { - .defaultItemOnSelect = [this](TextMenuItem &item){ vController.setInputPlayer(item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item){ vController.setInputPlayer(item.id); } }, - int(vCtrl.inputPlayer()), - std::span{pointerInputItem, size_t(EmuSystem::maxPlayers)} }, sizeItem { - {"6.5mm", &defaultFace(), 650}, - {"7mm", &defaultFace(), 700}, - {"7.5mm", &defaultFace(), 750}, - {"8mm", &defaultFace(), 800}, - {"8.5mm", &defaultFace(), 850}, - {"9mm", &defaultFace(), 900}, - {"10mm", &defaultFace(), 1000}, - {"12mm", &defaultFace(), 1200}, - {"14mm", &defaultFace(), 1400}, - {"15mm", &defaultFace(), 1500}, - {"Custom Value", &defaultFace(), + {"6.5mm", attach, {.id = 650}}, + {"7mm", attach, {.id = 700}}, + {"7.5mm", attach, {.id = 750}}, + {"8mm", attach, {.id = 800}}, + {"8.5mm", attach, {.id = 850}}, + {"9mm", attach, {.id = 900}}, + {"10mm", attach, {.id = 1000}}, + {"12mm", attach, {.id = 1200}}, + {"14mm", attach, {.id = 1400}}, + {"15mm", attach, {.id = 1500}}, + {"Custom Value", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, "Input 3.0 to 30.0", "", @@ -784,7 +783,7 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): int scaledIntVal = val * 100.0; if(vController.setButtonSize(scaledIntVal)) { - size.setSelected((MenuItem::Id)scaledIntVal, *this); + size.setSelected(MenuId{scaledIntVal}, *this); dismissPrevious(); return true; } @@ -795,26 +794,26 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): } }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} }, }, size { - "Button Size", &defaultFace(), + "Button Size", attach, + MenuId{vController.buttonSize()}, + sizeItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { t.resetString(std::format("{:g}mm", vController.buttonSize() / 100.)); return true; }, - .defaultItemOnSelect = [this](TextMenuItem &item){ vController.setButtonSize(item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item){ vController.setButtonSize(item.id); } }, - (MenuItem::Id)vController.buttonSize(), - sizeItem }, vibrate { - "Vibration", &defaultFace(), + "Vibration", attach, vController.vibrateOnTouchInput(), [this](BoolMenuItem &item) { @@ -823,7 +822,7 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): }, showOnTouch { - "Show Gamepad If Screen Touched", &defaultFace(), + "Show Gamepad If Screen Touched", attach, vController.showOnTouchInput(), [this](BoolMenuItem &item) { @@ -832,7 +831,7 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): }, highlightPushedButtons { - "Highlight Pushed Buttons", &defaultFace(), + "Highlight Pushed Buttons", attach, vController.highlightPushedButtons, [this](BoolMenuItem &item) { @@ -841,25 +840,25 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): }, alphaItem { - {"0%", &defaultFace(), 0}, - {"10%", &defaultFace(), int(255. * .1)}, - {"25%", &defaultFace(), int(255. * .25)}, - {"50%", &defaultFace(), int(255. * .5)}, - {"65%", &defaultFace(), int(255. * .65)}, - {"75%", &defaultFace(), int(255. * .75)}, + {"0%", attach, {.id = 0}}, + {"10%", attach, {.id = int(255. * .1)}}, + {"25%", attach, {.id = int(255. * .25)}}, + {"50%", attach, {.id = int(255. * .5)}}, + {"65%", attach, {.id = int(255. * .65)}}, + {"75%", attach, {.id = int(255. * .75)}}, }, alpha { - "Blend Amount", &defaultFace(), + "Blend Amount", attach, + MenuId{vController.buttonAlpha()}, + alphaItem, { - .defaultItemOnSelect = [this](TextMenuItem &item){ vController.setButtonAlpha(item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item){ vController.setButtonAlpha(item.id); } }, - (MenuItem::Id)vController.buttonAlpha(), - alphaItem }, btnPlace { - "Set Button Positions", &defaultFace(), + "Set Button Positions", attach, [this](const Input::Event &e) { pushAndShowModal(makeView(vController), e); @@ -867,7 +866,7 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): }, placeVideo { - "Set Video Position", &defaultFace(), + "Set Video Position", attach, [this](const Input::Event &e) { if(!system().hasContent()) @@ -877,7 +876,7 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): }, addButton { - "Add New Button Group", &defaultFace(), + "Add New Button Group", attach, [this](const Input::Event &e) { pushAndShow(makeView(*this, vController), e); @@ -885,7 +884,7 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): }, allowButtonsPastContentBounds { - "Allow Buttons In Display Cutout Area", &defaultFace(), + "Allow Buttons In Display Cutout Area", attach, vController.allowButtonsPastContentBounds(), [this](BoolMenuItem &item) { @@ -895,7 +894,7 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): }, resetEmuPositions { - "Reset Emulated Device Positions", &defaultFace(), + "Reset Emulated Device Positions", attach, [this](const Input::Event &e) { pushAndShowModal(makeView("Reset buttons to default positions?", @@ -911,7 +910,7 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): }, resetEmuGroups { - "Reset Emulated Device Groups", &defaultFace(), + "Reset Emulated Device Groups", attach, [this](const Input::Event &e) { pushAndShowModal(makeView("Reset buttons groups to default?", @@ -928,7 +927,7 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): }, resetUIPositions { - "Reset UI Positions", &defaultFace(), + "Reset UI Positions", attach, [this](const Input::Event &e) { pushAndShowModal(makeView("Reset buttons to default positions?", @@ -944,7 +943,7 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): }, resetUIGroups { - "Reset UI Groups", &defaultFace(), + "Reset UI Groups", attach, [this](const Input::Event &e) { pushAndShowModal(makeView("Reset buttons groups to default?", @@ -961,15 +960,15 @@ TouchConfigView::TouchConfigView(ViewAttachParams attach, VController &vCtrl): }, devButtonsHeading { - "Emulated Device Button Groups", &defaultBoldFace() + "Emulated Device Button Groups", attach }, uiButtonsHeading { - "UI Button Groups", &defaultBoldFace() + "UI Button Groups", attach }, otherHeading { - "Other Options", &defaultBoldFace() + "Other Options", attach } { reloadItems(); @@ -993,7 +992,7 @@ void TouchConfigView::reloadItems() for(auto &elem : vController.deviceElements()) { auto &i = elementItems.emplace_back( - elem.name(app()), &defaultFace(), + elem.name(app().inputManager), attachParams(), [this, &elem](const Input::Event &e) { visit(overloaded @@ -1009,7 +1008,7 @@ void TouchConfigView::reloadItems() for(auto &elem : vController.guiElements()) { auto &i = elementItems.emplace_back( - elem.name(app()), &defaultFace(), + elem.name(app().inputManager), attachParams(), [this, &elem](const Input::Event &e) { visit(overloaded diff --git a/EmuFramework/src/gui/VideoOptionView.cc b/EmuFramework/src/gui/VideoOptionView.cc index 71cd00dd4..4fa1b93e8 100644 --- a/EmuFramework/src/gui/VideoOptionView.cc +++ b/EmuFramework/src/gui/VideoOptionView.cc @@ -32,6 +32,8 @@ namespace EmuEx { +constexpr SystemLogger log{"VideoOptionView"}; + class DetectFrameRateView final: public View, public EmuAppHelper { public: @@ -47,7 +49,7 @@ class DetectFrameRateView final: public View, public EmuAppHelperpushed(Input::DefaultKey::CANCEL)) { - logMsg("aborted detection"); + log.info("aborted detection"); dismiss(); return true; } @@ -106,7 +108,7 @@ class DetectFrameRateView final: public View, public EmuAppHelper slack) { - logMsg("frame times differed by:%f", frameTimeDiffSecs); + log.info("frame times differed by:{}", frameTimeDiffSecs); stableFrameTime = false; } lastFrameTime = frameTime; @@ -116,16 +118,15 @@ class DetectFrameRateView final: public View, public EmuAppHelper(detectedFrameTimeSecs); { - waitForDrawFinished(); if(detectedFrameTime.count()) fpsText.resetString(std::format("{:g}fps", toHz(detectedFrameTimeSecs))); else fpsText.resetString("0fps"); - fpsText.compile(renderer()); + fpsText.compile(); } if(stableFrameTime) { - logMsg("found frame time:%f", detectedFrameTimeSecs.count()); + log.info("found frame time:{}", detectedFrameTimeSecs); onDetectFrameTime(detectedFrameTime); dismiss(); return false; @@ -135,7 +136,7 @@ class DetectFrameRateView final: public View, public EmuAppHelper= framesToTime) { @@ -205,53 +206,53 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): [&] { decltype(textureBufferModeItem) items; - items.emplace_back("Auto (Set optimal mode)", &defaultFace(), [this](View &view) + items.emplace_back("Auto (Set optimal mode)", attach, [this](View &view) { app().textureBufferModeOption() = 0; auto defaultMode = renderer().makeValidTextureBufferMode(); emuVideo().setTextureBufferMode(system(), defaultMode); - textureBufferMode.setSelected(MenuItem::Id(defaultMode)); + textureBufferMode.setSelected(MenuId{defaultMode}); view.dismiss(); return false; - }, 0); + }, MenuItem::Config{.id = 0}); for(auto desc: renderer().textureBufferModes()) { - items.emplace_back(desc.name, &defaultFace(), [this](MenuItem &item) + items.emplace_back(desc.name, attach, [this](MenuItem &item) { - app().textureBufferModeOption() = item.id(); - emuVideo().setTextureBufferMode(system(), Gfx::TextureBufferMode(item.id())); - }, to_underlying(desc.mode)); + app().textureBufferModeOption() = item.id; + emuVideo().setTextureBufferMode(system(), Gfx::TextureBufferMode(item.id.val)); + }, MenuItem::Config{.id = desc.mode}); } return items; }() }, textureBufferMode { - "GPU Copy Mode", &defaultFace(), - MenuItem::Id(renderer().makeValidTextureBufferMode(Gfx::TextureBufferMode(app().textureBufferModeOption().val))), + "GPU Copy Mode", attach, + MenuId{renderer().makeValidTextureBufferMode(Gfx::TextureBufferMode(app().textureBufferModeOption().val))}, textureBufferModeItem }, frameIntervalItem { - {"Full (No Skip)", &defaultFace(), 0}, - {"Full", &defaultFace(), 1}, - {"1/2", &defaultFace(), 2}, - {"1/3", &defaultFace(), 3}, - {"1/4", &defaultFace(), 4}, + {"Full (No Skip)", attach, {.id = 0}}, + {"Full", attach, {.id = 1}}, + {"1/2", attach, {.id = 2}}, + {"1/3", attach, {.id = 3}}, + {"1/4", attach, {.id = 4}}, }, frameInterval { - "Frame Rate Target", &defaultFace(), - MultiChoiceMenuItem::Delegates + "Frame Rate Target", attach, + MenuId{app().frameInterval()}, + frameIntervalItem, + MultiChoiceMenuItem::Config { - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setFrameInterval(item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setFrameInterval(item.id); } }, - MenuItem::Id(app().frameInterval()), - frameIntervalItem }, frameRateItems { - {"Auto (Match screen when rates are similar)", &defaultFace(), + {"Auto (Match screen when rates are similar)", attach, [this] { if(!app().viewController().emuWindowScreen()->frameRateIsReliable()) @@ -260,15 +261,15 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): "using the detected rate may give better results"); } onFrameTimeChange(activeVideoSystem, OutputTimingManager::autoOption); - }, int(OutputTimingManager::autoOption.count()) + }, {.id = OutputTimingManager::autoOption.count()} }, - {"Original (Use emulated system's rate)", &defaultFace(), + {"Original (Use emulated system's rate)", attach, [this] { onFrameTimeChange(activeVideoSystem, OutputTimingManager::originalOption); - }, int(OutputTimingManager::originalOption.count()) + }, {.id = OutputTimingManager::originalOption.count()} }, - {"Detect Custom Rate", &defaultFace(), + {"Detect Custom Rate", attach, [this](const Input::Event &e) { window().setIntendedFrameRate(system().frameRate()); @@ -290,7 +291,7 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): return false; } }, - {"Custom Rate", &defaultFace(), + {"Custom Rate", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueInputView>(attachParams(), e, @@ -299,6 +300,10 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): { if(onFrameTimeChange(activeVideoSystem, fromSeconds(val.second / val.first))) { + if(activeVideoSystem == VideoSystem::NATIVE_NTSC) + frameRate.setSelected(defaultMenuId, *this); + else + frameRatePAL.setSelected(defaultMenuId, *this); dismissPrevious(); return true; } @@ -306,12 +311,14 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): return false; }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} }, }, frameRate { - "Frame Rate", &defaultFace(), + "Frame Rate", attach, + app().outputTimingManager.frameTimeOptionAsMenuId(VideoSystem::NATIVE_NTSC), + frameRateItems, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -324,12 +331,12 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): item.defaultOnSelect(view, e); }, }, - app().outputTimingManager.frameTimeOptionAsMenuId(VideoSystem::NATIVE_NTSC), - frameRateItems }, frameRatePAL { - "Frame Rate (PAL)", &defaultFace(), + "Frame Rate (PAL)", attach, + app().outputTimingManager.frameTimeOptionAsMenuId(VideoSystem::PAL), + frameRateItems, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -342,12 +349,10 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): item.defaultOnSelect(view, e); }, }, - app().outputTimingManager.frameTimeOptionAsMenuId(VideoSystem::PAL), - frameRateItems }, frameTimeStats { - "Show Frame Time Stats", &defaultFace(), + "Show Frame Time Stats", attach, app().showFrameTimeStats, [this](BoolMenuItem &item) { app().showFrameTimeStats = item.flipBoolValue(*this); } }, @@ -358,23 +363,23 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): StaticArrayList aspectRatioItem; for(const auto &i : EmuSystem::aspectRatioInfos()) { - aspectRatioItem.emplace_back(i.name, &defaultFace(), [this](TextMenuItem &item) + aspectRatioItem.emplace_back(i.name, attach, [this](TextMenuItem &item) { - app().setVideoAspectRatio(std::bit_cast(item.id())); - }, std::bit_cast(i.aspect.ratio())); + app().setVideoAspectRatio(std::bit_cast(item.id)); + }, MenuItem::Config{.id = std::bit_cast(i.aspect.ratio())}); } if(EmuSystem::hasRectangularPixels) { - aspectRatioItem.emplace_back("Square Pixels", &defaultFace(), [this]() + aspectRatioItem.emplace_back("Square Pixels", attach, [this]() { app().setVideoAspectRatio(-1); - }, std::bit_cast(-1.f)); + }, MenuItem::Config{.id = std::bit_cast(-1.f)}); } - aspectRatioItem.emplace_back("Fill Display", &defaultFace(), [this]() + aspectRatioItem.emplace_back("Fill Display", attach, [this]() { app().setVideoAspectRatio(0); - }, 0); - aspectRatioItem.emplace_back("Custom Value", &defaultFace(), [this](const Input::Event &e) + }, MenuItem::Config{.id = 0}); + aspectRatioItem.emplace_back("Custom Value", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueInputView>(attachParams(), e, "Input decimal or fraction", "", @@ -383,7 +388,7 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): float ratio = val.first / val.second; if(app.setVideoAspectRatio(ratio)) { - aspectRatio.setSelected(std::bit_cast(ratio), *this); + aspectRatio.setSelected(std::bit_cast(ratio), *this); dismissPrevious(); return true; } @@ -394,13 +399,15 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): } }); return false; - }, MenuItem::DEFAULT_ID); + }, MenuItem::Config{.id = defaultMenuId}); return aspectRatioItem; }() }, aspectRatio { - "Aspect Ratio", &defaultFace(), + "Aspect Ratio", attach, + std::bit_cast(app().videoAspectRatio()), + aspectRatioItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -412,34 +419,34 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): return false; } }, - std::bit_cast(app().videoAspectRatio()), - aspectRatioItem }, zoomItem { - {"100%", &defaultFace(), 100}, - {"90%", &defaultFace(), 90}, - {"80%", &defaultFace(), 80}, - {"Integer-only", &defaultFace(), optionImageZoomIntegerOnly}, - {"Integer-only (Height)", &defaultFace(), optionImageZoomIntegerOnlyY}, - {"Custom Value", &defaultFace(), + {"100%", attach, {.id = 100}}, + {"90%", attach, {.id = 90}}, + {"80%", attach, {.id = 80}}, + {"Integer-only", attach, {.id = optionImageZoomIntegerOnly}}, + {"Integer-only (Height)", attach, {.id = optionImageZoomIntegerOnlyY}}, + {"Custom Value", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueRangeInputView(attachParams(), e, "Input 10 to 200", "", [this](EmuApp &app, auto val) { app.setVideoZoom(val); - zoom.setSelected((MenuItem::Id)val, *this); + zoom.setSelected(MenuId{val}, *this); dismissPrevious(); return true; }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} }, }, zoom { - "Content Zoom", &defaultFace(), + "Content Zoom", attach, + MenuId{app().videoZoom()}, + zoomItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -450,65 +457,63 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): } return false; }, - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setVideoZoom(item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setVideoZoom(item.id); } }, - (MenuItem::Id)app().videoZoom(), - zoomItem }, viewportZoomItem { - {"100%", &defaultFace(), 100}, - {"95%", &defaultFace(), 95}, - {"90%", &defaultFace(), 90}, - {"Custom Value", &defaultFace(), + {"100%", attach, {.id = 100}}, + {"95%", attach, {.id = 95}}, + {"90%", attach, {.id = 90}}, + {"Custom Value", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueRangeInputView(attachParams(), e, "Input 50 to 100", "", [this](EmuApp &app, auto val) { app.setViewportZoom(val); - viewportZoom.setSelected((MenuItem::Id)val, *this); + viewportZoom.setSelected(MenuId{val}, *this); dismissPrevious(); return true; }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} }, }, viewportZoom { - "App Zoom", &defaultFace(), + "App Zoom", attach, + MenuId{app().viewportZoom()}, + viewportZoomItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { t.resetString(std::format("{}%", app().viewportZoom())); return true; }, - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setViewportZoom(item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setViewportZoom(item.id); } }, - (MenuItem::Id)app().viewportZoom(), - viewportZoomItem }, contentRotationItem { - {"Auto", &defaultFace(), std::to_underlying(Rotation::ANY)}, - {"Standard", &defaultFace(), std::to_underlying(Rotation::UP)}, - {"90° Right", &defaultFace(), std::to_underlying(Rotation::RIGHT)}, - {"Upside Down", &defaultFace(), std::to_underlying(Rotation::DOWN)}, - {"90° Left", &defaultFace(), std::to_underlying(Rotation::LEFT)}, + {"Auto", attach, {.id = Rotation::ANY}}, + {"Standard", attach, {.id = Rotation::UP}}, + {"90° Right", attach, {.id = Rotation::RIGHT}}, + {"Upside Down", attach, {.id = Rotation::DOWN}}, + {"90° Left", attach, {.id = Rotation::LEFT}}, }, contentRotation { - "Content Rotation", &defaultFace(), + "Content Rotation", attach, + MenuId{app().contentRotation()}, + contentRotationItem, { - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setContentRotation(Rotation(item.id())); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setContentRotation(Rotation(item.id.val)); } }, - (MenuItem::Id)app().contentRotation(), - contentRotationItem }, placeVideo { - "Set Video Position", &defaultFace(), + "Set Video Position", attach, [this](const Input::Event &e) { if(!system().hasContent()) @@ -518,7 +523,7 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): }, imgFilter { - "Image Interpolation", &defaultFace(), + "Image Interpolation", attach, (bool)app().videoFilterOption(), "None", "Linear", [this](BoolMenuItem &item) @@ -530,99 +535,101 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): }, imgEffectItem { - {"Off", &defaultFace(), std::to_underlying(ImageEffectId::DIRECT)}, - {"hq2x", &defaultFace(), std::to_underlying(ImageEffectId::HQ2X)}, - {"Scale2x", &defaultFace(), std::to_underlying(ImageEffectId::SCALE2X)}, - {"Prescale 2x", &defaultFace(), std::to_underlying(ImageEffectId::PRESCALE2X)}, - {"Prescale 3x", &defaultFace(), std::to_underlying(ImageEffectId::PRESCALE3X)}, - {"Prescale 4x", &defaultFace(), std::to_underlying(ImageEffectId::PRESCALE4X)}, + {"Off", attach, {.id = ImageEffectId::DIRECT}}, + {"hq2x", attach, {.id = ImageEffectId::HQ2X}}, + {"Scale2x", attach, {.id = ImageEffectId::SCALE2X}}, + {"Prescale 2x", attach, {.id = ImageEffectId::PRESCALE2X}}, + {"Prescale 3x", attach, {.id = ImageEffectId::PRESCALE3X}}, + {"Prescale 4x", attach, {.id = ImageEffectId::PRESCALE4X}}, }, imgEffect { - "Image Effect", &defaultFace(), + "Image Effect", attach, + MenuId{app().videoEffectOption().val}, + imgEffectItem, { .defaultItemOnSelect = [this](TextMenuItem &item) { - app().videoEffectOption() = item.id(); + app().videoEffectOption() = item.id; if(emuVideo().image()) { - videoLayer->setEffect(system(), ImageEffectId(item.id()), app().videoEffectPixelFormat()); + videoLayer->setEffect(system(), ImageEffectId(item.id.val), app().videoEffectPixelFormat()); app().viewController().postDrawToEmuWindows(); } } }, - (MenuItem::Id)app().videoEffectOption().val, - imgEffectItem }, overlayEffectItem { - {"Off", &defaultFace(), 0}, - {"Scanlines", &defaultFace(), std::to_underlying(ImageOverlayId::SCANLINES)}, - {"Scanlines 2x", &defaultFace(), std::to_underlying(ImageOverlayId::SCANLINES_2)}, - {"LCD Grid", &defaultFace(), std::to_underlying(ImageOverlayId::LCD)}, - {"CRT Mask", &defaultFace(), std::to_underlying(ImageOverlayId::CRT_MASK)}, - {"CRT Mask .5x", &defaultFace(), std::to_underlying(ImageOverlayId::CRT_MASK_2)}, - {"CRT Grille", &defaultFace(), std::to_underlying(ImageOverlayId::CRT_GRILLE)}, - {"CRT Grille .5x", &defaultFace(), std::to_underlying(ImageOverlayId::CRT_GRILLE_2)} + {"Off", attach, {.id = 0}}, + {"Scanlines", attach, {.id = ImageOverlayId::SCANLINES}}, + {"Scanlines 2x", attach, {.id = ImageOverlayId::SCANLINES_2}}, + {"LCD Grid", attach, {.id = ImageOverlayId::LCD}}, + {"CRT Mask", attach, {.id = ImageOverlayId::CRT_MASK}}, + {"CRT Mask .5x", attach, {.id = ImageOverlayId::CRT_MASK_2}}, + {"CRT Grille", attach, {.id = ImageOverlayId::CRT_GRILLE}}, + {"CRT Grille .5x", attach, {.id = ImageOverlayId::CRT_GRILLE_2}} }, overlayEffect { - "Overlay Effect", &defaultFace(), + "Overlay Effect", attach, + MenuId{app().overlayEffectOption().val}, + overlayEffectItem, { .defaultItemOnSelect = [this](TextMenuItem &item) { - app().overlayEffectOption() = item.id(); - videoLayer->setOverlay((ImageOverlayId)item.id()); + app().overlayEffectOption() = item.id; + videoLayer->setOverlay((ImageOverlayId)item.id.val); app().viewController().postDrawToEmuWindows(); } }, - (MenuItem::Id)app().overlayEffectOption().val, - overlayEffectItem }, overlayEffectLevelItem { - {"100%", &defaultFace(), 100}, - {"75%", &defaultFace(), 75}, - {"50%", &defaultFace(), 50}, - {"25%", &defaultFace(), 25}, - {"Custom Value", &defaultFace(), + {"100%", attach, {.id = 100}}, + {"75%", attach, {.id = 75}}, + {"50%", attach, {.id = 50}}, + {"25%", attach, {.id = 25}}, + {"Custom Value", attach, [this](const Input::Event &e) { app().pushAndShowNewCollectValueRangeInputView(attachParams(), e, "Input 0 to 100", "", [this](EmuApp &app, auto val) { app.setOverlayEffectLevel(*videoLayer, val); - overlayEffectLevel.setSelected((MenuItem::Id)val, *this); + overlayEffectLevel.setSelected(MenuId{val}, *this); dismissPrevious(); return true; }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} }, }, overlayEffectLevel { - "Overlay Effect Level", &defaultFace(), + "Overlay Effect Level", attach, + MenuId{app().overlayEffectLevel()}, + overlayEffectLevelItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { t.resetString(std::format("{}%", app().overlayEffectLevel())); return true; }, - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setOverlayEffectLevel(*videoLayer, item.id()); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setOverlayEffectLevel(*videoLayer, item.id); } }, - (MenuItem::Id)app().overlayEffectLevel(), - overlayEffectLevelItem }, imgEffectPixelFormatItem { - {"Auto (Match display format)", &defaultFace(), PIXEL_NONE}, - {"RGBA8888", &defaultFace(), PIXEL_RGBA8888}, - {"RGB565", &defaultFace(), PIXEL_RGB565}, + {"Auto (Match display format)", attach, {.id = PIXEL_NONE}}, + {"RGBA8888", attach, {.id = PIXEL_RGBA8888}}, + {"RGB565", attach, {.id = PIXEL_RGB565}}, }, imgEffectPixelFormat { - "Effect Color Format", &defaultFace(), + "Effect Color Format", attach, + MenuId{app().videoEffectPixelFormatOption().val}, + imgEffectPixelFormatItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -636,13 +643,11 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): }, .defaultItemOnSelect = [this](TextMenuItem &item) { - app().videoEffectPixelFormatOption() = item.id(); + app().videoEffectPixelFormatOption() = item.id; videoLayer->setEffectFormat(app().videoEffectPixelFormat()); app().viewController().postDrawToEmuWindows(); } }, - (MenuItem::Id)app().videoEffectPixelFormatOption().val, - imgEffectPixelFormatItem }, windowPixelFormatItem { @@ -651,7 +656,7 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): decltype(windowPixelFormatItem) items; auto setWindowDrawableConfigDel = [this](TextMenuItem &item) { - auto conf = unpackDrawableConfig(item.id()); + auto conf = unpackDrawableConfig(item.id); if(!app().setWindowDrawableConfig(conf)) { app().postMessage("Restart app for option to take effect"); @@ -660,17 +665,19 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): renderPixelFormat.updateDisplayString(); imgEffectPixelFormat.updateDisplayString(); }; - items.emplace_back("Auto", &defaultFace(), setWindowDrawableConfigDel, 0); + items.emplace_back("Auto", attach, setWindowDrawableConfigDel, MenuItem::Config{.id = 0}); for(auto desc: renderer().supportedDrawableConfigs()) { - items.emplace_back(desc.name, &defaultFace(), setWindowDrawableConfigDel, pack(desc.config)); + items.emplace_back(desc.name, attach, setWindowDrawableConfigDel, MenuItem::Config{.id = pack(desc.config)}); } return items; }() }, windowPixelFormat { - "Display Color Format", &defaultFace(), + "Display Color Format", attach, + MenuId{pack(app().windowDrawableConfig())}, + windowPixelFormatItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -683,12 +690,10 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): return false; } }, - MenuItem::Id(pack(app().windowDrawableConfig())), - windowPixelFormatItem }, secondDisplay { - "2nd Window (for testing only)", &defaultFace(), + "2nd Window (for testing only)", attach, false, [this](BoolMenuItem &item) { @@ -697,7 +702,7 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): }, showOnSecondScreen { - "External Screen", &defaultFace(), + "External Screen", attach, (bool)app().showOnSecondScreenOption(), "OS Managed", "Emu Content", [this](BoolMenuItem &item) @@ -707,40 +712,18 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): app().setEmuViewOnExtraWindow(app().showOnSecondScreenOption(), *appContext().screens()[1]); } }, - imageBuffersItem - { - {"Auto", &defaultFace(), 0}, - {"1 (Syncs GPU each frame, less input lag)", &defaultFace(), 1}, - {"2 (More stable, may add 1 frame of lag)", &defaultFace(), 2}, - }, - imageBuffers - { - "Image Buffers", &defaultFace(), - { - .onSetDisplayString = [this](auto idx, Gfx::Text &t) - { - t.resetString(emuVideo().imageBuffers() == 1 ? "1" : "2"); - return true; - }, - .defaultItemOnSelect = [this](TextMenuItem &item) - { - app().videoImageBuffersOption() = item.id(); - emuVideo().setImageBuffers(item.id()); - } - }, - (MenuItem::Id)app().videoImageBuffersOption().val, - imageBuffersItem - }, presentModeItems { - {"Auto", &defaultFace(), to_underlying(Gfx::PresentMode::Auto)}, - {"Immediate (Less compositor latency but may drop frames)", &defaultFace(), to_underlying(Gfx::PresentMode::Immediate)}, - {"Queued (Better frame rate stability)", &defaultFace(), to_underlying(Gfx::PresentMode::FIFO)}, + {"Auto", attach, MenuItem::Config{.id = Gfx::PresentMode::Auto}}, + {"Immediate (Less compositor latency but may drop frames)", attach, MenuItem::Config{.id = Gfx::PresentMode::Immediate}}, + {"Queued (Better frame rate stability)", attach, MenuItem::Config{.id = Gfx::PresentMode::FIFO}}, }, presentMode { - "Present Mode", &defaultFace(), - MultiChoiceMenuItem::Delegates + "Present Mode", attach, + MenuId{Gfx::PresentMode(app().presentMode)}, + presentModeItems, + MultiChoiceMenuItem::Config { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -749,21 +732,21 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): }, .defaultItemOnSelect = [this](TextMenuItem &item) { - app().presentMode = Gfx::PresentMode(item.id()); + app().presentMode = Gfx::PresentMode(item.id.val); } }, - MenuItem::Id(Gfx::PresentMode(app().presentMode)), - presentModeItems }, renderPixelFormatItem { - {"Auto (Match display format)", &defaultFace(), PIXEL_NONE}, - {"RGBA8888", &defaultFace(), PIXEL_RGBA8888}, - {"RGB565", &defaultFace(), PIXEL_RGB565}, + {"Auto (Match display format)", attach, {.id = PIXEL_NONE}}, + {"RGBA8888", attach, {.id = PIXEL_RGBA8888}}, + {"RGB565", attach, {.id = PIXEL_RGB565}}, }, renderPixelFormat { - "Render Color Format", &defaultFace(), + "Render Color Format", attach, + MenuId{app().renderPixelFormat().id()}, + renderPixelFormatItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -774,71 +757,89 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): } return false; }, - .defaultItemOnSelect = [this](TextMenuItem &item) { app().setRenderPixelFormat(PixelFormatID(item.id())); } + .defaultItemOnSelect = [this](TextMenuItem &item) { app().setRenderPixelFormat(PixelFormatID(item.id.val)); } }, - (MenuItem::Id)app().renderPixelFormat().id(), - renderPixelFormatItem }, screenFrameRateItems { [&] { std::vector items; - auto setRateDel = [this](TextMenuItem &item) { app().overrideScreenFrameRate = std::bit_cast(item.id()); }; - items.emplace_back("Off", &defaultFace(), setRateDel, 0); + auto setRateDel = [this](TextMenuItem &item) { app().overrideScreenFrameRate = std::bit_cast(item.id); }; + items.emplace_back("Off", attach, setRateDel, MenuItem::Config{.id = 0}); for(auto rate : app().emuScreen().supportedFrameRates()) - items.emplace_back(std::format("{:g}Hz", rate), &defaultFace(), setRateDel, std::bit_cast(rate)); + items.emplace_back(std::format("{:g}Hz", rate), attach, setRateDel, MenuItem::Config{.id = std::bit_cast(rate)}); return items; }() }, screenFrameRate { - "Override Screen Frame Rate", &defaultFace(), - std::bit_cast(FrameRate(app().overrideScreenFrameRate)), + "Override Screen Frame Rate", attach, + std::bit_cast(FrameRate(app().overrideScreenFrameRate)), screenFrameRateItems }, + presentationTimeItems + { + {"Full (Apply to all frame rate targets)", attach, MenuItem::Config{.id = PresentationTimeMode::full}}, + {"Basic (Only apply to lower frame rate targets)", attach, MenuItem::Config{.id = PresentationTimeMode::basic}}, + {"Off", attach, MenuItem::Config{.id = PresentationTimeMode::off}}, + }, presentationTime { - "Precise Frame Pacing", &defaultFace(), - app().usePresentationTime, - [this](BoolMenuItem &item) { app().usePresentationTime = item.flipBoolValue(*this); } + "Precise Frame Pacing", attach, + MenuId{app().presentationTimeMode}, + presentationTimeItems, + MultiChoiceMenuItem::Config + { + .onSetDisplayString = [this](auto idx, Gfx::Text &t) + { + if(app().presentationTimeMode == PresentationTimeMode::off) + return false; + t.resetString(app().presentationTimeMode == PresentationTimeMode::full ? "Full" : "Basic"); + return true; + }, + .defaultItemOnSelect = [this](TextMenuItem &item) + { + app().presentationTimeMode = PresentationTimeMode(item.id.val); + } + }, }, blankFrameInsertion { - "Allow Blank Frame Insertion", &defaultFace(), + "Allow Blank Frame Insertion", attach, app().allowBlankFrameInsertion, [this](BoolMenuItem &item) { app().allowBlankFrameInsertion = item.flipBoolValue(*this); } }, brightnessItem { { - "Default", &defaultFace(), [this](View &v) + "Default", attach, [this](View &v) { app().setVideoBrightness(1.f, ImageChannel::All); - setAllColorLevelsSelected(MenuItem::Id{100}); + setAllColorLevelsSelected(MenuId{100}); v.dismiss(); } }, - {"Custom Value", &defaultFace(), setVideoBrightnessCustomDel(ImageChannel::All)}, + {"Custom Value", attach, setVideoBrightnessCustomDel(ImageChannel::All)}, }, redItem { - {"Default", &defaultFace(), [this](){ app().setVideoBrightness(1.f, ImageChannel::Red); }, 100}, - {"Custom Value", &defaultFace(), setVideoBrightnessCustomDel(ImageChannel::Red), MenuItem::DEFAULT_ID}, + {"Default", attach, [this](){ app().setVideoBrightness(1.f, ImageChannel::Red); }, {.id = 100}}, + {"Custom Value", attach, setVideoBrightnessCustomDel(ImageChannel::Red), {.id = defaultMenuId}}, }, greenItem { - {"Default", &defaultFace(), [this](){ app().setVideoBrightness(1.f, ImageChannel::Green); }, 100}, - {"Custom Value", &defaultFace(), setVideoBrightnessCustomDel(ImageChannel::Green), MenuItem::DEFAULT_ID}, + {"Default", attach, [this](){ app().setVideoBrightness(1.f, ImageChannel::Green); }, {.id = 100}}, + {"Custom Value", attach, setVideoBrightnessCustomDel(ImageChannel::Green), {.id = defaultMenuId}}, }, blueItem { - {"Default", &defaultFace(), [this](){ app().setVideoBrightness(1.f, ImageChannel::Blue); }, 100}, - {"Custom Value", &defaultFace(), setVideoBrightnessCustomDel(ImageChannel::Blue), MenuItem::DEFAULT_ID}, + {"Default", attach, [this](){ app().setVideoBrightness(1.f, ImageChannel::Blue); }, {.id = 100}}, + {"Custom Value", attach, setVideoBrightnessCustomDel(ImageChannel::Blue), {.id = defaultMenuId}}, }, brightness { - "Set All Levels", &defaultFace(), + "Set All Levels", attach, [this](const Input::Event &e) { pushAndShow(makeViewWithName("All Levels", brightnessItem), e); @@ -846,7 +847,9 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): }, red { - "Red", &defaultFace(), + "Red", attach, + MenuId{app().videoBrightnessAsInt(ImageChannel::Red)}, + redItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -854,12 +857,12 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): return true; } }, - MenuItem::Id{app().videoBrightnessAsInt(ImageChannel::Red)}, - redItem }, green { - "Green", &defaultFace(), + "Green", attach, + MenuId{app().videoBrightnessAsInt(ImageChannel::Green)}, + greenItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -867,12 +870,12 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): return true; } }, - MenuItem::Id{app().videoBrightnessAsInt(ImageChannel::Green)}, - greenItem }, blue { - "Blue", &defaultFace(), + "Blue", attach, + MenuId{app().videoBrightnessAsInt(ImageChannel::Blue)}, + blueItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -880,14 +883,12 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): return true; } }, - MenuItem::Id{app().videoBrightnessAsInt(ImageChannel::Blue)}, - blueItem - }, - visualsHeading{"Visuals", &defaultBoldFace()}, - screenShapeHeading{"Screen Shape", &defaultBoldFace()}, - colorLevelsHeading{"Color Levels", &defaultBoldFace()}, - advancedHeading{"Advanced", &defaultBoldFace()}, - systemSpecificHeading{"System-specific", &defaultBoldFace()} + }, + visualsHeading{"Visuals", attach}, + screenShapeHeading{"Screen Shape", attach}, + colorLevelsHeading{"Color Levels", attach}, + advancedHeading{"Advanced", attach}, + systemSpecificHeading{"System-specific", attach} { if(!customMenu) { @@ -897,7 +898,7 @@ VideoOptionView::VideoOptionView(ViewAttachParams attach, bool customMenu): void VideoOptionView::place() { - aspectRatio.setSelected(std::bit_cast(app().videoAspectRatio()), *this); + aspectRatio.setSelected(std::bit_cast(app().videoAspectRatio()), *this); TableView::place(); } @@ -938,8 +939,6 @@ void VideoOptionView::loadStockItems() if(EmuSystem::canRenderRGBA8888) item.emplace_back(&renderPixelFormat); item.emplace_back(&imgEffectPixelFormat); - if(!app().videoImageBuffersOption().isConst) - item.emplace_back(&imageBuffers); if(used(presentMode) && app().supportsPresentModes()) item.emplace_back(&presentMode); if(used(presentationTime) && renderer().supportsPresentationTime()) @@ -977,7 +976,7 @@ TextMenuItem::SelectDelegate VideoOptionView::setVideoBrightnessCustomDel(ImageC { app.setVideoBrightness(val / 100.f, ch); if(ch == ImageChannel::All) - setAllColorLevelsSelected(MenuItem::Id{val}); + setAllColorLevelsSelected(MenuId{val}); else [&]() -> MultiChoiceMenuItem& { @@ -989,7 +988,7 @@ TextMenuItem::SelectDelegate VideoOptionView::setVideoBrightnessCustomDel(ImageC case ImageChannel::Blue: return blue; } bug_unreachable("invalid ImageChannel"); - }().setSelected(MenuItem::Id{val}, *this); + }().setSelected(MenuId{val}, *this); dismissPrevious(); return true; }); @@ -997,7 +996,7 @@ TextMenuItem::SelectDelegate VideoOptionView::setVideoBrightnessCustomDel(ImageC }; } -void VideoOptionView::setAllColorLevelsSelected(MenuItem::Id val) +void VideoOptionView::setAllColorLevelsSelected(MenuId val) { red.setSelected(val, *this); green.setSelected(val, *this); diff --git a/EmuFramework/src/pathUtils.cc b/EmuFramework/src/pathUtils.cc index 88a17e355..6f4266b33 100644 --- a/EmuFramework/src/pathUtils.cc +++ b/EmuFramework/src/pathUtils.cc @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -26,13 +27,15 @@ namespace EmuEx using namespace IG; +constexpr SystemLogger log{"PathUtils"}; + std::vector subDirectoryStrings(ApplicationContext ctx, CStringView path) { std::vector subDirs{}; ctx.forEachInDirectoryUri(path, [&](auto &entry) { - //logMsg("entry:%s", entry.path().data()); + //log.debug("entry:{}", entry.path()); if(entry.type() != FS::file_type::directory) return true; subDirs.emplace_back(entry.path()); @@ -52,7 +55,7 @@ void flattenSubDirectories(ApplicationContext ctx, const std::vector(entry.size(), true); - if(entry.read(stream->map(), entry.size()) != entry.size()) + if(entry.read(stream->map(), entry.size()) != ssize_t(entry.size())) { throw MDFN_Error(0, "Error reading archive file:\n%s", filename.c_str()); } diff --git a/EmuFramework/src/shared/mednafen-emuex/MDFNUtils.hh b/EmuFramework/src/shared/mednafen-emuex/MDFNUtils.hh index f0436ea68..bcf49b4e5 100644 --- a/EmuFramework/src/shared/mednafen-emuex/MDFNUtils.hh +++ b/EmuFramework/src/shared/mednafen-emuex/MDFNUtils.hh @@ -102,7 +102,7 @@ inline std::string savePathMDFN(int id1, const char *cd1) inline BoolMenuItem saveFilenameTypeMenuItem(auto &view, auto &system) { - return {"Save Filename Type", &view.defaultFace(), + return {"Save Filename Type", view.attachParams(), system.noMD5InFilenames, "Default", "No MD5", [&](BoolMenuItem &item) { system.noMD5InFilenames = item.flipBoolValue(view); } diff --git a/EmuFramework/src/vcontrols/VController.cc b/EmuFramework/src/vcontrols/VController.cc index 55bfccef3..bb0a773d1 100644 --- a/EmuFramework/src/vcontrols/VController.cc +++ b/EmuFramework/src/vcontrols/VController.cc @@ -18,7 +18,7 @@ #include #include "../EmuOptions.hh" #include "../WindowData.hh" -#include +#include #include #include #include @@ -60,11 +60,11 @@ int VController::yMMSizeToPixel(const IG::Window &win, float mm) const return win.heightMMInPixels(mm); } -static void updateTexture(const EmuApp &app, VControllerElement &e, Gfx::RendererTask &task) +static void updateTexture(const EmuApp &app, VControllerElement &e, Gfx::RendererTask &task, const Gfx::IndexBuffer &fanQuadIdxs) { visit(overloaded { - [&](VControllerDPad &dpad){ dpad.setImage(task, app.asset(app.vControllerAssetDesc(0))); }, + [&](VControllerDPad &dpad){ dpad.setImage(task, app.asset(app.vControllerAssetDesc(0)), fanQuadIdxs); }, [&](VControllerButtonGroup &grp) { for(auto &btn : grp.buttons) @@ -112,8 +112,8 @@ static void updateTexture(const EmuApp &app, VControllerElement &e, Gfx::Rendere void VController::updateTextures() { - for(auto &e : gpElements) { updateTexture(app(), e, renderer().mainTask); } - for(auto &e : uiElements) { updateTexture(app(), e, renderer().mainTask); } + for(auto &e : gpElements) { updateTexture(app(), e, renderer().mainTask, fanQuadIdxs); } + for(auto &e : uiElements) { updateTexture(app(), e, renderer().mainTask, fanQuadIdxs); } } static void setSize(VControllerElement &elem, int sizePx, Gfx::Renderer &r) @@ -365,7 +365,6 @@ void VController::draw(Gfx::RendererCommands &__restrict__ cmds, bool showHidden cmds.set(Gfx::BlendMode::PREMULT_ALPHA); if(isInKeyboardMode()) { - cmds.setIndexArray(*quadIdxsPtr); cmds.setColor(Gfx::Color{alphaF}); kb.draw(cmds); } @@ -379,12 +378,10 @@ void VController::draw(Gfx::RendererCommands &__restrict__ cmds, bool showHidden auto activeElements = gpElements | std::views::filter(elementIsEnabled); if(!activeElements.empty()) { - cmds.setIndexArray(*quadIdxsPtr); for(const auto &e : activeElements) { e.drawBounds(cmds, showHidden); } cmds.basicEffect().enableTexture(cmds, gamepadTex); for(const auto &e : activeElements) { - setIndexArray(cmds, e); e.drawButtons(cmds, showHidden); } } @@ -392,7 +389,6 @@ void VController::draw(Gfx::RendererCommands &__restrict__ cmds, bool showHidden if(uiElements.size()) { cmds.basicEffect().enableTexture(cmds, uiTex); - cmds.setIndexArray(*quadIdxsPtr); // all UI elements use quad indices for(auto &e : uiElements) { e.drawButtons(cmds, showHidden); @@ -403,17 +399,11 @@ void VController::draw(Gfx::RendererCommands &__restrict__ cmds, bool showHidden void VController::draw(Gfx::RendererCommands &__restrict__ cmds, const VControllerElement &elem, bool showHidden) const { cmds.set(Gfx::BlendMode::PREMULT_ALPHA); - setIndexArray(cmds, elem); elem.drawBounds(cmds, showHidden); cmds.basicEffect().enableTexture(cmds, elem.uiButtonGroup() ? uiTex : gamepadTex); elem.drawButtons(cmds, showHidden); } -void VController::setIndexArray(Gfx::RendererCommands &__restrict__ cmds, const VControllerElement &elem) const -{ - cmds.setIndexArray(elem.dPad() ? fanQuadIdxs : *quadIdxsPtr); -} - bool VController::isInKeyboardMode() const { return EmuSystem::inputHasKeyboard && kbMode; @@ -424,7 +414,7 @@ void VController::setInputPlayer(int8_t player) inputPlayer_ = player; for(auto &e : gpElements) { - e.transposeKeysForPlayer(app(), player); + e.transposeKeysForPlayer(app().inputManager, player); } } @@ -594,7 +584,7 @@ bool VController::updateAutoOnScreenControlVisible() return false; } -static bool readVControllerElement(EmuApp &app, MapIO &io, std::vector &elems, bool readingUIElems) +static bool readVControllerElement(InputManager &mgr, MapIO &io, std::vector &elems, bool readingUIElems) { auto elemType = io.get(); if(elemType == 0) @@ -606,7 +596,7 @@ static bool readVControllerElement(EmuApp &app, MapIO &io, std::vector()); auto keys = io.get(); io.readSized(config.keys, keys); - config.validate(app); + config.validate(mgr); elems.emplace_back(std::in_place_type, std::move(config)); } else @@ -621,7 +611,7 @@ static bool readVControllerElement(EmuApp &app, MapIO &io, std::vector(); io.readSized(config.keys, keys); - config.validate(app); + config.validate(mgr); elems.emplace_back(std::in_place_type, std::move(config)); } } @@ -632,7 +622,7 @@ static bool readVControllerElement(EmuApp &app, MapIO &io, std::vector, std::move(config)); } else @@ -684,7 +674,7 @@ bool VController::readConfig(EmuApp &app, MapIO &io, unsigned key, size_t size) log.info("read emu device button data ({} bytes) with {} element(s)", size, elements); for(auto i : iotaCount(elements)) { - if(!readVControllerElement(app, io, gpElements, false)) + if(!readVControllerElement(app.inputManager, io, gpElements, false)) return false; } return true; @@ -697,7 +687,7 @@ bool VController::readConfig(EmuApp &app, MapIO &io, unsigned key, size_t size) log.info("read UI button data ({} bytes) with {} element(s)", size, elements); for(auto i : iotaCount(elements)) { - if(!readVControllerElement(app, io, uiElements, true)) + if(!readVControllerElement(app.inputManager, io, uiElements, true)) return false; } return true; @@ -816,12 +806,11 @@ void VController::writeConfig(FileIO &io) const writeUIButtonsConfig(io); } -void VController::configure(IG::Window &win, Gfx::Renderer &renderer, const Gfx::GlyphTextureSet &face, const Gfx::IndexBuffer &quadIdxs) +void VController::configure(IG::Window &win, Gfx::Renderer &renderer, const Gfx::GlyphTextureSet &face) { setWindow(win); setRenderer(renderer); setFace(face); - quadIdxsPtr = &quadIdxs; // common index buffer from view manager class fanQuadIdxs = {renderer.mainTask, {.size = 24}}; // for rendering DPads with FanQuads { auto indices = fanQuadIdxs.map(); @@ -1049,7 +1038,7 @@ void VController::update(VControllerElement &elem) const { if(!hasWindow()) return; - updateTexture(app(), elem, renderer_->mainTask); + updateTexture(app(), elem, renderer_->mainTask, fanQuadIdxs); setSize(elem, elem.uiButtonGroup() ? uiButtonPixelSize() : emulatedDeviceButtonPixelSize(), *renderer_); elem.updateMeasurements(window()); } diff --git a/EmuFramework/src/vcontrols/VControllerButton.cc b/EmuFramework/src/vcontrols/VControllerButton.cc index 57df3b034..92aef50ba 100644 --- a/EmuFramework/src/vcontrols/VControllerButton.cc +++ b/EmuFramework/src/vcontrols/VControllerButton.cc @@ -13,11 +13,9 @@ You should have received a copy of the GNU General Public License along with EmuFramework. If not, see */ -#define LOGTAG "VControllerButton" #include -#include +#include #include -#include namespace EmuEx { @@ -42,9 +40,9 @@ void VControllerButton::setImage(Gfx::TextureSpan t, int aR) aspectRatio = aR; } -std::string VControllerButton::name(const EmuApp &app) const +std::string VControllerButton::name(const InputManager &mgr) const { - return std::string{app.inputManager.toString(key)}; + return std::string{mgr.toString(key)}; } void VControllerButton::setAlpha(float alpha) diff --git a/EmuFramework/src/vcontrols/VControllerButtonGroup.cc b/EmuFramework/src/vcontrols/VControllerButtonGroup.cc index fb1306981..f4adcd4d2 100644 --- a/EmuFramework/src/vcontrols/VControllerButtonGroup.cc +++ b/EmuFramework/src/vcontrols/VControllerButtonGroup.cc @@ -13,14 +13,14 @@ You should have received a copy of the GNU General Public License along with EmuFramework. If not, see */ -#define LOGTAG "VControllerButton" #include -#include +#include #include +#include #include #include #include -#include +#include namespace EmuEx { @@ -163,11 +163,11 @@ void VControllerButtonGroup::updateMeasurements(const Window &win) setButtonSize(btnSize); } -void VControllerButtonGroup::transposeKeysForPlayer(const EmuApp &app, int player) +void VControllerButtonGroup::transposeKeysForPlayer(const InputManager &mgr, int player) { for(auto &b : buttons) { - b.key = app.inputManager.transpose(b.key, player); + b.key = mgr.transpose(b.key, player); } } @@ -197,10 +197,10 @@ void VControllerButtonGroup::drawBounds(Gfx::RendererCommands &__restrict__ cmds if(!layout.showBoundingArea || !enabledBtns) return; cmds.basicEffect().disableTexture(cmds); - cmds.drawQuads(boundQuads, 0, enabledBtns); + cmds.drawQuads(boundQuads, 0, enabledBtns); } -static std::string namesString(auto &buttons, const EmuApp &app) +static std::string namesString(auto &buttons, const InputManager &app) { if(buttons.empty()) return "Empty Group"; @@ -213,7 +213,7 @@ static std::string namesString(auto &buttons, const EmuApp &app) return s; } -std::string VControllerButtonGroup::name(const EmuApp &app) const +std::string VControllerButtonGroup::name(const InputManager &app) const { return namesString(buttons, app); } @@ -223,9 +223,9 @@ static bool isValidSpacing(int val) { return val >= 0 && val <= 8; } static bool isValidPadding(int val) { return val >= 0 && val <= 30; } static bool isValidStaggerType(int val) { return val >= 0 && val <= 5; } -void VControllerButtonGroup::Config::validate(const EmuApp &app) +void VControllerButtonGroup::Config::validate(const InputManager &mgr) { - for(auto &k : keys) { k = app.inputManager.validateSystemKey(k, false); } + for(auto &k : keys) { k = mgr.validateSystemKey(k, false); } if(!isValidRowItemCount(layout.rowItems)) layout.rowItems = 2; if(!isValidSpacing(layout.spacingMM)) @@ -296,14 +296,14 @@ int VControllerUIButtonGroup::rows() const return divRoundUp(buttonsToLayout(buttons), layout.rowItems); } -std::string VControllerUIButtonGroup::name(const EmuApp &app) const +std::string VControllerUIButtonGroup::name(const InputManager &mgr) const { - return namesString(buttons, app); + return namesString(buttons, mgr); } -void VControllerUIButtonGroup::Config::validate(const EmuApp &app) +void VControllerUIButtonGroup::Config::validate(const InputManager &mgr) { - for(auto &k : keys) { k = app.inputManager.validateSystemKey(k, true); } + for(auto &k : keys) { k = mgr.validateSystemKey(k, true); } if(!isValidRowItemCount(layout.rowItems)) layout.rowItems = 2; } @@ -314,7 +314,7 @@ void BaseVControllerButtonGroup::drawButtons(Gfx::RendererCommands &__res auto &g = static_cast(*this); if(!g.enabledBtns) return; - cmds.drawQuads(g.quads, 0, g.enabledBtns); + cmds.drawQuads(g.quads, 0, g.enabledBtns); } template diff --git a/EmuFramework/src/vcontrols/VControllerDPad.cc b/EmuFramework/src/vcontrols/VControllerDPad.cc index e1dda18e5..ff194490c 100644 --- a/EmuFramework/src/vcontrols/VControllerDPad.cc +++ b/EmuFramework/src/vcontrols/VControllerDPad.cc @@ -15,8 +15,7 @@ #include #include -#include -#include +#include #include #include #include @@ -29,9 +28,9 @@ namespace EmuEx constexpr SystemLogger log{"VControllerGamepad"}; -void VControllerDPad::setImage(Gfx::RendererTask &task, Gfx::TextureSpan img) +void VControllerDPad::setImage(Gfx::RendererTask &task, Gfx::TextureSpan img, const Gfx::IndexBuffer &idxs) { - spriteQuads = {task, {.size = 2}}; + spriteQuads = {task, {.size = 2}, idxs}; tex = img; } @@ -127,11 +126,11 @@ void VControllerDPad::updateMeasurements(const Window &win) deadzonePixels = win.widthMMInPixels(config.deadzoneMM100x / 100.f); } -void VControllerDPad::transposeKeysForPlayer(const EmuApp &app, int player) +void VControllerDPad::transposeKeysForPlayer(const InputManager &mgr, int player) { for(auto &k : config.keys) { - k = app.inputManager.transpose(k, player); + k = mgr.transpose(k, player); } } @@ -178,9 +177,9 @@ std::array VControllerDPad::getInput(WPt c) const return pad; } -void VControllerDPad::Config::validate(const EmuApp &app) +void VControllerDPad::Config::validate(const InputManager &mgr) { - for(auto &k : keys) { k = app.inputManager.validateSystemKey(k, false); } + for(auto &k : keys) { k = mgr.validateSystemKey(k, false); } if(!isValidDiagonalSensitivity(diagonalSensitivity)) diagonalSensitivity = defaultDPadDiagonalSensitivity; if(!isValidDeadzone(deadzoneMM100x)) diff --git a/EmuFramework/src/vcontrols/VControllerKeyboard.cc b/EmuFramework/src/vcontrols/VControllerKeyboard.cc index d18643432..31615a7a4 100644 --- a/EmuFramework/src/vcontrols/VControllerKeyboard.cc +++ b/EmuFramework/src/vcontrols/VControllerKeyboard.cc @@ -13,17 +13,19 @@ You should have received a copy of the GNU General Public License along with EmuFramework. If not, see */ -#define LOGTAG "VControllerKeyboard" #include #include -#include +#include #include +#include #include #include namespace EmuEx { +constexpr SystemLogger log{"VControllerKeyboard"}; + void VControllerKeyboard::updateImg() { texture.bounds = mode_ == VControllerKbMode::LAYOUT_2 ? FRect{{0., .5}, {texXEnd, 1.}} : FRect{{}, {texXEnd, .5}}; @@ -54,7 +56,7 @@ void VControllerKeyboard::place(int btnSize, int yOffset, WRect viewBounds) bound = bounds; keyXSize = std::max(bound.xSize() / VKEY_COLS, 1); keyYSize = std::max(bound.ySize() / KEY_ROWS, 1); - logMsg("key size %dx%d", keyXSize, keyYSize); + log.info("key size {}x{}", keyXSize, keyYSize); updateImg(); } @@ -99,7 +101,7 @@ int VControllerKeyboard::getInput(WPt c) const int row = std::min(relY/keyYSize, 3); int col = std::min(relX/keyXSize, 19); int idx = col + (row * VKEY_COLS); - //logMsg("pointer %d,%d key @ %d,%d, idx %d", relX, relY, row, col, idx); + //log.debug("pointer {},{} key @ {},{}, idx {}", relX, relY, row, col, idx); return idx; } @@ -129,7 +131,7 @@ bool VControllerKeyboard::keyInput(VController &v, Gfx::Renderer &r, const Input { if(!e.pushed() || e.repeated()) return false; - logMsg("dismiss kb"); + log.info("dismiss kb"); unselectKey(); v.toggleKeyboard(); } @@ -137,7 +139,7 @@ bool VControllerKeyboard::keyInput(VController &v, Gfx::Renderer &r, const Input { if(!e.pushed() || e.repeated()) return false; - logMsg("switch kb mode"); + log.info("switch kb mode"); cycleMode(v.system(), r); v.resetInput(); } @@ -182,7 +184,7 @@ WRect VControllerKeyboard::selectKey(int x, int y) { if(x >= VKEY_COLS || y >= KEY_ROWS) { - logErr("selected key:%dx%d out of range", x, y); + log.error("selected key:{}x{} out of range", x, y); return {{-1, -1}, {-1, -1}}; } return extendKeySelection({{x, y}, {x, y}}); @@ -208,7 +210,7 @@ void VControllerKeyboard::selectKeyRel(int x, int y) selected = extendKeySelection(selected); if(!currentKey(selected.x, selected.y)) { - logMsg("skipping blank key index"); + log.info("skipping blank key index"); selectKeyRel(x, y); } } @@ -235,7 +237,7 @@ IG::WindowRect VControllerKeyboard::extendKeySelection(IG::WindowRect selected) else break; } - logMsg("extended selection to:%d:%d", selected.x, selected.x2); + log.info("extended selection to:{}:{}", selected.x, selected.x2); return selected; } @@ -329,10 +331,10 @@ void VControllerKeyboard::applyMap(KbMap map) /*iterateTimes(table.size(), i) { - logMsg("row:%d", i); + log.debug("row:{}", i); iterateTimes(table[0].size(), j) { - logMsg("col:%d = %d", j, table[i][j]); + log.info("col:{} = {}", j, table[i][j]); } }*/ } diff --git a/GBA.emu/src/main/Cheats.cc b/GBA.emu/src/main/Cheats.cc index bcd93e487..3b3b3273d 100644 --- a/GBA.emu/src/main/Cheats.cc +++ b/GBA.emu/src/main/Cheats.cc @@ -63,7 +63,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, int cheatIdx, Refres { "Code", cheatsList[cheatIdx].codestring, - &defaultFace(), + attach, [this](DualTextMenuItem &, View &, Input::Event) { app().postMessage("To change this cheat, please delete and re-add it"); @@ -90,7 +90,7 @@ void EmuEditCheatListView::loadCheatItems() cheat.reserve(cheatsList.size()); for(auto &c : cheatsList) { - cheat.emplace_back(c.desc, &defaultFace(), + cheat.emplace_back(c.desc, attachParams(), [this, idx = std::distance(cheatsList.data(), &c)](Input::Event e) { pushAndShow(makeView(idx, [this](){ onCheatListChanged(); }), e); @@ -178,7 +178,7 @@ EmuEditCheatListView::EmuEditCheatListView(ViewAttachParams attach): }, addGS12CBCode { - "Add Game Shark v1-2/Code Breaker Code", &defaultFace(), + "Add Game Shark v1-2/Code Breaker Code", attach, [this](TextMenuItem &item, View &, Input::Event e) { addNewCheat(false); @@ -186,7 +186,7 @@ EmuEditCheatListView::EmuEditCheatListView(ViewAttachParams attach): }, addGS3Code { - "Add Game Shark v3 Code", &defaultFace(), + "Add Game Shark v3 Code", attach, [this](TextMenuItem &item, View &, Input::Event e) { addNewCheat(true); @@ -202,7 +202,7 @@ void EmuCheatsView::loadCheatItems() cheat.reserve(cheatsList.size()); for(auto &c : cheatsList) { - cheat.emplace_back(c.desc, &defaultFace(), c.enabled, + cheat.emplace_back(c.desc, attachParams(), c.enabled, [this, idx = std::distance(cheatsList.data(), &c)](BoolMenuItem &item, Input::Event e) { bool on = item.flipBoolValue(*this); diff --git a/GBA.emu/src/main/EmuMenuViews.cc b/GBA.emu/src/main/EmuMenuViews.cc index 32e59b7ff..07df27c40 100644 --- a/GBA.emu/src/main/EmuMenuViews.cc +++ b/GBA.emu/src/main/EmuMenuViews.cc @@ -37,14 +37,16 @@ class ConsoleOptionView : public TableView, public MainAppHelper("Really change save type? Existing data in .sav file may be lost so please make a backup before proceeding.", YesNoAlertView::Delegates { - .onYes = [this, optVal = item.id()](const Input::Event &e) + .onYes = [this, optVal = item.id](const Input::Event &e) { setSaveTypeOption(app(), optVal, attachParams(), e); } @@ -122,7 +122,7 @@ class ConsoleOptionView : public TableView, public MainAppHelper::system; using MainAppHelper::app; - TextHeadingMenuItem mixer{"Mixer", &defaultBoldFace()}; + TextHeadingMenuItem mixer{"Mixer", attachParams()}; using VolumeChoiceItemArr = std::array; @@ -219,19 +219,19 @@ class CustomAudioOptionView : public AudioOptionView, public MainAppHelper(attachParams(), e, "Input 0 to 100", "", @@ -239,12 +239,12 @@ class CustomAudioOptionView : public AudioOptionView, public MainAppHelper(attachParams(), e, "Input 0 to 100", "", [this](EmuApp &app, auto val) { soundSetFiltering(gGba, val / 100.f); - filteringLevel.setSelected((MenuItem::Id)val, *this); + filteringLevel.setSelected(MenuId{val}, *this); dismissPrevious(); return true; }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} } }; MultiChoiceMenuItem filteringLevel { - "Filtering Level", &defaultFace(), + "Filtering Level", attachParams(), + MenuId{soundFilteringAsInt(gGba)}, + filteringLevelItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -337,13 +339,11 @@ class CustomAudioOptionView : public AudioOptionView, public MainAppHelper(attachParams(), e, "Input 0 to 50000", "", [this](EmuApp &app, auto val) { system().lightSensorScaleLux = val; - lightSensorScale.setSelected((MenuItem::Id)val, *this); + lightSensorScale.setSelected(MenuId{val}, *this); dismissPrevious(); return true; }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} } }; MultiChoiceMenuItem lightSensorScale { - "Light Sensor Scale", &defaultFace(), + "Light Sensor Scale", attachParams(), + MenuId{system().lightSensorScaleLux}, + lightSensorScaleItem, { .onSetDisplayString = [this](auto idx, Gfx::Text &t) { @@ -407,13 +409,11 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper("Cheats", system().userPath(system().cheatsDir), @@ -441,14 +441,14 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { logMsg("set cheats path:%s", path.data()); system().cheatsDir = path; - cheatsPath.compile(cheatsMenuName(appContext(), path), renderer()); + cheatsPath.compile(cheatsMenuName(appContext(), path)); }), e); } }; TextMenuItem patchesPath { - patchesMenuName(appContext(), system().patchesDir), &defaultFace(), + patchesMenuName(appContext(), system().patchesDir), attachParams(), [this](const Input::Event &e) { pushAndShow(makeViewWithName("Patches", system().userPath(system().patchesDir), @@ -456,7 +456,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { logMsg("set patches path:%s", path.data()); system().patchesDir = path; - patchesPath.compile(patchesMenuName(appContext(), path), renderer()); + patchesPath.compile(patchesMenuName(appContext(), path)); }), e); } }; diff --git a/GBA.emu/src/main/VbamApi.cc b/GBA.emu/src/main/VbamApi.cc index bd63ece32..4f61f7214 100644 --- a/GBA.emu/src/main/VbamApi.cc +++ b/GBA.emu/src/main/VbamApi.cc @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include "MainSystem.hh" struct GameSettings diff --git a/GBC.emu/src/main/Cheats.cc b/GBC.emu/src/main/Cheats.cc index dc3a39608..7389876f4 100644 --- a/GBC.emu/src/main/Cheats.cc +++ b/GBC.emu/src/main/Cheats.cc @@ -174,7 +174,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, GbcCheat &cheat_, Re { "Code", cheat_.code, - &defaultFace(), + attach, [this](DualTextMenuItem &item, View &, Input::Event e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, @@ -191,7 +191,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, GbcCheat &cheat_, Re writeCheatFile(system()); static_cast(app.system()).applyCheats(); ggCode.set2ndName(str); - ggCode.compile(renderer()); + ggCode.compile(); postDraw(); return true; }); @@ -230,7 +230,7 @@ EmuEditCheatListView::EmuEditCheatListView(ViewAttachParams attach): }, addGGGS { - "Add Game Genie / GameShark Code", &defaultFace(), + "Add Game Genie / GameShark Code", attach, [this](TextMenuItem &item, View &, Input::Event e) { app().pushAndShowNewCollectTextInputView(attachParams(), e, @@ -296,7 +296,7 @@ void EmuEditCheatListView::loadCheatItems() for(auto c : iotaCount(cheats)) { auto &thisCheat = *it; - cheat.emplace_back(thisCheat.name, &defaultFace(), + cheat.emplace_back(thisCheat.name, attachParams(), [this, c](TextMenuItem &, View &, Input::Event e) { pushAndShow(makeView(cheatList[c], [this](){ onCheatListChanged(); }), e); @@ -319,7 +319,7 @@ void EmuCheatsView::loadCheatItems() for(auto cIdx : iotaCount(cheats)) { auto &thisCheat = *it; - cheat.emplace_back(thisCheat.name, &defaultFace(), thisCheat.isOn(), + cheat.emplace_back(thisCheat.name, attachParams(), thisCheat.isOn(), [this, cIdx](BoolMenuItem &item, View &, Input::Event e) { item.flipBoolValue(*this); diff --git a/GBC.emu/src/main/EmuMenuViews.cc b/GBC.emu/src/main/EmuMenuViews.cc index 73bfed244..9e2a95bc4 100644 --- a/GBC.emu/src/main/EmuMenuViews.cc +++ b/GBC.emu/src/main/EmuMenuViews.cc @@ -41,7 +41,7 @@ class CustomAudioOptionView : public AudioOptionView, public MainAppHelper("Cheats", system().userPath(system().cheatsDir), @@ -207,7 +207,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { logMsg("set cheats path:%s", path.data()); system().cheatsDir = path; - cheatsPath.compile(cheatsMenuName(appContext(), path), renderer()); + cheatsPath.compile(cheatsMenuName(appContext(), path)); }), e); } }; diff --git a/Lynx.emu/src/main/EmuMenuViews.cc b/Lynx.emu/src/main/EmuMenuViews.cc index 082a4b9d8..110606b67 100644 --- a/Lynx.emu/src/main/EmuMenuViews.cc +++ b/Lynx.emu/src/main/EmuMenuViews.cc @@ -41,7 +41,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper TextMenuItem biosPath { - biosMenuEntryStr(system().biosPath), &defaultFace(), + biosMenuEntryStr(system().biosPath), attachParams(), [this](Input::Event e) { pushAndShow(makeViewWithName>("BIOS", @@ -50,7 +50,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { system().biosPath = path; logMsg("set BIOS:%s", system().biosPath.data()); - biosPath.compile(biosMenuEntryStr(path), renderer()); + biosPath.compile(biosMenuEntryStr(path)); return true; }, hasBiosExtension), e); } @@ -72,21 +72,21 @@ class ConsoleOptionView : public TableView, public MainAppHelper(), e); } }; @@ -129,7 +129,7 @@ class CustomAudioOptionView : public AudioOptionView, public MainAppHelper(attachParams(), e, emuSystemIs16Bit() ? INPUT_CODE_16BIT_STR : INPUT_CODE_8BIT_STR, cheat->code, @@ -545,7 +545,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, MdCheat &cheat_, Ref updateCheats(); writeCheatFile(system()); code.set2ndName(str); - code.compile(renderer()); + code.compile(); postDraw(); return true; }); @@ -574,7 +574,7 @@ void EmuEditCheatListView::loadCheatItems() for(auto c : iotaCount(cheats)) { auto &thisCheat = *it; - cheat.emplace_back(thisCheat.name, &defaultFace(), + cheat.emplace_back(thisCheat.name, attachParams(), [this, c](TextMenuItem &, View &, Input::Event e) { pushAndShow(makeView(cheatList[c], [this](){ onCheatListChanged(); }), e); @@ -602,7 +602,7 @@ EmuEditCheatListView::EmuEditCheatListView(ViewAttachParams attach): }, addCode { - "Add Game Genie / Action Replay Code", &defaultFace(), + "Add Game Genie / Action Replay Code", attach, [this](TextMenuItem &item, View &, Input::Event e) { app().pushAndShowNewCollectTextInputView(attachParams(), e, emuSystemIs16Bit() ? INPUT_CODE_16BIT_STR : INPUT_CODE_8BIT_STR, "", @@ -677,7 +677,7 @@ void EmuCheatsView::loadCheatItems() for(auto cIdx : iotaCount(cheats)) { auto &thisCheat = *it; - cheat.emplace_back(thisCheat.name, &defaultFace(), thisCheat.isOn(), + cheat.emplace_back(thisCheat.name, attachParams(), thisCheat.isOn(), [this, cIdx](BoolMenuItem &item, View &, Input::Event e) { item.flipBoolValue(*this); diff --git a/MD.emu/src/main/EmuMenuViews.cc b/MD.emu/src/main/EmuMenuViews.cc index 09f11d352..05d4fc95c 100644 --- a/MD.emu/src/main/EmuMenuViews.cc +++ b/MD.emu/src/main/EmuMenuViews.cc @@ -38,7 +38,7 @@ class ConsoleOptionView : public TableView, public MainAppHelper("Cheats", system().userPath(system().cheatsDir), @@ -286,7 +286,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { logMsg("set cheats path:%s", path.data()); system().cheatsDir = path; - cheatsPath.compile(cheatsMenuName(appContext(), path), renderer()); + cheatsPath.compile(cheatsMenuName(appContext(), path)); }), e); } }; @@ -321,9 +321,9 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper TextMenuItem cdBiosPath[3] { - {biosMenuEntryStr(REGION_USA, pathFromRegion(REGION_USA)), &defaultFace(), setCDBiosPathDel(REGION_USA)}, - {biosMenuEntryStr(REGION_JAPAN_NTSC, pathFromRegion(REGION_JAPAN_NTSC)), &defaultFace(), setCDBiosPathDel(REGION_JAPAN_NTSC)}, - {biosMenuEntryStr(REGION_EUROPE, pathFromRegion(REGION_EUROPE)), &defaultFace(), setCDBiosPathDel(REGION_EUROPE)} + {biosMenuEntryStr(REGION_USA, pathFromRegion(REGION_USA)), attachParams(), setCDBiosPathDel(REGION_USA)}, + {biosMenuEntryStr(REGION_JAPAN_NTSC, pathFromRegion(REGION_JAPAN_NTSC)), attachParams(), setCDBiosPathDel(REGION_JAPAN_NTSC)}, + {biosMenuEntryStr(REGION_EUROPE, pathFromRegion(REGION_EUROPE)), attachParams(), setCDBiosPathDel(REGION_EUROPE)} }; std::string biosMenuEntryStr(uint8_t region, IG::CStringView path) const @@ -343,7 +343,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper auto idx = regionCodeToIdx(region); pathFromRegion(region) = path; logMsg("set bios:%d to path:%s", idx, pathFromRegion(region).data()); - cdBiosPath[idx].compile(biosMenuEntryStr(region, path), renderer()); + cdBiosPath[idx].compile(biosMenuEntryStr(region, path)); return true; }, hasMDExtension), e); }; diff --git a/MD.emu/src/main/input.cc b/MD.emu/src/main/input.cc index 9a722af1b..ff7e69214 100644 --- a/MD.emu/src/main/input.cc +++ b/MD.emu/src/main/input.cc @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include "MainSystem.hh" #include "MainApp.hh" #include "input.h" diff --git a/MSX.emu/src/main/EmuMenuViews.cc b/MSX.emu/src/main/EmuMenuViews.cc index d7f254af3..6868fea86 100644 --- a/MSX.emu/src/main/EmuMenuViews.cc +++ b/MSX.emu/src/main/EmuMenuViews.cc @@ -119,7 +119,9 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper("BIOS", @@ -206,7 +206,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper return false; } system().firmwarePath = path; - machineFilePath.compile(machinePathMenuEntryStr(path), renderer()); + machineFilePath.compile(machinePathMenuEntryStr(path)); if(type == FS::file_type::none) { app().postMessage(4, false, std::format("Using fallback path:\n{}", machineBasePath(system()))); @@ -267,7 +267,7 @@ class MsxIOControlView : public TableView, public MainAppHelper item; @@ -521,7 +521,7 @@ class CustomSystemActionsView : public SystemActionsView, public MainAppHelper("Change machine type and reset emulation?", @@ -651,20 +651,20 @@ class SoundMixerView : public TableView, public MainAppHelper std::array heading { - TextHeadingMenuItem{"PSG", &defaultBoldFace()}, - TextHeadingMenuItem{"SCC", &defaultBoldFace()}, - TextHeadingMenuItem{"MSX-MUSIC", &defaultBoldFace()}, - TextHeadingMenuItem{"MSX-AUDIO", &defaultBoldFace()}, - TextHeadingMenuItem{"MoonSound", &defaultBoldFace()}, - TextHeadingMenuItem{"Yamaha SFG", &defaultBoldFace()}, - TextHeadingMenuItem{"PCM", &defaultBoldFace()} + TextHeadingMenuItem{"PSG", attachParams(),}, + TextHeadingMenuItem{"SCC", attachParams(),}, + TextHeadingMenuItem{"MSX-MUSIC", attachParams(),}, + TextHeadingMenuItem{"MSX-AUDIO", attachParams(),}, + TextHeadingMenuItem{"MoonSound", attachParams(),}, + TextHeadingMenuItem{"Yamaha SFG", attachParams(),}, + TextHeadingMenuItem{"PCM", attachParams(),} }; BoolMenuItem makeEnableChannel(MixerAudioType type) { return { - "Output", &defaultFace(), + "Output", attachParams(), (bool)mixerEnableOption(type), [this, type](BoolMenuItem &item, View &, Input::Event) { @@ -690,12 +690,12 @@ class SoundMixerView : public TableView, public MainAppHelper { return { - TextMenuItem{"Default Value", &defaultFace(), + TextMenuItem{"Default Value", attachParams(), [this, type]() { setMixerVolumeOption(type, -1); }}, - TextMenuItem{"Custom Value", &defaultFace(), + TextMenuItem{"Custom Value", attachParams(), [this, type = (uint8_t)type, idx](Input::Event e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, "Input 0 to 100", "", @@ -735,7 +735,9 @@ class SoundMixerView : public TableView, public MainAppHelper { return { - "Volume", &defaultFace(), + "Volume", attachParams(), + 1, + volumeLevelItem[idx], { .onSetDisplayString = [this, type](auto idx, Gfx::Text &t) { @@ -743,8 +745,6 @@ class SoundMixerView : public TableView, public MainAppHelper return true; } }, - 1, - volumeLevelItem[idx] }; } @@ -763,12 +763,12 @@ class SoundMixerView : public TableView, public MainAppHelper { return { - TextMenuItem{"Default Value", &defaultFace(), + TextMenuItem{"Default Value", attachParams(), [this, type]() { setMixerPanOption(type, -1); }}, - TextMenuItem{"Custom Value", &defaultFace(), + TextMenuItem{"Custom Value", attachParams(), [this, type = (uint8_t)type, idx](Input::Event e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, "Input 0 to 100", "", @@ -808,7 +808,9 @@ class SoundMixerView : public TableView, public MainAppHelper { return { - "Pan", &defaultFace(), + "Pan", attachParams(), + 1, + panLevelItem[idx], { .onSetDisplayString = [this, type](auto idx, Gfx::Text &t) { @@ -816,8 +818,6 @@ class SoundMixerView : public TableView, public MainAppHelper return true; } }, - 1, - panLevelItem[idx] }; } @@ -877,7 +877,7 @@ class CustomAudioOptionView : public AudioOptionView protected: TextMenuItem mixer { - "Sound Mixer", &defaultFace(), + "Sound Mixer", attachParams(), [this](Input::Event e) { pushAndShow(makeView(), e); diff --git a/NEO.emu/src/main/EmuMenuViews.cc b/NEO.emu/src/main/EmuMenuViews.cc index bd9716532..113dd2af1 100644 --- a/NEO.emu/src/main/EmuMenuViews.cc +++ b/NEO.emu/src/main/EmuMenuViews.cc @@ -46,9 +46,9 @@ class ConsoleOptionView : public TableView, public MainAppHelper menuItem @@ -104,22 +104,22 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper { continue; } - item.emplace_back(drv->longname, &defaultFace(), + item.emplace_back(drv->longname, attachParams(), [this, &entry](TextMenuItem &item, View &, Input::Event e) { if(item.active()) @@ -569,21 +569,21 @@ class UnibiosSwitchesView : public TableView { TextMenuItem regionItem[3] { - {"Japan", &defaultFace(), [](){ setRegion(0); }}, - {"USA", &defaultFace(), [](){ setRegion(1); }}, - {"Europe", &defaultFace(), [](){ setRegion(2); }}, + {"Japan", attachParams(), [](){ setRegion(0); }}, + {"USA", attachParams(), [](){ setRegion(1); }}, + {"Europe", attachParams(), [](){ setRegion(2); }}, }; MultiChoiceMenuItem region { - "Region", &defaultFace(), + "Region", attachParams(), (int)memory.memcard[3] & 0x3, regionItem }; BoolMenuItem system { - "Mode", &defaultFace(), + "Mode", attachParams(), bool(memory.memcard[2] & 0x80), "Console (AES)", "Arcade (MVS)", [this](BoolMenuItem &item, View &, Input::Event e) @@ -632,7 +632,7 @@ class CustomSystemActionsView : public SystemActionsView private: TextMenuItem unibiosSwitches { - "Unibios Switches", &defaultFace(), + "Unibios Switches", attachParams(), [this](TextMenuItem &item, View &, Input::Event e) { if(system().hasContent()) @@ -651,7 +651,7 @@ class CustomSystemActionsView : public SystemActionsView TextMenuItem options { - "Console Options", &defaultFace(), + "Console Options", attachParams(), [this](TextMenuItem &, View &, Input::Event e) { if(system().hasContent()) @@ -682,7 +682,7 @@ class CustomMainMenuView : public MainMenuView private: TextMenuItem gameList { - "Open Content From List", &defaultFace(), + "Open Content From List", attachParams(), [this](TextMenuItem &, View &, Input::Event e) { auto gameListMenu = makeView(); diff --git a/NES.emu/src/main/Cheats.cc b/NES.emu/src/main/Cheats.cc index 42b51c407..048a14f8d 100644 --- a/NES.emu/src/main/Cheats.cc +++ b/NES.emu/src/main/Cheats.cc @@ -95,7 +95,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, unsigned cheatIdx, R { "Address", u"", - &defaultFace(), + attachParams(), [this](DualTextMenuItem &item, View &, Input::Event e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, "Input 4-digit hex", addrStr, @@ -112,7 +112,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, unsigned cheatIdx, R addrStr = a ? str : "0"; syncCheat(); addr.set2ndName(addrStr); - addr.compile(renderer()); + addr.compile(); postDraw(); return true; }); @@ -122,7 +122,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, unsigned cheatIdx, R { "Value", u"", - &defaultFace(), + attachParams(), [this](DualTextMenuItem &item, View &, Input::Event e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, "Input 2-digit hex", valueStr, @@ -139,7 +139,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, unsigned cheatIdx, R valueStr = a ? str : "0"; syncCheat(); value.set2ndName(valueStr); - value.compile(renderer()); + value.compile(); postDraw(); return true; }); @@ -149,7 +149,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, unsigned cheatIdx, R { "Compare", u"", - &defaultFace(), + attachParams(), [this](DualTextMenuItem &item, View &, Input::Event e) { app().pushAndShowNewCollectTextInputView(attachParams(), e, "Input 2-digit hex or blank", compStr.data(), @@ -175,7 +175,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, unsigned cheatIdx, R comp.set2ndName(); } syncCheat(); - comp.compile(renderer()); + comp.compile(); postDraw(); } view.dismiss(); @@ -187,7 +187,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, unsigned cheatIdx, R { "GG Code", u"", - &defaultFace(), + attachParams(), [this](DualTextMenuItem &item, View &, Input::Event e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, "Input Game Genie code", ggCodeStr, @@ -201,7 +201,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, unsigned cheatIdx, R ggCodeStr = str; syncCheat(); ggCode.set2ndName(str); - ggCode.compile(renderer()); + ggCode.compile(); postDraw(); return true; }); @@ -294,7 +294,7 @@ void EmuEditCheatListView::loadCheatItems() cheat.reserve(cheats); for(auto c : iotaCount(cheats)) { - cheat.emplace_back(cheatName(c), &defaultFace(), + cheat.emplace_back(cheatName(c), attachParams(), [this, c](TextMenuItem &, View &, Input::Event e) { pushAndShow(makeView(c, [this](){ onCheatListChanged(); }), e); @@ -322,7 +322,7 @@ EmuEditCheatListView::EmuEditCheatListView(ViewAttachParams attach): }, addGG { - "Add Game Genie Code", &defaultFace(), + "Add Game Genie Code", attachParams(), [this](TextMenuItem &item, View &, Input::Event e) { app().pushAndShowNewCollectTextInputView(attachParams(), e, "Input Game Genie code", "", @@ -381,7 +381,7 @@ EmuEditCheatListView::EmuEditCheatListView(ViewAttachParams attach): }, addRAM { - "Add RAM Patch", &defaultFace(), + "Add RAM Patch", attachParams(), [this](TextMenuItem &item, View &, Input::Event e) { app().pushAndShowNewCollectTextInputView(attachParams(), e, "Input description", "", @@ -434,7 +434,7 @@ void EmuCheatsView::loadCheatItems() { name = "Corrupt Cheat"; } - cheat.emplace_back(std::move(name), &defaultFace(), status, + cheat.emplace_back(std::move(name), attachParams(), status, [this, c](BoolMenuItem &item) { uint32 a; diff --git a/NES.emu/src/main/EmuMenuViews.cc b/NES.emu/src/main/EmuMenuViews.cc index 304af46f1..18bb1d9d2 100644 --- a/NES.emu/src/main/EmuMenuViews.cc +++ b/NES.emu/src/main/EmuMenuViews.cc @@ -45,7 +45,7 @@ class ConsoleOptionView : public TableView, public MainAppHelper(attachParams(), e, @@ -240,7 +240,7 @@ class ConsoleOptionView : public TableView, public MainAppHelper(attachParams(), e, @@ -288,7 +288,7 @@ class CustomVideoOptionView : public VideoOptionView, public MainAppHelper("Cheats", system().userPath(system().cheatsDir), @@ -574,14 +574,14 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { logMsg("set cheats path:%s", path.data()); system().cheatsDir = path; - cheatsPath.compile(cheatsMenuName(appContext(), path), renderer()); + cheatsPath.compile(cheatsMenuName(appContext(), path)); }), e); } }; TextMenuItem patchesPath { - patchesMenuName(appContext(), system().patchesDir), &defaultFace(), + patchesMenuName(appContext(), system().patchesDir), attachParams(), [this](const Input::Event &e) { pushAndShow(makeViewWithName("Patches", system().userPath(system().patchesDir), @@ -589,14 +589,14 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { logMsg("set patches path:%s", path.data()); system().patchesDir = path; - patchesPath.compile(patchesMenuName(appContext(), path), renderer()); + patchesPath.compile(patchesMenuName(appContext(), path)); }), e); } }; TextMenuItem palettesPath { - palettesMenuName(appContext(), system().palettesDir), &defaultFace(), + palettesMenuName(appContext(), system().palettesDir), attachParams(), [this](const Input::Event &e) { pushAndShow(makeViewWithName("Palettes", system().userPath(system().palettesDir), @@ -604,14 +604,14 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { logMsg("set palettes path:%s", path.data()); system().palettesDir = path; - palettesPath.compile(palettesMenuName(appContext(), path), renderer()); + palettesPath.compile(palettesMenuName(appContext(), path)); }), e); } }; TextMenuItem fdsBios { - biosMenuEntryStr(system().fdsBiosPath), &defaultFace(), + biosMenuEntryStr(system().fdsBiosPath), attachParams(), [this](TextMenuItem &, View &, Input::Event e) { pushAndShow(makeViewWithName>("Disk System BIOS", @@ -620,7 +620,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { system().fdsBiosPath = path; logMsg("set fds bios:%s", path.data()); - fdsBios.compile(biosMenuEntryStr(path), renderer()); + fdsBios.compile(biosMenuEntryStr(path)); return true; }, hasFDSBIOSExtension), e); } @@ -649,7 +649,7 @@ class FDSControlView : public TableView, public MainAppHelper TextMenuItem setSide[DISK_SIDES] { { - "Set Disk 1 Side A", &defaultFace(), + "Set Disk 1 Side A", attachParams(), [this](View &view, Input::Event e) { FCEU_FDSSetDisk(0, system()); @@ -657,7 +657,7 @@ class FDSControlView : public TableView, public MainAppHelper } }, { - "Set Disk 1 Side B", &defaultFace(), + "Set Disk 1 Side B", attachParams(), [this](View &view, Input::Event e) { FCEU_FDSSetDisk(1, system()); @@ -665,7 +665,7 @@ class FDSControlView : public TableView, public MainAppHelper } }, { - "Set Disk 2 Side A", &defaultFace(), + "Set Disk 2 Side A", attachParams(), [this](View &view, Input::Event e) { FCEU_FDSSetDisk(2, system()); @@ -673,7 +673,7 @@ class FDSControlView : public TableView, public MainAppHelper } }, { - "Set Disk 2 Side B", &defaultFace(), + "Set Disk 2 Side B", attachParams(), [this](View &view, Input::Event e) { FCEU_FDSSetDisk(3, system()); @@ -684,7 +684,7 @@ class FDSControlView : public TableView, public MainAppHelper TextMenuItem insertEject { - "Eject", &defaultFace(), + "Eject", attachParams(), [this](View &view, Input::Event e) { if(FCEU_FDSInserted()) @@ -731,7 +731,7 @@ class CustomSystemActionsView : public SystemActionsView private: TextMenuItem fdsControl { - u"", &defaultFace(), + u"", attachParams(), [this](Input::Event e) { pushAndShow(makeView(), e); } }; @@ -740,15 +740,14 @@ class CustomSystemActionsView : public SystemActionsView if(!isFDS) return; if(!FCEU_FDSInserted()) - fdsControl.compile("FDS Control (No Disk)", renderer()); + fdsControl.compile("FDS Control (No Disk)"); else - fdsControl.compile(std::format("FDS Control (Disk {}:{})", (FCEU_FDSCurrentSide() >> 1) + 1, (FCEU_FDSCurrentSide() & 1) ? 'B' : 'A'), - renderer()); + fdsControl.compile(std::format("FDS Control (Disk {}:{})", (FCEU_FDSCurrentSide() >> 1) + 1, (FCEU_FDSCurrentSide() & 1) ? 'B' : 'A')); } TextMenuItem options { - "Console Options", &defaultFace(), + "Console Options", attachParams(), [this](Input::Event e) { pushAndShow(makeView(), e); } }; @@ -774,7 +773,7 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper #include #include -#include +#include #include "MainSystem.hh" #include "MainApp.hh" #include diff --git a/NGP.emu/src/main/EmuMenuViews.cc b/NGP.emu/src/main/EmuMenuViews.cc index 978ab26a6..b2b7177b8 100644 --- a/NGP.emu/src/main/EmuMenuViews.cc +++ b/NGP.emu/src/main/EmuMenuViews.cc @@ -29,7 +29,7 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper(changeEmuCoreText, @@ -131,7 +131,7 @@ class ConsoleOptionView : public TableView, public MainAppHelper(), e); } }; @@ -184,7 +184,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper TextMenuItem sysCardPath { - biosMenuEntryStr(system().sysCardPath), &defaultFace(), + biosMenuEntryStr(system().sysCardPath), attachParams(), [this](Input::Event e) { pushAndShow(makeViewWithName>("System Card", @@ -193,7 +193,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { system().sysCardPath = path; logMsg("set system card:%s", system().sysCardPath.data()); - sysCardPath.compile(biosMenuEntryStr(path), renderer()); + sysCardPath.compile(biosMenuEntryStr(path)); return true; }, hasHuCardExtension), e); } @@ -219,23 +219,23 @@ class CustomVideoOptionView : public VideoOptionView, public MainAppHelper(changeEmuCoreText, @@ -335,7 +335,7 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper::system; using MainAppHelper::app; - TextHeadingMenuItem mixer{"Mixer", &defaultBoldFace()}; + TextHeadingMenuItem mixer{"Mixer", attachParams()}; struct VolumeTypeDesc { @@ -386,31 +386,31 @@ class CustomAudioOptionView : public AudioOptionView, public MainAppHelper(attachParams(), e, "Input 0 to 200", "", [=, this](EmuApp &, auto val) { system().setVolume(type, val); - volumeLevel[desc(type).idx].setSelected((MenuItem::Id)val, *this); + volumeLevel[desc(type).idx].setSelected(MenuId{val}, *this); dismissPrevious(); return true; }); return false; - }, MenuItem::DEFAULT_ID + }, {.id = defaultMenuId} } }; } @@ -425,7 +425,9 @@ class CustomAudioOptionView : public AudioOptionView, public MainAppHelper(attachParams(), e, "Input 6-digit hex", addrStr.data(), @@ -243,7 +243,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, int cheatIdx, Refres } writeCheatsFile(system()); addr.set2ndName(addrStr); - addr.compile(renderer()); + addr.compile(); postDraw(); return true; }); @@ -253,7 +253,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, int cheatIdx, Refres { "Value", u"", - &defaultFace(), + attach, [this](DualTextMenuItem &item, View &, Input::Event e) { app().pushAndShowNewCollectValueInputView(attachParams(), e, "Input 2-digit hex", valueStr.data(), @@ -278,7 +278,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, int cheatIdx, Refres } writeCheatsFile(system()); value.set2ndName(valueStr); - value.compile(renderer()); + value.compile(); postDraw(); return true; }); @@ -292,7 +292,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, int cheatIdx, Refres "Saved Value", #endif u"", - &defaultFace(), + attach, [this](DualTextMenuItem &item, View &, Input::Event e) { app().pushAndShowNewCollectTextInputView(attachParams(), e, "Input 2-digit hex or blank", savedStr.data(), @@ -334,7 +334,7 @@ EmuEditCheatView::EmuEditCheatView(ViewAttachParams attach, int cheatIdx, Refres } writeCheatsFile(system()); saved.set2ndName(savedStr); - saved.compile(renderer()); + saved.compile(); postDraw(); } view.dismiss(); @@ -379,7 +379,7 @@ void EmuEditCheatListView::loadCheatItems() cheat.reserve(cheats); for(auto c : iotaCount(cheats)) { - cheat.emplace_back(cheatName(c), &defaultFace(), + cheat.emplace_back(cheatName(c), attachParams(), [this, c](TextMenuItem &, View &, Input::Event e) { pushAndShow(makeView(c, [this](){ onCheatListChanged(); }), e); @@ -406,7 +406,7 @@ EmuEditCheatListView::EmuEditCheatListView(ViewAttachParams attach): }, addCode { - "Add Game Genie/Action Replay/Gold Finger Code", &defaultFace(), + "Add Game Genie/Action Replay/Gold Finger Code", attach, [this](TextMenuItem &item, View &, Input::Event e) { if(numCheats() == EmuCheats::MAX) @@ -472,7 +472,7 @@ void EmuCheatsView::loadCheatItems() cheat.reserve(cheats); for(auto c : iotaCount(cheats)) { - cheat.emplace_back(cheatName(c), &defaultFace(), cheatIsEnabled(c), + cheat.emplace_back(cheatName(c), attachParams(), cheatIsEnabled(c), [this, c](BoolMenuItem &item, View &, Input::Event e) { bool on = item.flipBoolValue(*this); diff --git a/Snes9x/src/main/EmuMenuViews.cc b/Snes9x/src/main/EmuMenuViews.cc index 378b1b380..3807a3bd2 100644 --- a/Snes9x/src/main/EmuMenuViews.cc +++ b/Snes9x/src/main/EmuMenuViews.cc @@ -35,16 +35,16 @@ class CustomAudioOptionView : public AudioOptionView, public MainAppHelper(attachParams(), e, "Input 5 to 250", "", @@ -182,7 +182,7 @@ class ConsoleOptionView : public TableView, public MainAppHelper("Cheats", system().userPath(system().cheatsDir), @@ -282,14 +282,14 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { logMsg("set cheats path:%s", path.data()); system().cheatsDir = path; - cheatsPath.compile(cheatsMenuName(appContext(), path), renderer()); + cheatsPath.compile(cheatsMenuName(appContext(), path)); }), e); } }; TextMenuItem patchesPath { - patchesMenuName(appContext(), system().patchesDir), &defaultFace(), + patchesMenuName(appContext(), system().patchesDir), attachParams(), [this](const Input::Event &e) { pushAndShow(makeViewWithName("Patches", system().userPath(system().patchesDir), @@ -297,7 +297,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { logMsg("set patches path:%s", path.data()); system().patchesDir = path; - patchesPath.compile(patchesMenuName(appContext(), path), renderer()); + patchesPath.compile(patchesMenuName(appContext(), path)); }), e); } }; @@ -309,7 +309,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper TextMenuItem satPath { - satMenuName(appContext(), system().satDir), &defaultFace(), + satMenuName(appContext(), system().satDir), attachParams(), [this](const Input::Event &e) { pushAndShow(makeViewWithName("Satellaview Files", system().userPath(system().satDir), @@ -317,14 +317,14 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { logMsg("set satellaview files path:%s", path.data()); system().satDir = path; - satPath.compile(satMenuName(appContext(), path), renderer()); + satPath.compile(satMenuName(appContext(), path)); }), e); } }; TextMenuItem bsxBios { - bsxMenuName(system().bsxBiosPath), &defaultFace(), + bsxMenuName(system().bsxBiosPath), attachParams(), [this](const Input::Event &e) { pushAndShow(makeViewWithName>("BS-X BIOS", @@ -333,7 +333,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { system().bsxBiosPath = path; logMsg("set BS-X bios:%s", path.data()); - bsxBios.compile(bsxMenuName(path), renderer()); + bsxBios.compile(bsxMenuName(path)); return true; }, Snes9xSystem::hasBiosExtension), e); } @@ -346,7 +346,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper TextMenuItem sufamiBios { - sufamiMenuName(system().sufamiBiosPath), &defaultFace(), + sufamiMenuName(system().sufamiBiosPath), attachParams(), [this](const Input::Event &e) { pushAndShow(makeViewWithName>("Sufami Turbo BIOS", @@ -355,7 +355,7 @@ class CustomFilePathOptionView : public FilePathOptionView, public MainAppHelper { system().sufamiBiosPath = path; logMsg("set Sufami Turbo bios:%s", path.data()); - sufamiBios.compile(sufamiMenuName(path), renderer()); + sufamiBios.compile(sufamiMenuName(path)); return true; }, Snes9xSystem::hasBiosExtension), e); } diff --git a/Snes9x/src/main/input.cc b/Snes9x/src/main/input.cc index 0bf9ee889..3cdcd4ba0 100644 --- a/Snes9x/src/main/input.cc +++ b/Snes9x/src/main/input.cc @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include "MainSystem.hh" #include "MainApp.hh" diff --git a/Swan.emu/src/main/EmuMenuViews.cc b/Swan.emu/src/main/EmuMenuViews.cc index 6552bddda..c5c7401e5 100644 --- a/Swan.emu/src/main/EmuMenuViews.cc +++ b/Swan.emu/src/main/EmuMenuViews.cc @@ -32,11 +32,11 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper::system; using MainAppHelper::app; - TextHeadingMenuItem userProfile{"WonderSwan User Profile", &defaultBoldFace()}; + TextHeadingMenuItem userProfile{"WonderSwan User Profile", attachParams()}; BoolMenuItem language { - "Language", &defaultFace(), + "Language", attachParams(), (bool)system().userProfile.languageIsEnglish, "Japanese", "English", [this](BoolMenuItem &item) @@ -47,7 +47,7 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper(attachParams(), e, @@ -69,7 +69,7 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper(attachParams(), e, @@ -85,7 +85,7 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper(attachParams(), e, @@ -101,7 +101,7 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper(attachParams(), e, @@ -117,41 +117,41 @@ class CustomSystemOptionView : public SystemOptionView, public MainAppHelper(), e); } }; diff --git a/imagine/include/imagine/base/MessagePort.hh b/imagine/include/imagine/base/MessagePort.hh index c0c4e8616..a75b1e39a 100644 --- a/imagine/include/imagine/base/MessagePort.hh +++ b/imagine/include/imagine/base/MessagePort.hh @@ -30,80 +30,84 @@ template concept ReplySemaphoreSettableMessage = requires (MsgType msg, std::binary_semaphore *sem){ msg.setReplySemaphore(sem); }; +enum class MessageReplyMode +{ + none, wait +}; + template -class PipeMessagePort +class PipeMessages { public: - class Messages + struct Sentinel {}; + + class Iterator { public: - struct Sentinel {}; - - class Iterator + constexpr Iterator(PosixIO &io): io{&io} { - public: - constexpr Iterator(PosixIO &io): io{&io} - { - this->operator++(); - } + this->operator++(); + } - Iterator operator++() - { - if(!io) [[unlikely]] - return *this; - if(io->read(msg).bytes != sizeof(MsgType)) - { - // end of messages - io = nullptr; - } + Iterator operator++() + { + if(!io) [[unlikely]] return *this; - } - - bool operator==(Sentinel) const - { - return !io; - } - - const MsgType &operator*() const + if(io->read(msg).bytes != sizeof(MsgType)) { - return msg; + // end of messages + io = nullptr; } + return *this; + } - private: - PosixIO *io{}; - MsgType msg; - }; - - constexpr Messages(PosixIO &io): io{io} {} - auto begin() const { return Iterator{io}; } - auto end() const { return Sentinel{}; } - - template - T getExtraData() + bool operator==(Sentinel) const { - return io.get(); + return !io; } - template - auto readExtraData(std::span span) + const MsgType &operator*() const { - return io.read(span); + return msg; } - protected: - PosixIO &io; + private: + PosixIO *io{}; + MsgType msg; }; + constexpr PipeMessages(PosixIO &io): io{io} {} + auto begin() const { return Iterator{io}; } + auto end() const { return Sentinel{}; } + + template + T getExtraData() + { + return io.get(); + } + + template + auto readExtraData(std::span span) + { + return io.read(span); + } + +protected: + PosixIO &io; +}; + +template +class PipeMessagePort +{ +public: + using Messages = PipeMessages; static constexpr size_t MSG_SIZE = sizeof(MsgType); static_assert(MSG_SIZE < PIPE_BUF, "size of message too big for atomic writes"); struct NullInit{}; PipeMessagePort(const char *debugLabel = nullptr, int capacity = 8): - pipe{debugLabel, (int)MSG_SIZE * capacity} - { - pipe.setReadNonBlocking(true); - } + pipe{debugLabel, (int)MSG_SIZE * capacity} {} explicit constexpr PipeMessagePort(NullInit) {} @@ -114,6 +118,7 @@ public: void attach(EventLoop loop, Callable auto &&f) { + pipe.setReadNonBlocking(true); pipe.attach(loop, [=](auto &io) -> bool { @@ -125,6 +130,7 @@ public: void attach(EventLoop loop, Callable auto &&f) { + pipe.setReadNonBlocking(true); pipe.attach(loop, [=](auto &io) -> bool { @@ -143,9 +149,9 @@ public: return pipe.sink().put(msg) != -1; } - bool send(MsgType msg, bool awaitReply) + bool send(MsgType msg, MessageReplyMode mode) { - if(awaitReply) + if(mode == MessageReplyMode::wait) { std::binary_semaphore replySemaphore{0}; return send(msg, &replySemaphore); @@ -177,20 +183,18 @@ public: bool sendWithExtraData(MsgType msg, auto &&obj) { static_assert(MSG_SIZE + sizeof(obj) < PIPE_BUF, "size of data too big for atomic writes"); - return sendWithExtraData(msg, std::span>{&obj, 1}); + return sendWithExtraData(msg, std::span>{&obj, 1}); } template - bool sendWithExtraData(MsgType msg, std::span span) + bool sendWithExtraData(MsgType msg, std::span span) { if(span.empty()) return send(msg); const auto bufferSize = MSG_SIZE + span.size_bytes(); - assumeExpr(bufferSize < PIPE_BUF); - char buffer[PIPE_BUF]; - memcpy(buffer, &msg, MSG_SIZE); - memcpy(buffer + MSG_SIZE, span.data(), span.size_bytes()); - return pipe.sink().write(buffer, bufferSize) != -1; + assert(bufferSize < PIPE_BUF); + OutVector buffs[2]{std::span{&msg, 1}, span}; + return pipe.sink().writeVector(buffs) != -1; } void clear() @@ -204,6 +208,8 @@ public: pipe.dispatchSourceEvents(); } + Messages messages() { return Messages{pipe.source()}; } + explicit operator bool() const { return (bool)pipe; } protected: @@ -213,4 +219,7 @@ protected: template using MessagePort = PipeMessagePort; +template +using Messages = PipeMessages; + } diff --git a/imagine/include/imagine/gfx/BasicEffect.hh b/imagine/include/imagine/gfx/BasicEffect.hh index 7496243bf..3205db058 100644 --- a/imagine/include/imagine/gfx/BasicEffect.hh +++ b/imagine/include/imagine/gfx/BasicEffect.hh @@ -46,29 +46,15 @@ public: cmds.drawQuad(startIdx); } - template - void drawSprites(RendererCommands &cmds, const Buffer &idxs, ssize_t startIdx, size_t size, auto &&texture) - { - enableTexture(cmds, texture); - cmds.drawQuads(idxs, startIdx, size); - } - - template - void drawSprite(RendererCommands &cmds, const Buffer &verts, ssize_t startIdx, auto &&texture) + template + void drawSprite(RendererCommands &cmds, const ObjectVertexArray &verts, ssize_t startIdx, auto &&texture) { enableTexture(cmds, texture); cmds.drawQuad(verts, startIdx); } - template - void drawSprites(RendererCommands &cmds, const Buffer &verts, const Buffer &idxs, ssize_t startIdx, size_t size, auto &&texture) - { - enableTexture(cmds, texture); - cmds.drawQuads(verts, idxs, startIdx, size); - } - - template - void drawSprites(RendererCommands &cmds, const Buffer &verts, ssize_t startIdx, size_t size, auto &&texture) + template + void drawSprites(RendererCommands &cmds, const ObjectVertexArray &verts, ssize_t startIdx, size_t size, auto &&texture) { enableTexture(cmds, texture); cmds.drawQuads(verts, startIdx, size); diff --git a/imagine/include/imagine/gfx/Buffer.hh b/imagine/include/imagine/gfx/Buffer.hh index 446b5c409..8cbb9df90 100644 --- a/imagine/include/imagine/gfx/Buffer.hh +++ b/imagine/include/imagine/gfx/Buffer.hh @@ -56,17 +56,17 @@ template class Buffer: public BufferImpl { public: + using Config = BufferConfig; using BaseBuffer = BufferImpl; using Type = T; static constexpr size_t elemSize = sizeof(T); - constexpr Buffer() = default; + Buffer() = default; Buffer(RendererTask &rTask, BufferConfig config): BaseBuffer(rTask, config.toByteConfig()) {} explicit operator bool() const { return BaseBuffer::operator bool(); } Renderer &renderer() const { return task().renderer(); } RendererTask &task() const { return *BaseBuffer::taskPtr(); } bool hasTask() const { return BaseBuffer::taskPtr(); } - void setTask(RendererTask &task) { return BaseBuffer::setTask(task); } void reset(BufferConfig config) { BaseBuffer::reset(config.toByteConfig()); } size_t size() const { return BaseBuffer::sizeBytes() / elemSize; } MappedBuffer map(ssize_t offset, size_t size) { return {BaseBuffer::map(offset * elemSize, size * elemSize)}; } @@ -102,10 +102,11 @@ class ObjectVertexBuffer : public VertexBuffer public: using Type = T; using Vertex = T::Vertex; + using Config = ObjectBufferConfig; using BaseBuffer = VertexBuffer; using BaseBuffer::map; - constexpr ObjectVertexBuffer() = default; + ObjectVertexBuffer() = default; ObjectVertexBuffer(RendererTask &rTask, ObjectBufferConfig config): VertexBuffer{rTask, config.toBufferConfig()} {} void reset(ObjectBufferConfig config) { VertexBuffer::reset(config.toBufferConfig()); } size_t size() const { return BaseBuffer::size() / T::vertexCount; } @@ -114,4 +115,42 @@ public: void write(ssize_t offset, T::InitParams params) { write(offset, T{params}); } }; +class VertexArray: public VertexArrayImpl +{ +public: + VertexArray() = default; + template + VertexArray(RendererTask &rTask, const VertexBuffer &buff, NativeBuffer idxs): VertexArrayImpl(rTask, buff, idxs) {} +}; + +template +struct VertexOf { using type = typename T::Vertex; }; + +template +struct VertexOf { using type = T; }; + +template +class ObjectVertexArray : public std::conditional_t, Buffer, ObjectVertexBuffer> +{ +public: + using Base = std::conditional_t, Buffer, ObjectVertexBuffer>; + using Vertex = VertexOf::type; + + ObjectVertexArray() = default; + + ObjectVertexArray(RendererTask &rTask, Base::Config config, NativeBuffer idxsRef = {}): + Base{rTask, config}, + vao{rTask, *this, idxsRef} {} + + template + ObjectVertexArray(RendererTask &rTask, Base::Config config, const IndexBuffer &idxs): + ObjectVertexArray{rTask, config, idxs.name()} {} + + const VertexArray &array() const { return vao; } + operator const VertexArray&() const { return vao; } + +private: + VertexArray vao; +}; + } diff --git a/imagine/include/imagine/gfx/FanQuads.hh b/imagine/include/imagine/gfx/FanQuads.hh index 81b244164..f990fc480 100644 --- a/imagine/include/imagine/gfx/FanQuads.hh +++ b/imagine/include/imagine/gfx/FanQuads.hh @@ -93,7 +93,7 @@ public: using ILitTexFanQuad = BaseFanQuad; -using ILitTexFanQuads = ObjectVertexBuffer; +using ILitTexFanQuads = ObjectVertexArray; template constexpr std::array mapFanQuadIndices(T baseIdx) diff --git a/imagine/include/imagine/gfx/GfxText.hh b/imagine/include/imagine/gfx/GfxText.hh index 0eed1ca99..0c9e345ab 100644 --- a/imagine/include/imagine/gfx/GfxText.hh +++ b/imagine/include/imagine/gfx/GfxText.hh @@ -45,15 +45,10 @@ struct TextLayoutConfig class Text { public: - constexpr Text() = default; - - Text(GlyphTextureSet *face): Text{UTF16String{}, face} {} - Text(UTF16Convertible auto &&str, GlyphTextureSet *face = nullptr): - textStr{IG_forward(str)}, face_{face} {} - Text(const Text &) noexcept; - Text &operator=(const Text &) noexcept; - Text(Text &&) = default; - Text &operator=(Text &&) = default; + Text() = default; + Text(RendererTask &task, GlyphTextureSet *face): Text{task, UTF16String{}, face} {} + Text(RendererTask &task, UTF16Convertible auto &&str, GlyphTextureSet *face = nullptr): + textStr{IG_forward(str)}, face_{face}, quads{task, {.size = 1}} {} void resetString(UTF16Convertible auto &&str) { @@ -64,8 +59,8 @@ public: void resetString() { resetString(UTF16String{}); } void setFace(GlyphTextureSet *face) { face_ = face; } GlyphTextureSet *face() const { return face_; } - void makeGlyphs(Renderer &); - bool compile(Renderer &, TextLayoutConfig conf = {}); + void makeGlyphs(); + bool compile(TextLayoutConfig conf = {}); void draw(RendererCommands &, WPt pos, _2DOrigin, Color) const; void draw(RendererCommands &, WPt pos, _2DOrigin) const; WSize pixelSize() const { return {xSize, ySize}; } @@ -79,6 +74,7 @@ public: bool isVisible() const; std::u16string_view stringView() const; std::u16string string() const; + Renderer &renderer(); protected: struct LineSpan diff --git a/imagine/include/imagine/gfx/Quads.hh b/imagine/include/imagine/gfx/Quads.hh index ee604e696..148a37128 100644 --- a/imagine/include/imagine/gfx/Quads.hh +++ b/imagine/include/imagine/gfx/Quads.hh @@ -217,15 +217,29 @@ using IColQuad = BaseQuad; using IColTexQuad = BaseQuad; using ILitTexQuad = BaseQuad; -using Quads = ObjectVertexBuffer; -using TexQuads = ObjectVertexBuffer; -using ColQuads = ObjectVertexBuffer; -using ColTexQuads = ObjectVertexBuffer; -using IQuads = ObjectVertexBuffer; -using ITexQuads = ObjectVertexBuffer; -using IColQuads = ObjectVertexBuffer; -using IColTexQuads = ObjectVertexBuffer; -using ILitTexQuads = ObjectVertexBuffer; +const IndexBuffer &rendererQuadIndices(const RendererTask &rTask); + +template +class QuadVertexArray : public ObjectVertexArray +{ +public: + using Base = ObjectVertexArray; + using Vertex = Base::Vertex; + using Base::Base; + + QuadVertexArray(RendererTask &rTask, Base::Config config): + Base{rTask, config, rendererQuadIndices(rTask)} {} +}; + +using Quads = QuadVertexArray; +using TexQuads = QuadVertexArray; +using ColQuads = QuadVertexArray; +using ColTexQuads = QuadVertexArray; +using IQuads = QuadVertexArray; +using ITexQuads = QuadVertexArray; +using IColQuads = QuadVertexArray; +using IColTexQuads = QuadVertexArray; +using ILitTexQuads = QuadVertexArray; template constexpr std::array mapQuadIndices(T baseIdx) @@ -248,6 +262,7 @@ class QuadIndexArray : public IndexBuffer { public: using BaseBuffer = IndexBuffer; + using Type = T; constexpr QuadIndexArray() = default; diff --git a/imagine/include/imagine/gfx/RendererCommands.hh b/imagine/include/imagine/gfx/RendererCommands.hh index 76b91d9c7..7176cb24f 100644 --- a/imagine/include/imagine/gfx/RendererCommands.hh +++ b/imagine/include/imagine/gfx/RendererCommands.hh @@ -97,8 +97,6 @@ public: void setViewport(Viewport v); void restoreViewport(); void vertexBufferData(ssize_t offset, const void *data, size_t size); - template - void setVertexBuffer(const Buffer &verts) { RendererCommandsImpl::setVertexBuffer(verts); } void flush(); // shaders @@ -130,66 +128,49 @@ public: void drawPrimitives(Primitive, int start, int count); void drawPrimitiveElements(Primitive, int start, int count, AttribType); - template - void setVertexAttribs() { RendererCommandsImpl::setVertexAttribs(); } + template + void setVertexArray(const ObjectVertexArray &verts) { RendererCommandsImpl::setVertexArray(verts); } - template - void setVertexArray(const Buffer &verts) { setVertexBuffer(verts); setVertexAttribs(); } + template + void setVertexBuffer(const Buffer &verts) { RendererCommandsImpl::setVertexBuffer(verts); } - template - void setIndexArray(const Buffer &idxs) { setIndexBuffer(idxs); } - - template - void drawPrimitives(Primitive mode, const Buffer &verts, int start, int count) + template + void drawPrimitives(Primitive mode, const ObjectVertexArray &verts, int start, int count) { setVertexArray(verts); drawPrimitives(mode, start, count); } - template - void drawPrimitiveElements(const Buffer &idxs, Primitive mode, int start, int count) - { - setIndexArray(idxs); - drawPrimitiveElements(mode, start * sizeof(I), count, attribType); - } - - template - void drawPrimitiveElements(const Buffer &verts, const Buffer &idxs, Primitive mode, int start, int count) - { - setVertexArray(verts); - drawPrimitiveElements(idxs, mode, start, count); - } - void drawQuad(ssize_t startIdx) { drawPrimitives(Primitive::TRIANGLE_STRIP, startIdx * 4, 4); } - template - void drawQuad(const Buffer &verts, ssize_t startIdx) + template + void drawQuad(const ObjectVertexArray &verts, ssize_t startIdx) { setVertexArray(verts); drawQuad(startIdx); } - template - void drawQuads(const Buffer &idxs, ssize_t startIdx, size_t size) + template + void drawPrimitiveElements(Primitive mode, const ObjectVertexArray &verts, int start, int count) { - drawPrimitiveElements(idxs, Primitive::TRIANGLE, startIdx * 6, size * 6); + setVertexArray(verts); + drawPrimitiveElements(mode, start, count, attribType); } - template - void drawQuads(const Buffer &verts, const Buffer &idxs, ssize_t startIdx, size_t size) + template + void drawQuads(ssize_t startIdx, size_t size) { - setVertexArray(verts); - drawQuads(idxs, startIdx, size); + drawPrimitiveElements(Primitive::TRIANGLE, startIdx * 6 * sizeof(I), size * 6, attribType); } - template - void drawQuads(const Buffer &verts, ssize_t startIdx, size_t size) + template + void drawQuads(const ObjectVertexArray &verts, ssize_t startIdx, size_t size) { setVertexArray(verts); - drawPrimitiveElements(Primitive::TRIANGLE, startIdx * 6 * sizeof(I), size * 6, attribType); + drawQuads(startIdx, size); } }; diff --git a/imagine/include/imagine/gfx/RendererTask.hh b/imagine/include/imagine/gfx/RendererTask.hh index 11e61868a..82d0aafad 100644 --- a/imagine/include/imagine/gfx/RendererTask.hh +++ b/imagine/include/imagine/gfx/RendererTask.hh @@ -52,9 +52,9 @@ public: explicit operator bool() const; // Run a delegate on the renderer thread - void run(std::invocable auto &&f, bool awaitReply = false) + void run(std::invocable auto &&f, MessageReplyMode mode = MessageReplyMode::none) { - RendererTaskImpl::run(IG_forward(f), awaitReply); + RendererTaskImpl::run(IG_forward(f), mode); } // Run a delegate for drawing on the renderer thread @@ -79,15 +79,19 @@ public: { if constexpr(sizeof(&buff) + sizeof(offset) + sizeof(data) <= FuncDelegateStorageSize) { - run([&buff, offset, data]() + RendererTaskImpl::run([&buff, offset, data]() { - buff.writeSubData(offset * buff.elemSize, std::size(data) * buff.elemSize, std::data(data)); + buff.writeSubData(offset * buff.elemSize, sizeof(data), &data); }); } else { - auto map = buff.map(offset, std::size(data)); - std::ranges::copy(data, map.begin()); + RendererTaskImpl::run([&buff, offset](TaskContext ctx) + { + std::remove_cvref_t data; + ctx.msgsPtr->readExtraData(std::span{&data, 1}); + buff.writeSubData(offset * buff.elemSize, sizeof(data), &data); + }, IG_forward(data)); } } }; diff --git a/imagine/include/imagine/gfx/defs.hh b/imagine/include/imagine/gfx/defs.hh index bab7d4967..3863a5916 100644 --- a/imagine/include/imagine/gfx/defs.hh +++ b/imagine/include/imagine/gfx/defs.hh @@ -53,6 +53,10 @@ enum class BufferType : uint8_t; template class Buffer; template +class ObjectVertexBuffer; +template +class ObjectVertexArray; +template class QuadIndexArray; using GCRect = CoordinateRect; @@ -206,7 +210,7 @@ constexpr Color4F::operator Color4B() const { return Color4B::format.build(r, g, using PackedColor = Color4B; using Color = Color4F; -enum class AttribType +enum class AttribType : uint8_t { UByte = 1, Short, @@ -217,7 +221,7 @@ enum class AttribType struct AttribDesc { size_t offset{}; - size_t size{}; + int size{}; AttribType type{}; bool normalize{}; diff --git a/imagine/include/imagine/gfx/opengl/GLBuffer.hh b/imagine/include/imagine/gfx/opengl/GLBuffer.hh index 4df814371..95c9a086a 100644 --- a/imagine/include/imagine/gfx/opengl/GLBuffer.hh +++ b/imagine/include/imagine/gfx/opengl/GLBuffer.hh @@ -45,12 +45,11 @@ template class GLBuffer { public: - constexpr GLBuffer() = default; + GLBuffer() = default; GLBuffer(RendererTask &, ByteBufferConfig); explicit operator bool() const { return bool(buffer); } RendererTask *taskPtr() const { return buffer.get_deleter().rTaskPtr; } RendererTask &task() const { return *taskPtr(); } - void setTask(RendererTask &task) { buffer.get_deleter().rTaskPtr = &task; } GLBufferRef name() const { return buffer.get(); } void reset(ByteBufferConfig); size_t sizeBytes() const { return sizeBytes_; } @@ -66,4 +65,49 @@ protected: template using BufferImpl = GLBuffer; +using GLVertexArrayRef = GLuint; + +void destroyGLVertexArrayRef(RendererTask &, GLVertexArrayRef); + +struct GLVertexArrayRefDeleter +{ + RendererTask *rTaskPtr{}; + + void operator()(GLBufferRef s) const + { + destroyGLVertexArrayRef(*rTaskPtr, s); + } +}; +using UniqueGLVertexArrayRef = UniqueResource; + +class GLVertexArray +{ +public: + GLVertexArray() = default; + template + GLVertexArray(RendererTask &rTask, const Buffer &buff, NativeBuffer idxs): + arr{GLVertexArrayRefDeleter{&rTask}} + { + reset(buff, idxs); + } + + template + void reset(const Buffer &buff, NativeBuffer idxs) + { + initArray(buff.name(), idxs, sizeof(V), vertexLayoutEnableMask(), vertexLayoutDesc()); + } + + RendererTask *taskPtr() const { return arr.get_deleter().rTaskPtr; } + RendererTask &task() const { return *taskPtr(); } + GLBufferRef name() const { return arr.get(); } + explicit operator bool() const { return bool(arr); } + +protected: + UniqueGLVertexArrayRef arr; + + void initArray(GLBufferRef vbo, GLBufferRef ibo, int stride, VertexLayoutFlags enabledLayout, VertexLayoutDesc layoutDesc); +}; + +using VertexArrayImpl = GLVertexArray; + } diff --git a/imagine/include/imagine/gfx/opengl/GLRenderer.hh b/imagine/include/imagine/gfx/opengl/GLRenderer.hh index ea3933afb..d29e05b3a 100644 --- a/imagine/include/imagine/gfx/opengl/GLRenderer.hh +++ b/imagine/include/imagine/gfx/opengl/GLRenderer.hh @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,9 @@ public: void (* GL_APIENTRY glBindSampler) (GLuint unit, GLuint sampler){}; void (* GL_APIENTRY glSamplerParameteri) (GLuint sampler, GLenum pname, GLint param){}; void (* GL_APIENTRY glTexStorage2D) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height){}; + void (* GL_APIENTRY glBindVertexArray) (GLuint array){}; + void (* GL_APIENTRY glDeleteVertexArrays) (GLsizei n, const GLuint *arrays){}; + void (* GL_APIENTRY glGenVertexArrays) (GLsizei n, GLuint *arrays){}; GLvoid* (* GL_APIENTRY glMapBufferRange) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access){}; using UnmapBufferProto = GLboolean (* GL_APIENTRY) (GLenum target); UnmapBufferProto glUnmapBuffer{}; @@ -80,6 +84,9 @@ public: static void glBindSampler(GLuint unit, GLuint sampler) { ::glBindSampler(unit, sampler); }; static void glSamplerParameteri(GLuint sampler, GLenum pname, GLint param) { ::glSamplerParameteri(sampler, pname, param); }; static void glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { ::glTexStorage2D(target, levels, internalformat, width, height); }; + static void glBindVertexArray(GLuint array) { ::glBindVertexArray(array); }; + static void glDeleteVertexArrays(GLsizei n, const GLuint *arrays) { ::glDeleteVertexArrays(n, arrays); }; + static void glGenVertexArrays(GLsizei n, GLuint *arrays) { ::glGenVertexArrays(n, arrays); }; static GLvoid* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { return ::glMapBufferRange(target, offset, length, access); }; static GLboolean glUnmapBuffer(GLenum target) { return ::glUnmapBuffer(target); } static void glDrawBuffers(GLsizei size, const GLenum *bufs) { ::glDrawBuffers(size, bufs); }; @@ -144,6 +151,7 @@ public: bool hasEGLTextureStorage() const; bool hasImmutableBufferStorage() const; bool hasMemoryBarriers() const; + bool hasVAOFuncs() const; GLsync fenceSync(GLDisplay dpy); void deleteSync(GLDisplay dpy, GLsync sync); GLenum clientWaitSync(GLDisplay dpy, GLsync sync, GLbitfield flags, GLuint64 timeout); @@ -158,6 +166,7 @@ public: [[no_unique_address]] GLManager glManager; RendererTask mainTask; BasicEffect basicEffect_{}; + Gfx::QuadIndexArray quadIndices; CustomEvent releaseShaderCompilerEvent{CustomEvent::NullInit{}}; GLRenderer(ApplicationContext); @@ -183,6 +192,7 @@ protected: void setupUnmapBufferFunc(); void setupImmutableBufferStorage(); void setupMemoryBarrier(); + void setupVAOFuncs(bool oes = false); void setupFenceSync(); void setupAppleFenceSync(); void setupEglFenceSync(std::string_view eglExtenstionStr); diff --git a/imagine/include/imagine/gfx/opengl/GLRendererCommands.hh b/imagine/include/imagine/gfx/opengl/GLRendererCommands.hh index 0a057c8ff..fc4a4fd72 100644 --- a/imagine/include/imagine/gfx/opengl/GLRendererCommands.hh +++ b/imagine/include/imagine/gfx/opengl/GLRendererCommands.hh @@ -38,6 +38,7 @@ public: constexpr GLRendererCommands() = default; GLRendererCommands(RendererTask &rTask, Window *winPtr, Drawable drawable, Rect2 viewport, GLDisplay glDpy, const GLContext &glCtx, std::binary_semaphore *drawCompleteSemPtr); + void bindGLVertexArray(GLuint vao); void bindGLArrayBuffer(GLuint vbo); void bindGLIndexBuffer(GLuint ibo); #ifdef CONFIG_GFX_OPENGL_FIXED_FUNCTION_PIPELINE @@ -66,6 +67,7 @@ protected: void notifyPresentComplete(); const GLContext &glContext() const; bool useFixedFunctionPipeline() const; + bool hasVAOFuncs() const; template void setupVertexArrayPointers() @@ -95,11 +97,26 @@ protected: #endif } - template - void setVertexBuffer(const Buffer &verts) { bindGLArrayBuffer(verts.name()); } + template + void setVertexArray(const ObjectVertexArray &verts) + { + if(hasVAOFuncs()) + { + bindGLVertexArray(verts.array().name()); + } + else + { + bindGLArrayBuffer(verts.name()); + bindGLIndexBuffer(verts.array().name()); // index buffer name is stored in place of array name + setVertexAttribs::Vertex>(); + } + } - template - void setIndexBuffer(const Buffer &idxs) { bindGLIndexBuffer(idxs.name()); } + template + void setVertexBuffer(const Buffer &verts) + { + bindGLArrayBuffer(verts.name()); + } RendererTask *rTask{}; Renderer *r{}; @@ -110,6 +127,7 @@ protected: Drawable drawable{}; Rect2 winViewport{}; GLuint currSamplerName{}; + GLuint currVertexArrayName{}; GLuint currIndexBufferName{}; #ifdef CONFIG_GFX_OPENGL_SHADER_PIPELINE NativeProgram currProgram{}; diff --git a/imagine/include/imagine/gfx/opengl/GLRendererTask.hh b/imagine/include/imagine/gfx/opengl/GLRendererTask.hh index 113aebccb..5f4220876 100644 --- a/imagine/include/imagine/gfx/opengl/GLRendererTask.hh +++ b/imagine/include/imagine/gfx/opengl/GLRendererTask.hh @@ -42,7 +42,6 @@ public: GLRendererTask(ApplicationContext, Renderer &); GLRendererTask(ApplicationContext, const char *debugLabel, Renderer &); - void initVAO(); void initDefaultFramebuffer(); GLuint defaultFBO() const { return defaultFB; } GLuint bindFramebuffer(Texture &tex); @@ -53,7 +52,9 @@ public: RendererCommands makeRendererCommands(GLTask::TaskContext taskCtx, bool manageSemaphore, bool notifyWindowAfterPresent, Window &win); - void run(std::invocable auto &&f, bool awaitReply = false) { GLTask::run(IG_forward(f), awaitReply); } + void run(std::invocable auto &&f, MessageReplyMode mode = MessageReplyMode::none) { GLTask::run(IG_forward(f), mode); } + + void run(std::invocable auto &&f, auto &&extData, MessageReplyMode mode = MessageReplyMode::none) { GLTask::run(IG_forward(f), IG_forward(extData), mode); } bool draw(Window &win, WindowDrawParams winParams, DrawParams params, std::invocable auto &&f) @@ -62,12 +63,12 @@ public: assert(params.asyncMode != DrawAsyncMode::AUTO); // doPreDraw() should set mode bool manageSemaphore = params.asyncMode == DrawAsyncMode::PRESENT; bool notifyWindowAfterPresent = params.asyncMode != DrawAsyncMode::NONE; - bool awaitReply = params.asyncMode != DrawAsyncMode::FULL; + MessageReplyMode replyMode = params.asyncMode != DrawAsyncMode::FULL ? MessageReplyMode::wait : MessageReplyMode::none; GLTask::run([=, this, &win](TaskContext ctx) { auto cmds = makeRendererCommands(ctx, manageSemaphore, notifyWindowAfterPresent, win); f(win, cmds); - }, awaitReply); + }, replyMode); return params.asyncMode != DrawAsyncMode::NONE; } @@ -78,9 +79,6 @@ public: protected: Renderer *r{}; - #ifndef CONFIG_GFX_OPENGL_ES - GLuint streamVAO = 0; - #endif IG_UseMemberIf(Config::Gfx::GLDRAWABLE_NEEDS_FRAMEBUFFER, GLuint, defaultFB){}; GLuint fbo = 0; IG_UseMemberIf(Config::Gfx::OPENGL_DEBUG_CONTEXT, bool, debugEnabled){}; diff --git a/imagine/include/imagine/gfx/opengl/GLTask.hh b/imagine/include/imagine/gfx/opengl/GLTask.hh index 839cd1ead..235dc7937 100644 --- a/imagine/include/imagine/gfx/opengl/GLTask.hh +++ b/imagine/include/imagine/gfx/opengl/GLTask.hh @@ -42,26 +42,12 @@ struct GLTaskConfig class GLTask { public: - class TaskContext - { - public: - constexpr TaskContext(GLDisplay glDpy, std::binary_semaphore *semPtr, bool *semaphoreNeedsNotifyPtr): - glDpy{glDpy}, semPtr{semPtr}, semaphoreNeedsNotifyPtr{semaphoreNeedsNotifyPtr} - {} - void notifySemaphore(); - void markSemaphoreNotified(); - constexpr GLDisplay glDisplay() const { return glDpy; } - constexpr std::binary_semaphore *semaphorePtr() const { return semPtr; } - - protected: - [[no_unique_address]] GLDisplay glDpy{}; - std::binary_semaphore *semPtr{}; - bool *semaphoreNeedsNotifyPtr{}; - }; + struct CommandMessage; + using CommandMessages = Messages; // Align delegate data to 16 bytes in case we store SIMD types static constexpr size_t FuncDelegateStorageSize = sizeof(uintptr_t)*2 + sizeof(int)*16; - using FuncDelegate = DelegateFuncA; + using FuncDelegate = DelegateFuncA; struct CommandMessage { @@ -71,53 +57,77 @@ public: void setReplySemaphore(std::binary_semaphore *semPtr_) { assert(!semPtr); semPtr = semPtr_; }; }; + using CommandMessagePort = MessagePort; + + struct TaskContext + { + [[no_unique_address]] GLDisplay glDisplay{}; + std::binary_semaphore *semaphorePtr{}; + bool *semaphoreNeedsNotifyPtr{}; + CommandMessages *msgsPtr; + + void notifySemaphore(); + void markSemaphoreNotified(); + }; + GLTask(ApplicationContext); GLTask(ApplicationContext, const char *debugLabel); ~GLTask(); GLTask &operator=(GLTask &&) = delete; bool makeGLContext(GLTaskConfig); - void runFunc(FuncDelegate del, bool awaitReply); + void runFunc(FuncDelegate del, std::span extBuff, MessageReplyMode); GLBufferConfig glBufferConfig() const; const GLContext &glContext() const; ApplicationContext appContext() const; explicit operator bool() const; - void run(std::invocable auto &&f, bool awaitReply = false) + void run(std::invocable auto &&f, MessageReplyMode mode = MessageReplyMode::none) { runFunc( - [=](GLDisplay, std::binary_semaphore *semPtr) + [=](GLDisplay, std::binary_semaphore *semPtr, CommandMessages &) { f(); if(semPtr) { semPtr->release(); } - }, awaitReply); + }, {}, mode); } - void run(std::invocable auto &&f, bool awaitReply = false) + template + void run(std::invocable auto &&f, ExtraData &&extData, MessageReplyMode mode = MessageReplyMode::none) { + std::span extBuff; + if constexpr(!std::is_null_pointer_v) + { + extBuff = {reinterpret_cast(&extData), sizeof(extData)}; + } runFunc( - [=](GLDisplay glDpy, std::binary_semaphore *semPtr) + [=](GLDisplay glDpy, std::binary_semaphore *semPtr, CommandMessages &msgs) { bool semaphoreNeedsNotify = semPtr; - TaskContext ctx{glDpy, semPtr, &semaphoreNeedsNotify}; + TaskContext ctx{glDpy, semPtr, &semaphoreNeedsNotify, &msgs}; f(ctx); if(semaphoreNeedsNotify) // semaphore wasn't already notified in the delegate { semPtr->release(); } - }, awaitReply); + }, extBuff, mode); + } + + void run(std::invocable auto &&f, MessageReplyMode mode = MessageReplyMode::none) + { + run(IG_forward(f), nullptr, mode); } - void runSync(auto &&f) { run(IG_forward(f), true); } + void runSync(auto &&f) { run(IG_forward(f), MessageReplyMode::wait); } protected: std::thread thread{}; GLContext context{}; GLBufferConfig bufferConfig{}; OnExit onExit; - MessagePort commandPort{MessagePort::NullInit{}}; + CommandMessagePort commandPort{CommandMessagePort::NullInit{}}; ThreadId threadId_{}; GLContext makeGLContext(GLManager &, GLBufferConfig bufferConf); diff --git a/imagine/include/imagine/gui/AlertView.hh b/imagine/include/imagine/gui/AlertView.hh index 1e2c402fc..dd340d2d1 100644 --- a/imagine/include/imagine/gui/AlertView.hh +++ b/imagine/include/imagine/gui/AlertView.hh @@ -32,7 +32,7 @@ public: BaseAlertView(ViewAttachParams attach, UTF16Convertible auto &&label, TableView::ItemsDelegate items, TableView::ItemDelegate item): View{attach}, bgQuads{attach.rendererTask, {.size = 2}}, - text{IG_forward(label), &defaultFace()}, + text{attach.rendererTask, IG_forward(label), &defaultFace()}, menu { attach, @@ -69,14 +69,9 @@ class AlertView : public BaseAlertView { public: AlertView(ViewAttachParams attach, UTF16Convertible auto &&label, size_t menuItems): - BaseAlertView{attach, IG_forward(label), item}, - item{menuItems} {} - - void setItem(size_t idx, UTF16Convertible auto &&name, TextMenuItem::SelectDelegate del) + BaseAlertView{attach, IG_forward(label), item} { - assert(idx < item.size()); - item[idx].setName(IG_forward(name), &defaultFace()); - item[idx].onSelect = del; + item.reserve(menuItems); } protected: @@ -98,8 +93,8 @@ public: BaseAlertView(attach, IG_forward(label), [](const TableView &) -> size_t { return 2; }, [this](const TableView &, size_t idx) -> MenuItem& { return idx == 0 ? yes : no; }), - yes{IG_forward(yesStr), &defaultFace(), delegates.onYes}, - no{IG_forward(noStr), &defaultFace(), delegates.onNo} {} + yes{IG_forward(yesStr), attach, delegates.onYes}, + no{IG_forward(noStr), attach,delegates.onNo} {} YesNoAlertView(ViewAttachParams attach, UTF16Convertible auto &&label, Delegates delegates): YesNoAlertView{attach, IG_forward(label), u"Yes", u"No", delegates} {} diff --git a/imagine/include/imagine/gui/FSPicker.hh b/imagine/include/imagine/gui/FSPicker.hh index 2c38f4973..76d823637 100644 --- a/imagine/include/imagine/gui/FSPicker.hh +++ b/imagine/include/imagine/gui/FSPicker.hh @@ -76,9 +76,11 @@ protected: { static constexpr auto isDirFlag = bit(0); - std::string path{}; - TextMenuItem text{}; + std::string path; + TextMenuItem text; + FileEntry(ViewAttachParams attach, auto &&path, UTF16Convertible auto &&name): + path{IG_forward(path)}, text{IG_forward(name), attach} {} bool isDir() const { return text.flags.user & isDirFlag; } }; diff --git a/imagine/include/imagine/gui/MenuItem.hh b/imagine/include/imagine/gui/MenuItem.hh index 95a8e22e5..86d840da1 100644 --- a/imagine/include/imagine/gui/MenuItem.hh +++ b/imagine/include/imagine/gui/MenuItem.hh @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -114,24 +115,43 @@ struct MenuItemFlags user:4{}; }; +struct MenuId +{ + using Type = int32_t; + Type val{}; + + constexpr MenuId() = default; + constexpr MenuId(auto &&i):val{static_cast(i)} {} + constexpr operator Type() const { return val; } +}; + +constexpr MenuId defaultMenuId{std::numeric_limits::min()}; + class MenuItem { public: - using IdInt = int32_t; - enum Id : IdInt{}; + struct Config + { + Gfx::GlyphTextureSet *face{}; + MenuId id{}; + }; - static constexpr Id DEFAULT_ID = static_cast(std::numeric_limits::min()); MenuItemFlags flags{.selectable = true, .active = true}; + MenuId id{}; + + MenuItem() = default; - constexpr MenuItem() = default; - MenuItem(UTF16Convertible auto &&name, Gfx::GlyphTextureSet *face, IdInt id = {}): - id_{id}, - t{IG_forward(name), face} {} + MenuItem(UTF16Convertible auto &&name, ViewAttachParams attach, Config conf): + id{conf.id}, + t{attach.rendererTask, IG_forward(name), conf.face ?: &attach.viewManager.defaultFace} {} + + MenuItem(MenuItem &&) = default; + MenuItem &operator=(MenuItem &&) = default; virtual ~MenuItem() = default; - virtual void prepareDraw(Gfx::Renderer &r); + virtual void prepareDraw(); virtual void draw(Gfx::RendererCommands &__restrict__, int xPos, int yPos, int xSize, int ySize, int xIndent, _2DOrigin align, Gfx::Color) const; - virtual void compile(Gfx::Renderer &r); + virtual void compile(); int ySize() const; int xSize() const; virtual bool select(View &, const Input::Event &) = 0; @@ -141,13 +161,11 @@ public: constexpr void setActive(bool on) { flags.active = on; } constexpr bool highlighted() const { return flags.highlight; } constexpr void setHighlighted(bool on) { flags.highlight = on; } - constexpr Id id() const { return (Id)id_; } - constexpr void setId(IdInt id) { id_ = id; } - void compile(UTF16Convertible auto &&name, Gfx::Renderer &r) + void compile(UTF16Convertible auto &&name) { t.resetString(IG_forward(name)); - compile(r); + compile(); } void setName(UTF16Convertible auto &&name, Gfx::GlyphTextureSet *face = nullptr) @@ -157,10 +175,11 @@ public: t.setFace(face); } + static constexpr Config toBaseConfig(auto &&conf) { return {.face = conf.face, .id = conf.id}; } + const Gfx::Text &text() const; protected: - IdInt id_{}; Gfx::Text t; }; @@ -171,14 +190,14 @@ public: SelectDelegate onSelect; - constexpr TextMenuItem() = default; + TextMenuItem() = default; - TextMenuItem(UTF16Convertible auto &&name, Gfx::GlyphTextureSet *face, SelectDelegate onSelect, IdInt id = {}): - MenuItem{IG_forward(name), face, id}, + TextMenuItem(UTF16Convertible auto &&name, ViewAttachParams attach, SelectDelegate onSelect = {}, Config conf = Config{}): + MenuItem{IG_forward(name), attach, conf}, onSelect{onSelect} {} - TextMenuItem(UTF16Convertible auto &&name, Gfx::GlyphTextureSet *face, IdInt id): - MenuItem{IG_forward(name), face, id} {} + TextMenuItem(UTF16Convertible auto &&name, ViewAttachParams attach, Config conf): + MenuItem{IG_forward(name), attach, conf} {} bool select(View &parent, const Input::Event &e) override { return onSelect.callCopySafe(*this, parent, e); } }; @@ -186,10 +205,12 @@ public: class TextHeadingMenuItem : public MenuItem { public: - constexpr TextHeadingMenuItem() = default; + static constexpr Config applyBoldFont(ViewAttachParams attach, Config conf) { conf.face = &attach.viewManager.defaultBoldFace; return conf; } - TextHeadingMenuItem(UTF16Convertible auto &&name, Gfx::GlyphTextureSet *face, IdInt id = {}): - MenuItem{IG_forward(name), face, id} + TextHeadingMenuItem() = default; + + TextHeadingMenuItem(UTF16Convertible auto &&name, ViewAttachParams attach, Config conf = Config{}): + MenuItem{IG_forward(name), attach, conf.face ? conf : applyBoldFont(attach, conf)} { setSelectable(false); } @@ -200,17 +221,17 @@ public: class BaseDualTextMenuItem : public MenuItem { public: - constexpr BaseDualTextMenuItem() = default; + BaseDualTextMenuItem() = default; - BaseDualTextMenuItem(UTF16Convertible auto &&name, UTF16Convertible auto &&name2, Gfx::GlyphTextureSet *face, IdInt id = {}): - MenuItem{IG_forward(name), face, id}, - t2{IG_forward(name2), face} {} + BaseDualTextMenuItem(UTF16Convertible auto &&name, UTF16Convertible auto &&name2, ViewAttachParams attach, Config conf = Config{}): + MenuItem{IG_forward(name), attach, conf}, + t2{attach.rendererTask, IG_forward(name2), t.face()} {} void set2ndName(UTF16Convertible auto &&name) { t2.resetString(IG_forward(name)); } void set2ndName() { t2.resetString(); } - void compile(Gfx::Renderer &r) override; - void compile2nd(Gfx::Renderer &r); - void prepareDraw(Gfx::Renderer &r) override; + void compile() override; + void compile2nd(); + void prepareDraw() override; void draw2ndText(Gfx::RendererCommands &, int xPos, int yPos, int xSize, int ySize, int xIndent, _2DOrigin align, Gfx::Color) const; void draw(Gfx::RendererCommands &__restrict__, int xPos, int yPos, int xSize, int ySize, @@ -228,11 +249,11 @@ public: SelectDelegate onSelect; Gfx::Color text2Color; - constexpr DualTextMenuItem() = default; + DualTextMenuItem() = default; - DualTextMenuItem(UTF16Convertible auto &&name, UTF16Convertible auto &&name2, Gfx::GlyphTextureSet *face, - SelectDelegate onSelect = {}, IdInt id = {}): - BaseDualTextMenuItem{IG_forward(name), IG_forward(name2), face, id}, + DualTextMenuItem(UTF16Convertible auto &&name, UTF16Convertible auto &&name2, ViewAttachParams attach, + SelectDelegate onSelect, Config conf = Config{}): + BaseDualTextMenuItem{IG_forward(name), IG_forward(name2), attach, conf}, onSelect{onSelect} {} void draw(Gfx::RendererCommands &__restrict__, int xPos, int yPos, int xSize, int ySize, @@ -250,10 +271,11 @@ public: SelectDelegate onSelect; - constexpr BoolMenuItem() = default; + BoolMenuItem() = default; - BoolMenuItem(UTF16Convertible auto &&name, Gfx::GlyphTextureSet *face, bool val, SelectDelegate onSelect, IdInt id = {}): - BaseDualTextMenuItem{IG_forward(name), val ? u"On" : u"Off", face, id}, + BoolMenuItem(UTF16Convertible auto &&name, ViewAttachParams attach, bool val, + SelectDelegate onSelect, Config conf = Config{}): + BaseDualTextMenuItem{IG_forward(name), val ? u"On" : u"Off", attach, conf}, onSelect{onSelect} { if(val) @@ -261,9 +283,9 @@ public: flags.impl |= onOffStyleFlag; } - BoolMenuItem(UTF16Convertible auto &&name, Gfx::GlyphTextureSet *face, bool val, - UTF16Convertible auto &&offStr, UTF16Convertible auto &&onStr, SelectDelegate onSelect, IdInt id = {}): - BaseDualTextMenuItem{IG_forward(name), val ? onStr : offStr, face, id}, + BoolMenuItem(UTF16Convertible auto &&name, ViewAttachParams attach, bool val, + UTF16Convertible auto &&offStr, UTF16Convertible auto &&onStr, SelectDelegate onSelect, Config conf = Config{}): + BaseDualTextMenuItem{IG_forward(name), val ? onStr : offStr, attach, conf}, onSelect{onSelect}, offStr{IG_forward(offStr)}, onStr{IG_forward(onStr)} @@ -299,26 +321,30 @@ public: bool isId{}; constexpr SelectedInit(int i): val{i} {} - constexpr SelectedInit(Id i): val{i}, isId{true} {} + constexpr SelectedInit(MenuId i): val{i.val}, isId{true} {} }; - struct Delegates + struct Config { + Gfx::GlyphTextureSet *face{}; + MenuId id{}; SetDisplayStringDelegate onSetDisplayString{}; SelectDelegate onSelect{}; TextMenuItem::SelectDelegate defaultItemOnSelect{}; + + static Config defaultConfig() { return {}; } }; SelectDelegate onSelect; - constexpr MultiChoiceMenuItem() = default; + MultiChoiceMenuItem() = default; - MultiChoiceMenuItem(UTF16Convertible auto &&name, Gfx::GlyphTextureSet *face, Delegates delegates, - SelectedInit selected, ItemsDelegate items, ItemDelegate item, IdInt id = {}): - BaseDualTextMenuItem{IG_forward(name), UTF16String{}, face, id}, + MultiChoiceMenuItem(UTF16Convertible auto &&name, ViewAttachParams attach, + SelectedInit selected, ItemsDelegate items, ItemDelegate item, Config conf = Config::defaultConfig()): + BaseDualTextMenuItem{IG_forward(name), UTF16String{}, attach, toBaseConfig(conf)}, onSelect { - delegates.onSelect ? delegates.onSelect : + conf.onSelect ? conf.onSelect : [this](MultiChoiceMenuItem &item, View &view, const Input::Event &e) { item.defaultOnSelect(view, e); @@ -326,50 +352,43 @@ public: }, items_{items}, item_{item}, - onSetDisplayString{delegates.onSetDisplayString}, - selected_{selected.isId ? idxOfId((Id)selected.val) : selected.val} {} - - MultiChoiceMenuItem(UTF16Convertible auto &&name, Gfx::GlyphTextureSet *face, - SelectedInit selected, ItemsDelegate items, ItemDelegate item, IdInt id = {}): - MultiChoiceMenuItem{IG_forward(name), face, {}, selected, items, item, id} {} - - MultiChoiceMenuItem(UTF16Convertible auto &&name, Gfx::GlyphTextureSet *face, Delegates delegates, - SelectedInit selected, Container auto &&item, IdInt id = {}): - MultiChoiceMenuItem{IG_forward(name), face, delegates, selected, - itemsDelegate(IG_forward(item)), - itemDelegate(IG_forward(item)), - id} + onSetDisplayString{conf.onSetDisplayString}, + selected_{selected.isId ? idxOfId(MenuId{selected.val}) : selected.val} {} + + MultiChoiceMenuItem(UTF16Convertible auto &&name, ViewAttachParams attach, + SelectedInit selected, Container auto &&item, Config conf = Config::defaultConfig()): + MultiChoiceMenuItem + { + IG_forward(name), attach, selected, + itemsDelegate(IG_forward(item)), itemDelegate(IG_forward(item)), conf + } { - if(delegates.defaultItemOnSelect) + if(conf.defaultItemOnSelect) { for(auto &i : item) { if(!i.onSelect) - i.onSelect = delegates.defaultItemOnSelect; + i.onSelect = conf.defaultItemOnSelect; } } } - MultiChoiceMenuItem(UTF16Convertible auto &&name, Gfx::GlyphTextureSet *face, - SelectedInit selected, Container auto &&item, IdInt id = {}): - MultiChoiceMenuItem{IG_forward(name), face, {}, selected, IG_forward(item), id} {} - void draw(Gfx::RendererCommands &__restrict__, int xPos, int yPos, int xSize, int ySize, int xIndent, _2DOrigin align, Gfx::Color) const override; - void compile(Gfx::Renderer &r) override; + void compile() override; int selected() const; size_t items() const; bool setSelected(int idx, View &view); bool setSelected(int idx); - bool setSelected(Id, View &view); - bool setSelected(Id); + bool setSelected(MenuId, View &view); + bool setSelected(MenuId); int cycleSelected(int offset, View &view); int cycleSelected(int offset); bool select(View &, const Input::Event &) override; std::unique_ptr makeTableView(ViewAttachParams attach); void defaultOnSelect(View &, const Input::Event &); void updateDisplayString(); - int idxOfId(IdInt); + int idxOfId(MenuId); protected: ItemsDelegate items_; diff --git a/imagine/include/imagine/gui/NavView.hh b/imagine/include/imagine/gui/NavView.hh index ae5b155d6..a004a4677 100644 --- a/imagine/include/imagine/gui/NavView.hh +++ b/imagine/include/imagine/gui/NavView.hh @@ -58,7 +58,7 @@ protected: static constexpr int controls = 3; std::array control{}; int selected = -1; - Gfx::Text text{}; + Gfx::Text text; bool selectNextLeftButton(); bool selectNextRightButton(); @@ -80,7 +80,7 @@ public: protected: DynArray gradientStops; Gfx::IQuads selectQuad; - Gfx::VertexBuffer bgVerts; + Gfx::ObjectVertexArray bgVerts; Gfx::ITexQuads buttonQuads; Gfx::TextureSpan leftTex, rightTex; bool centerTitle = true; diff --git a/imagine/include/imagine/gui/TextEntry.hh b/imagine/include/imagine/gui/TextEntry.hh index 308b82bc4..7e7bebb2f 100644 --- a/imagine/include/imagine/gui/TextEntry.hh +++ b/imagine/include/imagine/gui/TextEntry.hh @@ -31,7 +31,7 @@ class TextEntry public: Gfx::IQuads bgQuads; - TextEntry(const char *initText, Gfx::Renderer &r, Gfx::GlyphTextureSet *face); + TextEntry(const char *initText, ViewAttachParams, Gfx::GlyphTextureSet *face); void setAcceptingInput(bool on); bool isAcceptingInput() const; bool inputEvent(View &parentView, const Input::Event &); @@ -69,9 +69,9 @@ public: protected: struct CancelButton { - WRect bounds; + WRect bounds{}; Gfx::ITexQuads quad; - Gfx::TextureSpan texture; + Gfx::TextureSpan texture{}; }; // TODO: cancel button doesn't work yet due to popup window not forwarding touch events to main window IG_UseMemberIf(!Config::envIsAndroid, CancelButton, cancelButton); diff --git a/imagine/include/imagine/gui/TextTableView.hh b/imagine/include/imagine/gui/TextTableView.hh index 8115d781f..a046121fe 100644 --- a/imagine/include/imagine/gui/TextTableView.hh +++ b/imagine/include/imagine/gui/TextTableView.hh @@ -37,23 +37,22 @@ public: TextMenuItem &appendItem(UTF16Convertible auto &&name, TextMenuItem::SelectDelegate del) { - return textItem.emplace_back(IG_forward(name), &defaultFace(), del); + return textItem.emplace_back(IG_forward(name), attachParams(), del); } TextMenuItem &setItem(size_t idx, UTF16Convertible auto &&name, TextMenuItem::SelectDelegate del) { assert(idx < textItem.size()); - textItem[idx] = {IG_forward(name), &defaultFace(), del}; + textItem[idx] = {IG_forward(name), attachParams(), del}; return textItem[idx]; } TextMenuItem &item(size_t idx); - void setItems(size_t items); void onAddedToController(ViewController *, const Input::Event &) override; void drawElement(Gfx::RendererCommands &__restrict__ cmds, size_t i, MenuItem &item, WRect rect, int xIndent) const override; protected: - std::vector textItem{}; + std::vector textItem; int activeItem = -1; }; diff --git a/imagine/include/imagine/gui/ToastView.hh b/imagine/include/imagine/gui/ToastView.hh index 3d1e7a51b..8ca7d6f8c 100644 --- a/imagine/include/imagine/gui/ToastView.hh +++ b/imagine/include/imagine/gui/ToastView.hh @@ -28,7 +28,6 @@ namespace IG class ToastView : public View { public: - ToastView() = default; ToastView(ViewAttachParams attach); void setFace(Gfx::GlyphTextureSet &face); void clear(); @@ -49,7 +48,7 @@ public: bool inputEvent(const Input::Event &) final; private: - Gfx::Text text{}; + Gfx::Text text; Timer unpostTimer{Timer::NullInit{}}; Gfx::IQuads msgFrameQuads; WRect msgFrame{}; diff --git a/imagine/include/imagine/gui/View.hh b/imagine/include/imagine/gui/View.hh index 4f58858bb..82fa4308d 100644 --- a/imagine/include/imagine/gui/View.hh +++ b/imagine/include/imagine/gui/View.hh @@ -104,7 +104,6 @@ public: ApplicationContext appContext() const; template T &applicationAs() const { return appContext().applicationAs(); } static std::u16string nameString(const MenuItem &item); - Gfx::QuadIndexArray &quadIndices(); Gfx::GlyphTextureSet &defaultFace(); Gfx::GlyphTextureSet &defaultBoldFace(); static Gfx::Color menuTextColor(bool isSelected); @@ -126,7 +125,6 @@ public: WindowRect displayInsetRect(Direction) const; static WindowRect displayInsetRect(Direction, WindowRect viewRect, WindowRect displayRect); bool pointIsInView(WPt pos); - void waitForDrawFinished(); template std::unique_ptr makeView(auto &&...args) diff --git a/imagine/include/imagine/gui/ViewManager.hh b/imagine/include/imagine/gui/ViewManager.hh index 69b6002ec..e74019d78 100644 --- a/imagine/include/imagine/gui/ViewManager.hh +++ b/imagine/include/imagine/gui/ViewManager.hh @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -40,7 +39,6 @@ public: static constexpr bool needsBackControlDefault = ViewDefs::needsBackControlDefault; static constexpr bool needsBackControlIsMutable = ViewDefs::needsBackControlIsMutable; - Gfx::QuadIndexArray quadIndices; Gfx::GlyphTextureSet defaultFace; Gfx::GlyphTextureSet defaultBoldFace; int tableXIndentPx{}; diff --git a/imagine/include/imagine/gui/ViewStack.hh b/imagine/include/imagine/gui/ViewStack.hh index ee4ede0a5..603153ae4 100644 --- a/imagine/include/imagine/gui/ViewStack.hh +++ b/imagine/include/imagine/gui/ViewStack.hh @@ -93,9 +93,7 @@ public: protected: struct ViewEntry { - ViewEntry(std::unique_ptr v, bool needsNavView): - v{std::move(v)}, needsNavView{needsNavView} {} - std::unique_ptr v; + std::unique_ptr ptr; bool needsNavView{}; bool isModal{}; }; diff --git a/imagine/include/imagine/io/IO.hh b/imagine/include/imagine/io/IO.hh index 21362da4f..9be690136 100644 --- a/imagine/include/imagine/io/IO.hh +++ b/imagine/include/imagine/io/IO.hh @@ -66,6 +66,7 @@ public: explicit operator bool() const; // optional API + ssize_t writeVector(std::span buffs, std::optional offset = {}); bool truncate(off_t offset); std::span map(); void sync(); diff --git a/imagine/include/imagine/io/PosixIO.hh b/imagine/include/imagine/io/PosixIO.hh index c53b98f6c..e17ca6197 100644 --- a/imagine/include/imagine/io/PosixIO.hh +++ b/imagine/include/imagine/io/PosixIO.hh @@ -49,6 +49,7 @@ public: int fd() const; ssize_t read(void *buff, size_t bytes, std::optional offset = {}); ssize_t write(const void *buff, size_t bytes, std::optional offset = {}); + ssize_t writeVector(std::span buffs, std::optional offset = {}); bool truncate(off_t offset); off_t seek(off_t offset, SeekMode mode); void sync(); diff --git a/imagine/include/imagine/io/ioDefs.hh b/imagine/include/imagine/io/ioDefs.hh index 3199b5669..30bf0d639 100644 --- a/imagine/include/imagine/io/ioDefs.hh +++ b/imagine/include/imagine/io/ioDefs.hh @@ -16,7 +16,9 @@ along with Imagine. If not, see */ #include // for SEEK_* +#include #include +#include namespace IG { @@ -81,7 +83,7 @@ concept Readable = template concept Writable = - requires(T &i, void *buff, size_t bytes) + requires(T &i, const void *buff, size_t bytes) { i.write(buff, bytes); }; @@ -93,7 +95,24 @@ concept Seekable = i.seek(offset, mode); }; +struct OutVector +{ + // should map exactly to iovec in + const void *dataPtr{}; + size_t bytes{}; + + constexpr OutVector() = default; + template + constexpr OutVector(std::span buff): + dataPtr{static_cast(buff.data())}, + bytes{buff.size_bytes()} {} + constexpr auto *data() const { return static_cast(dataPtr); } + constexpr size_t size() const { return bytes; } + auto iovecPtr() const { return reinterpret_cast(this); } +}; + class AssetIO; class FileIO; +class MapIO; } diff --git a/imagine/include/imagine/util/2DOrigin.h b/imagine/include/imagine/util/2DOrigin.h index 9c3d69c46..f59865e01 100644 --- a/imagine/include/imagine/util/2DOrigin.h +++ b/imagine/include/imagine/util/2DOrigin.h @@ -16,7 +16,7 @@ along with Imagine. If not, see */ #include -#include +#include #include #include #include diff --git a/imagine/include/imagine/util/math.hh b/imagine/include/imagine/util/math.hh new file mode 100644 index 000000000..ca43fe571 --- /dev/null +++ b/imagine/include/imagine/util/math.hh @@ -0,0 +1,233 @@ +#pragma once + +/* This file is part of Imagine. + + Imagine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Imagine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Imagine. If not, see */ + +#include +#include +#include +#include +#include + +namespace IG +{ + +template +constexpr auto radians(T degrees) +{ + return degrees * static_cast(std::numbers::pi / 180.0); +} + +template +constexpr auto degrees(T radians) +{ + return radians * static_cast(180.0 / std::numbers::pi); +} + +constexpr auto pow2(auto base) +{ + return base * base; +} + +// ceil/floor/round "n" to the nearest multiple "mult" +constexpr auto ceilMult(std::floating_point auto n, std::floating_point auto mult) +{ + return std::ceil(n / mult) * mult; +} + +constexpr auto floorMult(std::floating_point auto n, std::floating_point auto mult) +{ + return std::floor(n / mult) * mult; +} + +constexpr auto roundMult(std::floating_point auto n, std::floating_point auto mult) +{ + return std::round(n / mult) * mult; +} + +constexpr bool isInRange(auto val, auto min, auto max) +{ + return val >= min && val <= max; +} + +// treat zeros as positive +constexpr auto sign(auto num) +{ + return static_cast(num >= 0 ? 1 : -1); +} + +constexpr auto wrapMax(auto x, auto max) +{ + if constexpr(std::is_floating_point_v) + { + return std::fmod(max + std::fmod(x, max), max); + } + else + { + return (max + (x % max)) % max; + } +} + +constexpr auto wrapMinMax(auto x, auto min, auto max) +{ + return min + wrapMax(x - min, max - min); +} + +constexpr auto roundUpPowOf2(std::unsigned_integral auto x) +{ + return 1 << fls(x - 1); +} + +constexpr auto roundDownPowOf2(std::unsigned_integral auto x) +{ + return 1 << (fls(x) - 1); +} + +constexpr auto pow(std::integral auto base, std::integral auto exp) +{ + decltype(base) result = 1; + while(exp) + { + if(exp & 1) // exp % 2 == 1 + { + result *= base; + } + exp >>= 1; // exp /= 2 + base *= base; + } + return result; +} + +constexpr bool isEven(std::integral auto x) +{ + return x % 2 == 0; +} + +constexpr bool isOdd(std::integral auto x) +{ + return !isEven(x); +} + +constexpr auto makeEvenRoundedUp(std::integral auto x) +{ + return isEven(x) ? x : x+1; +} + +constexpr auto makeEvenRoundedDown(std::integral auto x) +{ + return isEven(x) ? x : x-1; +} + +constexpr bool isPowerOf2(std::integral auto x) +{ + return x && !( (x-1) & x ); + // return ((x != 0) && ((x & (~x + 1)) == x)); // alternate method +} + +constexpr auto alignRoundedUp(std::unsigned_integral auto addr, unsigned int align) +{ + assumeExpr(isPowerOf2(align)); + return (addr+(align-1)) & ~(align-1); +} + +// divide integer rounding-upwards +constexpr auto divRoundUp(std::integral auto x, std::integral auto y) +{ + return (x + (y - 1)) / y; +} + +// divide rounding to closest integer +constexpr auto divRoundClosestPositive(std::integral auto x, std::integral auto y) +{ + return (x + (y / 2)) / y; +} + +constexpr auto divRoundClosestNegative(std::integral auto x, std::integral auto y) +{ + return (x - (y / 2)) / y; +} + +constexpr auto divRoundClosest(std::integral auto x, std::integral auto y) +{ + return (x >= 0) ? divRoundClosestPositive(x, y) : divRoundClosestNegative(x, y); +} + +constexpr auto divRoundClosest(std::floating_point auto x, std::floating_point auto y) +{ + return std::round(x / y); +} + +template +constexpr T distance3D(T x1, T y1, T z1, T x2, T y2, T z2) +{ + return std::sqrt(pow2(x1 - x2) + pow2(y1 - y2) + pow2(z1 - z2)); +} + +template +constexpr void adjust2DSizeToFit(T &xBound, T &yBound, T aR) +{ + T boundAR = xBound / yBound; + T xSize = aR >= boundAR ? xBound : yBound * aR; + T ySize = aR >= boundAR ? xBound / aR : yBound; + xBound = xSize; + yBound = ySize; +} + +template +constexpr void setSizesWithRatioY(T &xSize, T &ySize, T2 aspectRatio, T y) +{ + ySize = y; + if(aspectRatio) // treat 0 AR as a no-op, xSize doesn't get modified + { + T2 res = (T2)y * aspectRatio; + xSize = std::is_integral_v ? std::round(res) : res; + } +} + +template +constexpr void setSizesWithRatioX(T &xSize, T &ySize, T2 aspectRatio, T x) +{ + xSize = x; + if(aspectRatio) // treat 0 AR as a no-op, ySize doesn't get modified + { + T2 res = (T2)x / aspectRatio; + ySize = std::is_integral_v ? std::round(res) : res; + } +} + +template +constexpr bool valIsWithinStretch(T val, T val2, T stretch) +{ + return val + stretch >= val2 && val - stretch <= val2; +} + +template +constexpr void rotateAboutPoint(T rads, T &x, T &y, T ox, T oy) +{ + T oldX = x, oldY = y; + x = std::cos(rads) * (oldX-ox) - std::sin(rads) * (oldY-oy) + ox; + y = std::sin(rads) * (oldX-ox) + std::cos(rads) * (oldY-oy) + oy; +} + +// to rotate about z axis, pass x,y +// to rotate about x axis, pass y,z +// to rotate about y axis, pass z,x +template +constexpr void rotateAboutAxis(T rads, T &x, T &y) +{ + rotateAboutPoint(rads, x, y, (T)0, (T)0); +} + +} diff --git a/imagine/include/imagine/util/math/Point2D.hh b/imagine/include/imagine/util/math/Point2D.hh index 9f03d94c8..24b752574 100644 --- a/imagine/include/imagine/util/math/Point2D.hh +++ b/imagine/include/imagine/util/math/Point2D.hh @@ -17,7 +17,7 @@ #include #include -#include +#include namespace IG { diff --git a/imagine/include/imagine/util/math/fast.hh b/imagine/include/imagine/util/math/fast.hh deleted file mode 100644 index 57c56965d..000000000 --- a/imagine/include/imagine/util/math/fast.hh +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -/* This file is part of Imagine. - - Imagine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Imagine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Imagine. If not, see */ - -#include - -namespace IG -{ - -template -static T sqrtFast(T remainder) -{ - if constexpr(std::is_same_v) - { - // Method using Log Base 2 Approximation With One Extra Babylonian Steps - // http://ilab.usc.edu/wiki/index.php/Fast_Square_Root - - union - { - int i; - float x; - } u; - u.x = x; - u.i = (1<<29) + (u.i >> 1) - (1<<22); - - // One Babylonian Step - u.x = 0.5f * (u.x + x/u.x); - - return u.x; - } - else if constexpr(std::is_unsigned_v) - { - T place = (T)1 << (sizeof(T) * 8 - 2); // calculated by precompiler = same runtime as: place = 0x40000000 - while (place > remainder) - place /= 4; // optimized by complier as place >>= 2 - - T root = 0; - while (place) - { - if (remainder >= root+place) - { - remainder -= root+place; - root += place * 2; - } - root /= 2; - place /= 4; - } - return root; - } - else - { - // error - } -} - -} diff --git a/imagine/include/imagine/util/math/int.hh b/imagine/include/imagine/util/math/int.hh deleted file mode 100644 index e281563da..000000000 --- a/imagine/include/imagine/util/math/int.hh +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -/* This file is part of Imagine. - - Imagine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Imagine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Imagine. If not, see */ - -#include -#include -#include -#include - -namespace IG -{ - -constexpr auto roundUpPowOf2(std::unsigned_integral auto x) -{ - return 1 << fls(x - 1); -} - -constexpr auto roundDownPowOf2(std::unsigned_integral auto x) -{ - return 1 << (fls(x) - 1); -} - -constexpr auto pow(std::integral auto base, std::integral auto exp) -{ - decltype(base) result = 1; - while(exp) - { - if(exp & 1) // exp % 2 == 1 - { - result *= base; - } - exp >>= 1; // exp /= 2 - base *= base; - } - return result; -} - -constexpr bool isEven(std::integral auto x) -{ - return x % 2 == 0; -} - -constexpr bool isOdd(std::integral auto x) -{ - return !isEven(x); -} - -constexpr auto makeEvenRoundedUp(std::integral auto x) -{ - return isEven(x) ? x : x+1; -} - -constexpr auto makeEvenRoundedDown(std::integral auto x) -{ - return isEven(x) ? x : x-1; -} - -constexpr bool isPowerOf2(std::integral auto x) -{ - return x && !( (x-1) & x ); - // return ((x != 0) && ((x & (~x + 1)) == x)); // alternate method -} - -constexpr auto alignRoundedUp(std::unsigned_integral auto addr, unsigned int align) -{ - assumeExpr(isPowerOf2(align)); - return (addr+(align-1)) & ~(align-1); -} - -// divide integer rounding-upwards -constexpr auto divRoundUp(std::integral auto x, std::integral auto y) -{ - return (x + (y - 1)) / y; -} - -// divide rounding to closest integer -constexpr auto divRoundClosestPositive(std::integral auto x, std::integral auto y) -{ - return (x + (y / 2)) / y; -} - -constexpr auto divRoundClosestNegative(std::integral auto x, std::integral auto y) -{ - return (x - (y / 2)) / y; -} - -constexpr auto divRoundClosest(std::integral auto x, std::integral auto y) -{ - return (x >= 0) ? divRoundClosestPositive(x, y) : divRoundClosestNegative(x, y); -} - -constexpr auto divRoundClosest(std::floating_point auto x, std::floating_point auto y) -{ - return std::round(x / y); -} - -} diff --git a/imagine/include/imagine/util/math/math.hh b/imagine/include/imagine/util/math/math.hh deleted file mode 100644 index 69f5c1be8..000000000 --- a/imagine/include/imagine/util/math/math.hh +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -/* This file is part of Imagine. - - Imagine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Imagine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Imagine. If not, see */ - -#include -#include -#include - -namespace IG -{ - -template -constexpr auto radians(T degrees) -{ - return degrees * static_cast(std::numbers::pi / 180.0); -} - -template -constexpr auto degrees(T radians) -{ - return radians * static_cast(180.0 / std::numbers::pi); -} - -constexpr auto pow2(auto base) -{ - return base * base; -} - -// ceil/floor/round "n" to the nearest multiple "mult" -constexpr auto ceilMult(std::floating_point auto n, std::floating_point auto mult) -{ - return std::ceil(n / mult) * mult; -} - -constexpr auto floorMult(std::floating_point auto n, std::floating_point auto mult) -{ - return std::floor(n / mult) * mult; -} - -constexpr auto roundMult(std::floating_point auto n, std::floating_point auto mult) -{ - return std::round(n / mult) * mult; -} - -constexpr bool isInRange(auto val, auto min, auto max) -{ - return val >= min && val <= max; -} - -// treat zeros as positive -constexpr auto sign(auto num) -{ - return static_cast(num >= 0 ? 1 : -1); -} - -constexpr auto wrapMax(auto x, auto max) -{ - if constexpr(std::is_floating_point_v) - { - return std::fmod(max + std::fmod(x, max), max); - } - else - { - return (max + (x % max)) % max; - } -} - -constexpr auto wrapMinMax(auto x, auto min, auto max) -{ - return min + wrapMax(x - min, max - min); -} - -} diff --git a/imagine/include/imagine/util/math/space.hh b/imagine/include/imagine/util/math/space.hh deleted file mode 100755 index 1af982720..000000000 --- a/imagine/include/imagine/util/math/space.hh +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -/* This file is part of Imagine. - - Imagine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Imagine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Imagine. If not, see */ - -#include - -namespace IG -{ - -template -constexpr T distance3D(T x1, T y1, T z1, T x2, T y2, T z2) -{ - return std::sqrt(pow2(x1 - x2) + pow2(y1 - y2) + pow2(z1 - z2)); -} - -template -constexpr void adjust2DSizeToFit(T &xBound, T &yBound, T aR) -{ - T boundAR = xBound / yBound; - T xSize = aR >= boundAR ? xBound : yBound * aR; - T ySize = aR >= boundAR ? xBound / aR : yBound; - xBound = xSize; - yBound = ySize; -} - -template -constexpr void setSizesWithRatioY(T &xSize, T &ySize, T2 aspectRatio, T y) -{ - ySize = y; - if(aspectRatio) // treat 0 AR as a no-op, xSize doesn't get modified - { - T2 res = (T2)y * aspectRatio; - xSize = std::is_integral_v ? std::round(res) : res; - } -} - -template -constexpr void setSizesWithRatioX(T &xSize, T &ySize, T2 aspectRatio, T x) -{ - xSize = x; - if(aspectRatio) // treat 0 AR as a no-op, ySize doesn't get modified - { - T2 res = (T2)x / aspectRatio; - ySize = std::is_integral_v ? std::round(res) : res; - } -} - -template -constexpr bool valIsWithinStretch(T val, T val2, T stretch) -{ - return val + stretch >= val2 && val - stretch <= val2; -} - -template -constexpr void rotateAboutPoint(T rads, T &x, T &y, T ox, T oy) -{ - T oldX = x, oldY = y; - x = std::cos(rads) * (oldX-ox) - std::sin(rads) * (oldY-oy) + ox; - y = std::sin(rads) * (oldX-ox) + std::cos(rads) * (oldY-oy) + oy; -} - -// to rotate about z axis, pass x,y -// to rotate about x axis, pass y,z -// to rotate about y axis, pass z,x -template -constexpr void rotateAboutAxis(T rads, T &x, T &y) -{ - rotateAboutPoint(rads, x, y, (T)0, (T)0); -} - -} diff --git a/imagine/include/imagine/util/ranges.hh b/imagine/include/imagine/util/ranges.hh index 70d6d3f19..14d398ea6 100644 --- a/imagine/include/imagine/util/ranges.hh +++ b/imagine/include/imagine/util/ranges.hh @@ -27,4 +27,7 @@ constexpr auto iotaCount(T count) { return std::views::iota((T)0, count); } template constexpr auto enumerate(T &&rng) { return std::views::zip(std::views::iota(0), std::forward(rng)); } +template +constexpr auto lastIndex(T &&rng) { return std::ranges::size(std::forward(rng)) - 1; } + } diff --git a/imagine/include/imagine/util/rectangle2.h b/imagine/include/imagine/util/rectangle2.h index 74ce6e9a7..e1d5cf896 100644 --- a/imagine/include/imagine/util/rectangle2.h +++ b/imagine/include/imagine/util/rectangle2.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include namespace IG diff --git a/imagine/include/imagine/util/span.hh b/imagine/include/imagine/util/span.hh index aa5756ae2..19e9677a8 100644 --- a/imagine/include/imagine/util/span.hh +++ b/imagine/include/imagine/util/span.hh @@ -15,7 +15,6 @@ You should have received a copy of the GNU General Public License along with Imagine. If not, see */ -#include #include #include diff --git a/imagine/src/audio/Format.cc b/imagine/src/audio/Format.cc index 6c27badc1..e076d6874 100644 --- a/imagine/src/audio/Format.cc +++ b/imagine/src/audio/Format.cc @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include namespace IG::Audio diff --git a/imagine/src/base/common/Base.cc b/imagine/src/base/common/Base.cc index a6ef1f8e0..68f2b00cc 100755 --- a/imagine/src/base/common/Base.cc +++ b/imagine/src/base/common/Base.cc @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -109,7 +108,7 @@ void GLManager::resetCurrentContext() const SteadyClockTimePoint FrameParams::presentTime(int frames) const { - if(frames <= 1) + if(frames <= 0) return {}; return frameTime * frames + timestamp; } diff --git a/imagine/src/base/common/Screen.cc b/imagine/src/base/common/Screen.cc index 11a8b1ff0..ef747d049 100644 --- a/imagine/src/base/common/Screen.cc +++ b/imagine/src/base/common/Screen.cc @@ -20,7 +20,6 @@ #include #include #include -#include namespace IG { diff --git a/imagine/src/gfx/common/GfxText.cc b/imagine/src/gfx/common/GfxText.cc index 789b836f3..7a258f683 100644 --- a/imagine/src/gfx/common/GfxText.cc +++ b/imagine/src/gfx/common/GfxText.cc @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -26,21 +26,7 @@ namespace IG::Gfx { -Text::Text(const Text &t) noexcept -{ - *this = t; -} - -Text &Text::operator=(const Text &t) noexcept -{ - textStr = t.textStr; - face_ = t.face_; - sizeBeforeLineSpans = t.sizeBeforeLineSpans; - xSize = t.xSize; - ySize = t.ySize; - metrics = t.metrics; - return *this; -} +constexpr SystemLogger log{"GfxText"}; static int xSizeOfChar(Renderer &r, GlyphTextureSet *face_, int c, int spaceX) { @@ -56,13 +42,13 @@ static int xSizeOfChar(Renderer &r, GlyphTextureSet *face_, int c, int spaceX) return 0; } -void Text::makeGlyphs(Renderer &r) +void Text::makeGlyphs() { if(!hasText()) [[unlikely]] return; for(auto c : textStr) { - face_->glyphEntry(r, c); + face_->glyphEntry(renderer(), c); } } @@ -77,7 +63,7 @@ auto writeSpan(Renderer &r, auto quadsIt, WPt pos, std::u16string_view strView, auto gly = face_->glyphEntry(r, c, false); if(!gly) { - //logMsg("no glyph for %X", c); + //log.info("no glyph for:{:X}", c); pos.x += spaceSize; continue; } @@ -93,11 +79,16 @@ auto writeSpan(Renderer &r, auto quadsIt, WPt pos, std::u16string_view strView, return quadsIt; } -bool Text::compile(Renderer &r, TextLayoutConfig conf) +bool Text::compile(TextLayoutConfig conf) { if(!hasText()) [[unlikely]] + { + if(!face_) + log.warn("called compile() before setting face"); return false; - //logMsg("compiling text %s", str); + } + assert(quads.hasTask()); + auto &r = renderer(); if(sizeBeforeLineSpans) { textStr.resize(stringSize()); @@ -135,7 +126,7 @@ bool Text::compile(Renderer &r, TextLayoutConfig conf) { wentToNextLine = true; // Don't break text - //logMsg("new line %d without text break @ char %d, %d chars in line", lines+1, charIdx, charsInLine); + //log.info("new line {} without text break @ char {}, {} chars in line", lines+1, charIdx, charsInLine); lineInfo.emplace_back(xLineSize, charsInLine); maxXLineSize = std::max(xLineSize, maxXLineSize); xLineSize = 0; @@ -145,14 +136,14 @@ bool Text::compile(Renderer &r, TextLayoutConfig conf) { wentToNextLine = true; // Line has more than 1 block and is too big, needs text break - //logMsg("new line %d with text break @ char %d, %d chars in line", lines+1, charIdx, charsInLine); + //log.info("new line {} with text break @ char {}, {} chars in line", lines+1, charIdx, charsInLine); xLineSize -= textBlockSize; int charsInNextLine = (charIdx - textBlockIdx) + 1; lineInfo.emplace_back(xLineSize, charsInLine - charsInNextLine); maxXLineSize = std::max(xLineSize, maxXLineSize); xLineSize = textBlockSize; charsInLine = charsInNextLine; - //logMsg("break @ char %d with line starting @ %d, %d chars moved to next line, leaving %d", textBlockIdx, currLineIdx, charsInNextLine, lineInfo[lines-1].chars); + //log.info("break @ char {} with line starting @ {}, {} chars moved to next line, leaving {}", textBlockIdx, currLineIdx, charsInNextLine, lineInfo[lines-1].chars); } if(wentToNextLine) { @@ -179,7 +170,6 @@ bool Text::compile(Renderer &r, TextLayoutConfig conf) // write vertex data WPt pos{0, nominalHeight - yLineStart}; - quads.setTask(r.task()); quads.reset({.size = size_t(charIdx)}); auto mappedVerts = quads.map(); if(lines > 1) @@ -202,7 +192,7 @@ bool Text::compile(Renderer &r, TextLayoutConfig conf) auto [xLineSize, charsToDraw] = LineSpan::decode({spansPtr, LineSpan::encodedChar16Size}); spansPtr += LineSpan::encodedChar16Size; pos.x = startingXPos(xLineSize); - //logMsg("line:%d chars:%d ", i, charsToDraw); + //log.info("line:{} chars:{} ", i, charsToDraw); vertsIt = writeSpan(r, vertsIt, pos, std::u16string_view{s, charsToDraw}, face_, spaceSize); s += charsToDraw; pos.y += nominalHeight; @@ -228,7 +218,7 @@ static int drawSpan(RendererCommands &cmds, std::u16string_view strView, int spr auto gly = face_->glyphEntry(renderer, c, false); if(!gly) { - //logMsg("no glyph for %X", c); + //log.info("no glyph for {:X}", c); continue; } auto &[glyph, metrics] = *gly; @@ -253,7 +243,7 @@ void Text::draw(RendererCommands &cmds, WPt pos, _2DOrigin o) const pos.y -= ySize; else if(o.onYCenter()) pos.y -= ySize / 2; - //logMsg("drawing text @ %d,%d, size:%d,%d", xPos, yPos, xSize, ySize); + //log.info("drawing text @ {},{}, size:{},{}", xPos, yPos, xSize, ySize); cmds.basicEffect().setModelView(cmds, Mat4::makeTranslate({pos.x, pos.y, 0})); cmds.setVertexArray(quads); auto lines = currentLines(); @@ -266,7 +256,7 @@ void Text::draw(RendererCommands &cmds, WPt pos, _2DOrigin o) const { auto [xLineSize, charsToDraw] = LineSpan::decode({spansPtr, LineSpan::encodedChar16Size}); spansPtr += LineSpan::encodedChar16Size; - //logMsg("line:%d chars:%d ", i, charsToDraw); + //log.info("line:{} chars:{}", i, charsToDraw); spriteOffset = drawSpan(cmds, std::u16string_view{s, charsToDraw}, spriteOffset, face_); s += charsToDraw; } @@ -318,6 +308,8 @@ std::u16string Text::string() const return std::u16string{stringView()}; } +Renderer &Text::renderer() { return quads.renderer(); } + bool Text::hasText() const { return face_ && stringSize(); diff --git a/imagine/src/gfx/opengl/Buffer.cc b/imagine/src/gfx/opengl/Buffer.cc index d0d9e06c9..f46d0f6ab 100644 --- a/imagine/src/gfx/opengl/Buffer.cc +++ b/imagine/src/gfx/opengl/Buffer.cc @@ -79,7 +79,8 @@ static void allocBufferData(GLenum target, GLuint name, GLsizeiptr size, GLenum template void GLBuffer::reset(ByteBufferConfig config) { - if(sizeBytes_ == config.size) + assumeExpr(taskPtr()); + if(name() && sizeBytes_ == config.size) return; sizeBytes_ = config.size; auto usage = toGLEnum(config.usageHint); @@ -108,6 +109,7 @@ void GLBuffer::reset(ByteBufferConfig config) template MappedByteBuffer GLBuffer::map(ssize_t offset, size_t size) { + assumeExpr(taskPtr()); if(!size) size = sizeBytes() - offset; assert(offset + size <= sizeBytes()); @@ -116,14 +118,14 @@ MappedByteBuffer GLBuffer::map(ssize_t offset, size_t size) if(hasBufferMap(task().renderer())) { void *ptr; - task().run([this, &ptr, offset, size]() + task().runSync([this, &ptr, offset, size]() { auto target = toGLEnum(type); glBindBuffer(target, name()); ptr = task().renderer().support.glMapBufferRange(target, offset, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT); //log.debug("mapped offset:{} size:{} of buffer:0x{:X} to {}", offset, size, name(), ptr); - }, true); + }); return {{static_cast(ptr), size}, [this](const uint8_t *ptr, size_t) { task().run([name = name(), &support = task().renderer().support]() @@ -177,4 +179,59 @@ void destroyGLBufferRef(RendererTask &rTask, GLBufferRef name) template class GLBuffer; template class GLBuffer; +void GLVertexArray::initArray(GLBufferRef vbo, GLBufferRef ibo, int stride, VertexLayoutFlags enabledLayout, VertexLayoutDesc layoutDesc) +{ + assumeExpr(taskPtr()); + if(!task().renderer().support.hasVAOFuncs()) + { + arr.get() = ibo; + return; + } + if(arr.get()) + return; + task().runSync([=, &support = task().renderer().support, &arr = arr](GLTask::TaskContext ctx) + { + GLuint name; + support.glGenVertexArrays(1, &name); + arr.get() = name; + //log.info("created vertex array object:{:X}", name); + ctx.notifySemaphore(); + support.glBindVertexArray(name); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glEnableVertexAttribArray(VATTR_POS); + if(layoutDesc.texCoord.size) + glEnableVertexAttribArray(VATTR_TEX_UV); + else + glDisableVertexAttribArray(VATTR_TEX_UV); + if(layoutDesc.color.size) + glEnableVertexAttribArray(VATTR_COLOR); + else + glDisableVertexAttribArray(VATTR_COLOR); + glVertexAttribPointer(VATTR_POS, layoutDesc.pos.size, asGLType(layoutDesc.pos.type), + layoutDesc.pos.normalize, stride, (const void*)layoutDesc.pos.offset); + if(layoutDesc.texCoord.size) + { + glVertexAttribPointer(VATTR_TEX_UV, layoutDesc.texCoord.size, asGLType(layoutDesc.texCoord.type), + layoutDesc.texCoord.normalize, stride, (const void*)layoutDesc.texCoord.offset); + } + if(layoutDesc.color.size) + { + glVertexAttribPointer(VATTR_COLOR, layoutDesc.color.size, asGLType(layoutDesc.color.type), + layoutDesc.color.normalize, stride, (const void*)layoutDesc.color.offset); + } + }); +} + +void destroyGLVertexArrayRef(RendererTask &rTask, GLVertexArrayRef name) +{ + if(!rTask.renderer().support.hasVAOFuncs()) // name is actually a non-owning index buffer name + return; + rTask.run([&support = rTask.renderer().support, name]() + { + //log.debug("deleting vertex array object:0x{:X}", name); + support.glDeleteVertexArrays(1, &name); + }); +} + } diff --git a/imagine/src/gfx/opengl/GLTask.cc b/imagine/src/gfx/opengl/GLTask.cc index 81198e077..d7e150cfd 100644 --- a/imagine/src/gfx/opengl/GLTask.cc +++ b/imagine/src/gfx/opengl/GLTask.cc @@ -13,7 +13,6 @@ You should have received a copy of the GNU General Public License along with Imagine. If not, see */ -#define LOGTAG "GLTask" #include #include #include @@ -25,57 +24,45 @@ namespace IG::Gfx { +constexpr SystemLogger log{"GLTask"}; + GLTask::GLTask(ApplicationContext ctx): - GLTask{ctx, nullptr} -{} + GLTask{ctx, nullptr} {} GLTask::GLTask(ApplicationContext ctx, const char *debugLabel): onExit{ctx}, - commandPort{debugLabel} -{} + commandPort{debugLabel} {} bool GLTask::makeGLContext(GLTaskConfig config) { deinit(); - thread = IG::makeThreadSync( - [this, &config](auto &sem) + thread = makeThreadSync([this, &config](auto &sem) + { + threadId_ = thisThreadId(); + auto &glManager = *config.glManagerPtr; + glManager.bindAPI(glAPI); + context = makeGLContext(glManager, config.bufferConfig); + if(!context) [[unlikely]] { - threadId_ = thisThreadId(); - auto &glManager = *config.glManagerPtr; - glManager.bindAPI(glAPI); - context = makeGLContext(glManager, config.bufferConfig); - if(!context) [[unlikely]] - { - sem.release(); - return; - } - context.setCurrentContext(config.initialDrawable); - auto eventLoop = EventLoop::makeForThread(); - commandPort.attach(eventLoop, - [this, glDpy = context.display()](auto msgs) - { - for(auto msg : msgs) - { - if(msg.func) [[likely]] - { - msg.func(glDpy, msg.semPtr); - } - else - { - glDpy.resetCurrentContext(); - logMsg("exiting GL context:%p thread", (NativeGLContext)context); - context = {}; - EventLoop::forThread().stop(); - return false; - } - } - return true; - }); - logMsg("starting GL context:%p thread event loop", (NativeGLContext)context); sem.release(); - eventLoop.run(context); - commandPort.detach(); - }); + return; + } + context.setCurrentContext(config.initialDrawable); + log.info("starting GL context:{} thread message loop", (NativeGLContext)context); + sem.release(); + auto msgs = commandPort.messages(); + auto glDpy = context.display(); + for(auto msg : msgs) + { + if(msg.func) [[likely]] + msg.func(glDpy, msg.semPtr, msgs); + else + break; + } + glDpy.resetCurrentContext(); + log.info("exiting GL context:{} thread", (NativeGLContext)context); + context = {}; + }); if(!context) [[unlikely]] { return false; @@ -87,14 +74,14 @@ bool GLTask::makeGLContext(GLTaskConfig config) { if(backgrounded) { - run( + runSync( [&glContext = context](TaskContext ctx) { // unset the drawable and finish all commands before entering background if(GLManager::hasCurrentDrawable()) glContext.setCurrentDrawable({}); glFinish(); - }, true); + }); } return true; }, appContext(), RENDERER_TASK_ON_EXIT_PRIORITY @@ -107,10 +94,18 @@ GLTask::~GLTask() deinit(); } -void GLTask::runFunc(FuncDelegate del, bool awaitReply) +void GLTask::runFunc(FuncDelegate del, std::span extBuff, MessageReplyMode mode) { assert(context); - commandPort.send({.func = del}, awaitReply); + if(extBuff.size()) + { + assert(mode == MessageReplyMode::none); + commandPort.sendWithExtraData({.func = del}, extBuff); + } + else + { + commandPort.send({.func = del}, mode); + } } GLBufferConfig GLTask::glBufferConfig() const @@ -144,9 +139,9 @@ void GLTask::deinit() void GLTask::TaskContext::notifySemaphore() { - assumeExpr(semPtr); + assumeExpr(semaphorePtr); assumeExpr(semaphoreNeedsNotifyPtr); - semPtr->release(); + semaphorePtr->release(); markSemaphoreNotified(); } diff --git a/imagine/src/gfx/opengl/PixmapBufferTexture.cc b/imagine/src/gfx/opengl/PixmapBufferTexture.cc index 393cd8fa0..932a73613 100644 --- a/imagine/src/gfx/opengl/PixmapBufferTexture.cc +++ b/imagine/src/gfx/opengl/PixmapBufferTexture.cc @@ -19,7 +19,7 @@ #include #include #include -#include +#include #ifdef __ANDROID__ #include #include diff --git a/imagine/src/gfx/opengl/Renderer.cc b/imagine/src/gfx/opengl/Renderer.cc index cd43b7312..ed5b7dcd1 100755 --- a/imagine/src/gfx/opengl/Renderer.cc +++ b/imagine/src/gfx/opengl/Renderer.cc @@ -95,6 +95,7 @@ void Renderer::initMainTask(Window *initialWindow, DrawableConfig drawableConfig { throw std::runtime_error("Renderer error creating basic shader program"); } + quadIndices = {mainTask, 32}; } NativeWindowFormat GLRenderer::nativeWindowFormat(GLBufferConfig bufferConfig) const @@ -519,4 +520,6 @@ void destroyGLBuffer(RendererTask &task, NativeBuffer buff) }); } +const IndexBuffer &rendererQuadIndices(const RendererTask &rTask) { return rTask.renderer().quadIndices; } + } diff --git a/imagine/src/gfx/opengl/RendererCommands.cc b/imagine/src/gfx/opengl/RendererCommands.cc index 64a786336..3222e333d 100644 --- a/imagine/src/gfx/opengl/RendererCommands.cc +++ b/imagine/src/gfx/opengl/RendererCommands.cc @@ -46,6 +46,15 @@ GLRendererCommands::GLRendererCommands(RendererTask &rTask, Window *winPtr, Draw } } +void GLRendererCommands::bindGLVertexArray(GLuint vao) +{ + assert(hasVAOFuncs()); + if(currVertexArrayName == vao) + return; + currVertexArrayName = vao; + r->support.glBindVertexArray(vao); +} + void GLRendererCommands::bindGLArrayBuffer(GLuint vbo) { glBindBuffer(GL_ARRAY_BUFFER, vbo); @@ -53,6 +62,7 @@ void GLRendererCommands::bindGLArrayBuffer(GLuint vbo) void GLRendererCommands::bindGLIndexBuffer(GLuint ibo) { + assert(!hasVAOFuncs()); if(currIndexBufferName == ibo) return; currIndexBufferName = ibo; @@ -434,18 +444,6 @@ void RendererCommands::vertexBufferData(ssize_t offset, const void *data, size_t glBufferSubData(GL_ARRAY_BUFFER, offset, size, data); } -constexpr GLenum asGLType(AttribType type) -{ - switch(type) - { - case AttribType::UByte: return GL_UNSIGNED_BYTE; - case AttribType::Short: return GL_SHORT; - case AttribType::UShort: return GL_UNSIGNED_SHORT; - case AttribType::Float: return GL_FLOAT; - } - bug_unreachable("invalid AttribType"); -} - constexpr bool shouldNormalize(AttribType type, bool normalize) { return type != AttribType::Float && normalize; } void RendererCommands::drawPrimitives(Primitive mode, int start, int count) @@ -466,6 +464,8 @@ void RendererCommands::drawPrimitiveElements(Primitive mode, int start, int coun bool GLRendererCommands::useFixedFunctionPipeline() const { return r->support.useFixedFunctionPipeline; } +bool GLRendererCommands::hasVAOFuncs() const { return r->support.hasVAOFuncs(); } + #ifdef CONFIG_GFX_OPENGL_FIXED_FUNCTION_PIPELINE void GLRendererCommands::setupVertexArrayPointers(int stride, AttribDesc textureAttrib, AttribDesc colorAttrib, AttribDesc posAttrib) @@ -493,6 +493,7 @@ void GLRendererCommands::setupVertexArrayPointers(int stride, #ifdef CONFIG_GFX_OPENGL_SHADER_PIPELINE void GLRendererCommands::setupShaderVertexArrayPointers(int stride, VertexLayoutFlags enabledLayout, VertexLayoutDesc layoutDesc) { + assert(!hasVAOFuncs()); if(currentEnabledVertexLayout != enabledLayout) { if(layoutDesc.texCoord.size) diff --git a/imagine/src/gfx/opengl/RendererTask.cc b/imagine/src/gfx/opengl/RendererTask.cc index adc935b21..e09bf4df4 100644 --- a/imagine/src/gfx/opengl/RendererTask.cc +++ b/imagine/src/gfx/opengl/RendererTask.cc @@ -13,7 +13,6 @@ You should have received a copy of the GNU General Public License along with Imagine. If not, see */ -#define LOGTAG "RendererTask" #include #include #include @@ -27,23 +26,14 @@ namespace IG::Gfx { +constexpr SystemLogger log{"RendererTask"}; + GLRendererTask::GLRendererTask(ApplicationContext ctx, Renderer &r): GLRendererTask{ctx, nullptr, r} {} GLRendererTask::GLRendererTask(ApplicationContext ctx, const char *debugLabel, Renderer &r): GLTask{ctx, debugLabel}, r{&r} {} -void GLRendererTask::initVAO() -{ - #ifndef CONFIG_GFX_OPENGL_ES - if(streamVAO) [[likely]] - return; - logMsg("making stream VAO"); - glGenVertexArrays(1, &streamVAO); - glBindVertexArray(streamVAO); - #endif -} - void GLRendererTask::initDefaultFramebuffer() { if(Config::Gfx::GLDRAWABLE_NEEDS_FRAMEBUFFER && !defaultFB) @@ -51,7 +41,7 @@ void GLRendererTask::initDefaultFramebuffer() glContext().setCurrentContext({}); GLuint fb; glGenFramebuffers(1, &fb); - logMsg("created default framebuffer:%u", fb); + log.info("created default framebuffer:{}", fb); glBindFramebuffer(GL_FRAMEBUFFER, fb); defaultFB = fb; } @@ -63,7 +53,7 @@ GLuint GLRendererTask::bindFramebuffer(Texture &tex) if(!fbo) [[unlikely]] { glGenFramebuffers(1, &fbo); - logMsg("init FBO:0x%X", fbo); + log.info("init FBO:{:X}", fbo); } glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.texName(), 0); @@ -84,7 +74,7 @@ void GLRendererTask::doPreDraw(Window &win, WindowDrawParams winParams, DrawPara { if(!context) [[unlikely]] { - logWarn("draw() called without context"); + log.warn("draw() called without context"); return; } assumeExpr(winData(win).drawable); @@ -123,7 +113,7 @@ void RendererTask::updateDrawableForSurfaceChange(Window &win, WindowSurfaceChan if(change.flags.surfaceResized) { GLTask::run( - [this, drawable = (Drawable)drawable, v = data.viewportRect, swapInterval = data.swapInterval](TaskContext ctx) + [this, drawable = (Drawable)drawable, v = data.viewportRect, swapInterval = data.swapInterval]() { // reset and clear the drawable updateDrawable(drawable, v, swapInterval); @@ -148,8 +138,8 @@ void RendererTask::setPresentMode(Window &win, PresentMode mode) data.swapInterval = swapInterval; if(!data.drawable) return; - logMsg("setting swap interval:%d for drawable:%p", swapInterval, Drawable(data.drawable)); - GLTask::run([this, drawable = Drawable(data.drawable), v = data.viewportRect, swapInterval](TaskContext ctx) + log.info("setting swap interval:{} for drawable:{}", swapInterval, Drawable(data.drawable)); + GLTask::run([this, drawable = Drawable(data.drawable), v = data.viewportRect, swapInterval]() { updateDrawable(drawable, v, swapInterval); }); @@ -160,7 +150,7 @@ void RendererTask::setDefaultViewport(Window &win, Viewport v) renderer().setDefaultViewport(win, v); auto &data = winData(win); GLTask::run( - [drawable = (Drawable)data.drawable, v = v.asYUpRelRect()](TaskContext ctx) + [drawable = (Drawable)data.drawable, v = v.asYUpRelRect()]() { // update viewport if drawable is currently in use if(GLManager::hasCurrentDrawable(drawable)) @@ -174,13 +164,13 @@ void GLRendererTask::destroyDrawable(GLDrawable &drawable) { if(!drawable) return; - GLTask::run( + GLTask::runSync( [this, drawable = (Drawable)drawable](TaskContext ctx) { // unset the drawable if it's currently in use if(GLManager::hasCurrentDrawable(drawable)) context.setCurrentDrawable({}); - }, true); + }); drawable = {}; } @@ -192,12 +182,15 @@ void GLRendererTask::runInitialCommandsInGL(TaskContext ctx, DrawContextSupport debugEnabled = true; support.setGLDebugOutput(true); } - #ifndef CONFIG_GFX_OPENGL_ES - if(!support.useFixedFunctionPipeline) - initVAO(); - #endif ctx.notifySemaphore(); - if(!support.useFixedFunctionPipeline) + if(!support.useFixedFunctionPipeline && !Config::Gfx::OPENGL_ES && !support.hasVAOFuncs()) + { + log.debug("creating global VAO for testing non-VAO code paths"); + GLuint name; + support.glGenVertexArrays(1, &name); + support.glBindVertexArray(name); + } + if(!support.useFixedFunctionPipeline && !support.hasVAOFuncs()) { runGLCheckedVerbose([&]() { @@ -233,7 +226,7 @@ SyncFence RendererTask::addSyncFence() runSync( [&support = r->support, &sync](TaskContext ctx) { - sync = support.fenceSync(ctx.glDisplay()); + sync = support.fenceSync(ctx.glDisplay); }); return sync; } @@ -254,7 +247,7 @@ void RendererTask::deleteSyncFence(SyncFence fence) GLTask::run( [&support = r->support, sync = fence.sync](TaskContext ctx) { - support.deleteSync(ctx.glDisplay(), sync); + support.deleteSync(ctx.glDisplay, sync); }); } } @@ -267,7 +260,7 @@ void RendererTask::clientWaitSync(SyncFence fence, int flags, std::chrono::nanos const bool canPerformInCurrentThread = Config::GL_PLATFORM_EGL && !flags; if(canPerformInCurrentThread) { - //logDMsg("waiting on sync:%p flush:%s timeout:0%llX", fence.sync, flags & 1 ? "yes" : "no", (unsigned long long)timeout); + //log.debug("waiting on sync:{} flush:{} timeout:{}", fence.sync, flags & 1 ? "yes" : "no", timeout); auto dpy = renderer().glDisplay(); renderer().support.clientWaitSync(dpy, fence.sync, 0, timeout.count()); renderer().support.deleteSync(dpy, fence.sync); @@ -277,9 +270,9 @@ void RendererTask::clientWaitSync(SyncFence fence, int flags, std::chrono::nanos runSync( [&support = r->support, sync = fence.sync, timeout, flags](TaskContext ctx) { - support.clientWaitSync(ctx.glDisplay(), sync, flags, timeout.count()); + support.clientWaitSync(ctx.glDisplay, sync, flags, timeout.count()); ctx.notifySemaphore(); - support.deleteSync(ctx.glDisplay(), sync); + support.deleteSync(ctx.glDisplay, sync); }); } } @@ -298,8 +291,8 @@ void RendererTask::waitSync(SyncFence fence) GLTask::run( [&support = r->support, sync = fence.sync](TaskContext ctx) { - support.waitSync(ctx.glDisplay(), sync); - support.deleteSync(ctx.glDisplay(), sync); + support.waitSync(ctx.glDisplay, sync); + support.deleteSync(ctx.glDisplay, sync); }); } @@ -334,7 +327,7 @@ void RendererTask::setDebugOutput(bool on) { return; } - logMsg("set context:%p debug output:%s", (NativeGLContext)glContext(), on ? "on" : "off"); + log.info("set context:{} debug output:{}", (NativeGLContext)glContext(), on ? "on" : "off"); debugEnabled = on; run( [&support = renderer().support, on]() @@ -351,8 +344,8 @@ RendererCommands GLRendererTask::makeRendererCommands(GLTask::TaskContext taskCt initDefaultFramebuffer(); auto &drawable = winData(win).drawable; RendererCommands cmds{*static_cast(this), - notifyWindowAfterPresent ? &win : nullptr, drawable, winData(win).viewportRect, taskCtx.glDisplay(), - glContext(), manageSemaphore ? taskCtx.semaphorePtr() : nullptr}; + notifyWindowAfterPresent ? &win : nullptr, drawable, winData(win).viewportRect, taskCtx.glDisplay, + glContext(), manageSemaphore ? taskCtx.semaphorePtr : nullptr}; if(manageSemaphore) taskCtx.markSemaphoreNotified(); // semaphore will be notified in RendererCommands::present() return cmds; diff --git a/imagine/src/gfx/opengl/Texture.cc b/imagine/src/gfx/opengl/Texture.cc index f1b0a21a1..913c93df8 100644 --- a/imagine/src/gfx/opengl/Texture.cc +++ b/imagine/src/gfx/opengl/Texture.cc @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include "utils.hh" @@ -385,7 +385,7 @@ ErrorCode Texture::setFormat(PixmapDesc desc, int levels, ColorSpace colorSpace, setSwizzleForFormatInGL(r, desc.format, texName); if(remakeTexName) setSamplerParamsInGL(r, samplerParams); - }, remakeTexName); + }, remakeTexName ? MessageReplyMode::wait : MessageReplyMode::none); } updateFormatInfo(desc, levels); return {}; @@ -433,7 +433,7 @@ void Texture::writeAligned(int level, PixmapView pixmap, WPt destPos, int assume log.info("generating mipmaps for texture:0x{:X}", texName); r.support.generateMipmaps(GL_TEXTURE_2D); } - }, !writeFlags.async); + }, writeFlags.async ? MessageReplyMode::none : MessageReplyMode::wait); if(makeMipmaps) { updateLevelsForMipmapGeneration(); diff --git a/imagine/src/gfx/opengl/config.cc b/imagine/src/gfx/opengl/config.cc index 15fb12dc1..f7c8b88e3 100755 --- a/imagine/src/gfx/opengl/config.cc +++ b/imagine/src/gfx/opengl/config.cc @@ -98,6 +98,10 @@ static void printFeatures(DrawContextSupport support) { featuresStr.append(" [Sampler Objects]"); } + if(Config::Gfx::OPENGL_ES >= 2 && support.hasVAOFuncs()) + { + featuresStr.append(" [VAOs]"); + } if(support.hasPBOFuncs) { featuresStr.append(" [PBOs]"); @@ -270,6 +274,17 @@ bool DrawContextSupport::hasMemoryBarriers() const #endif*/ } +bool DrawContextSupport::hasVAOFuncs() const +{ + if constexpr(Config::DEBUG_BUILD && forceNoVAOs) + return false; + #ifdef CONFIG_GFX_OPENGL_ES + return glBindVertexArray; + #else + return !useFixedFunctionPipeline; + #endif +} + void GLRenderer::setupUnmapBufferFunc() { #ifdef CONFIG_GFX_OPENGL_ES @@ -316,6 +331,26 @@ void GLRenderer::setupMemoryBarrier() #endif*/ } +void GLRenderer::setupVAOFuncs(bool oes) +{ + #ifdef CONFIG_GFX_OPENGL_ES + if(support.glBindVertexArray) + return; + if(oes) + { + support.glBindVertexArray = (typeof(support.glBindVertexArray))glManager.procAddress("glBindVertexArrayOES"); + support.glGenVertexArrays = (typeof(support.glGenVertexArrays))glManager.procAddress("glGenVertexArraysOES"); + support.glDeleteVertexArrays = (typeof(support.glDeleteVertexArrays))glManager.procAddress("glDeleteVertexArraysOES"); + } + else + { + support.glBindVertexArray = (typeof(support.glBindVertexArray))glManager.procAddress("glBindVertexArray"); + support.glGenVertexArrays = (typeof(support.glGenVertexArrays))glManager.procAddress("glGenVertexArrays"); + support.glDeleteVertexArrays = (typeof(support.glDeleteVertexArrays))glManager.procAddress("glDeleteVertexArrays"); + } + #endif +} + void GLRenderer::checkExtensionString(std::string_view extStr, bool &useFBOFuncs) { //logMsg("checking %s", extStr); @@ -421,6 +456,10 @@ void GLRenderer::checkExtensionString(std::string_view extStr, bool &useFBOFuncs { support.hasSrgbWriteControl = true; } + else if(Config::Gfx::OPENGL_ES >= 2 && extStr == "GL_OES_vertex_array_object") + { + setupVAOFuncs(true); + } #endif #ifndef CONFIG_GFX_OPENGL_ES /*else if(string_equal(extStr, "GL_EXT_texture_filter_anisotropic")) @@ -518,7 +557,7 @@ void Renderer::configureRenderer() #ifdef CONFIG_BASE_GL_PLATFORM_EGL if constexpr((bool)Config::Gfx::OPENGL_ES) { - auto extStr = ctx.glDisplay().queryExtensions(); + auto extStr = ctx.glDisplay.queryExtensions(); setupEglFenceSync(extStr); } #endif @@ -544,8 +583,6 @@ void Renderer::configureRenderer() { if(!support.useFixedFunctionPipeline) { - // must render via VAOs/VBOs in 3.1+ without compatibility context - //setupVAOFuncs(); setupTextureSwizzle(); setupRGFormats(); setupSamplerObjects(); @@ -607,6 +644,7 @@ void Renderer::configureRenderer() setupRGFormats(); setupSamplerObjects(); setupPBO(); + setupVAOFuncs(); if(!Config::GL_PLATFORM_EGL) setupFenceSync(); if(!Config::envIsIOS) diff --git a/imagine/src/gfx/opengl/debug.cc b/imagine/src/gfx/opengl/debug.cc index 3d68a05f5..000bd1109 100644 --- a/imagine/src/gfx/opengl/debug.cc +++ b/imagine/src/gfx/opengl/debug.cc @@ -127,6 +127,8 @@ void DrawContextSupport::setGLDebugOutput(bool on) return; } logger_modulePrintfn(severityToLogger(severity), "%s: %s", debugTypeToStr(type), message); + if(severity == GL_DEBUG_SEVERITY_HIGH) + abort(); }, nullptr); glEnable(DEBUG_OUTPUT); } diff --git a/imagine/src/gfx/opengl/internalDefs.hh b/imagine/src/gfx/opengl/internalDefs.hh index d1e6e3252..dee0b65b6 100644 --- a/imagine/src/gfx/opengl/internalDefs.hh +++ b/imagine/src/gfx/opengl/internalDefs.hh @@ -31,8 +31,9 @@ const GLRendererWindowData &winData(const Window &win); extern bool checkGLErrors; extern bool checkGLErrorsVerbose; -static constexpr bool defaultToFullErrorChecks = true; -static constexpr GLuint VATTR_POS = 0, VATTR_TEX_UV = 1, VATTR_COLOR = 2; +constexpr bool forceNoVAOs = false; // for testing non-VAO code paths +constexpr bool defaultToFullErrorChecks = true; +constexpr GLuint VATTR_POS = 0, VATTR_TEX_UV = 1, VATTR_COLOR = 2; static constexpr GL::API glAPI = Config::Gfx::OPENGL_ES ? GL::API::OPENGL_ES : GL::API::OPENGL; @@ -40,4 +41,16 @@ static constexpr GL::API glAPI = float rotationRadians(Rotation o); int toSwapInterval(Window &win, PresentMode mode); +constexpr GLenum asGLType(AttribType type) +{ + switch(type) + { + case AttribType::UByte: return GL_UNSIGNED_BYTE; + case AttribType::Short: return GL_SHORT; + case AttribType::UShort: return GL_UNSIGNED_SHORT; + case AttribType::Float: return GL_FLOAT; + } + bug_unreachable("invalid AttribType"); +} + } diff --git a/imagine/src/gui/AlertView.cc b/imagine/src/gui/AlertView.cc index da4bbbde2..7f2fee4b0 100644 --- a/imagine/src/gui/AlertView.cc +++ b/imagine/src/gui/AlertView.cc @@ -22,7 +22,7 @@ #include #include #include -#include +#include namespace IG { @@ -47,7 +47,7 @@ void BaseAlertView::place() { using namespace IG::Gfx; int xSize = viewRect().xSize() * .8; - text.compile(renderer(), {.maxLineSize = int(xSize * 0.95f)}); + text.compile({.maxLineSize = int(xSize * 0.95f)}); int menuYSize = menu.cells() * text.face()->nominalHeight()*2; int labelYSize = IG::makeEvenRoundedUp(text.fullHeight()); @@ -78,7 +78,7 @@ bool BaseAlertView::inputEvent(const Input::Event &e) void BaseAlertView::prepareDraw() { - text.makeGlyphs(renderer()); + text.makeGlyphs(); menu.prepareDraw(); } diff --git a/imagine/src/gui/FSPicker.cc b/imagine/src/gui/FSPicker.cc index 3fff24691..d3b2a380c 100644 --- a/imagine/src/gui/FSPicker.cc +++ b/imagine/src/gui/FSPicker.cc @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -38,7 +38,7 @@ FSPicker::FSPicker(ViewAttachParams attach, Gfx::TextureSpan backRes, Gfx::Textu View{attach}, filter{filter}, controller{attach}, - msgText{face_ ? face_ : &defaultFace()}, + msgText{attach.rendererTask, face_ ? face_ : &defaultFace()}, mode_{mode} { auto nav = makeView @@ -83,7 +83,7 @@ void FSPicker::place() controller.place(viewRect(), displayRect()); if(dirListThread.isWorking()) return; - msgText.compile(renderer()); + msgText.compile(); } void FSPicker::changeDirByInput(CStringView path, FS::RootPathInfo rootInfo, const Input::Event &e, @@ -175,7 +175,7 @@ void FSPicker::prepareDraw() controller.top().prepareDraw(); if(dirListThread.isWorking()) return; - msgText.makeGlyphs(renderer()); + msgText.makeGlyphs(); } void FSPicker::draw(Gfx::RendererCommands &__restrict__ cmds) @@ -505,7 +505,7 @@ void FSPicker::listDirectory(CStringView path, ThreadStop &stop) { return true; } - auto &item = dir.emplace_back(FileEntry{std::string{entry.path()}, {entry.name(), &face(), nullptr}}); + auto &item = dir.emplace_back(attachParams(), std::string{entry.path()}, entry.name()); if(isDir) item.text.flags.user |= FileEntry::isDirFlag; if(mode_ == Mode::DIR && !isDir) @@ -553,7 +553,7 @@ void FSPicker::listDirectory(CStringView path, ThreadStop &stop) else // no entries, show a message instead { msgText.resetString("Empty Directory"); - msgText.compile(renderer()); + msgText.compile(); } } catch(std::system_error &err) @@ -562,7 +562,7 @@ void FSPicker::listDirectory(CStringView path, ThreadStop &stop) auto ec = err.code(); std::string_view extraMsg = mode_ == Mode::FILE_IN_DIR ? "" : "\nPick a path from the top bar"; msgText.resetString(std::format("Can't open directory:\n{}{}", ec.message(), extraMsg)); - msgText.compile(renderer()); + msgText.compile(); } } diff --git a/imagine/src/gui/MenuItem.cc b/imagine/src/gui/MenuItem.cc index 7b6a4f1a8..c00a586f7 100644 --- a/imagine/src/gui/MenuItem.cc +++ b/imagine/src/gui/MenuItem.cc @@ -23,9 +23,9 @@ namespace IG { -void MenuItem::prepareDraw(Gfx::Renderer &r) +void MenuItem::prepareDraw() { - t.makeGlyphs(r); + t.makeGlyphs(); } void MenuItem::draw(Gfx::RendererCommands &__restrict__ cmds, int xPos, int yPos, int xSize, int ySize, @@ -46,14 +46,14 @@ void MenuItem::draw(Gfx::RendererCommands &__restrict__ cmds, int xPos, int yPos t.draw(cmds, {xPos, yPos}, align,color); } -void MenuItem::compile(Gfx::Renderer &r) +void MenuItem::compile() { - t.compile(r); + t.compile(); } int MenuItem::ySize() const { - return t.face()->nominalHeight(); + return t.face() ? t.face()->nominalHeight() : 0; } int MenuItem::xSize() const @@ -66,21 +66,21 @@ const Gfx::Text &MenuItem::text() const return t; } -void BaseDualTextMenuItem::compile(Gfx::Renderer &r) +void BaseDualTextMenuItem::compile() { - MenuItem::compile(r); - compile2nd(r); + MenuItem::compile(); + compile2nd(); } -void BaseDualTextMenuItem::compile2nd(Gfx::Renderer &r) +void BaseDualTextMenuItem::compile2nd() { - t2.compile(r); + t2.compile(); } -void BaseDualTextMenuItem::prepareDraw(Gfx::Renderer &r) +void BaseDualTextMenuItem::prepareDraw() { - MenuItem::prepareDraw(r); - t2.makeGlyphs(r); + MenuItem::prepareDraw(); + t2.makeGlyphs(); } void BaseDualTextMenuItem::draw2ndText(Gfx::RendererCommands &cmds, int xPos, int yPos, int xSize, int ySize, @@ -123,7 +123,7 @@ bool BoolMenuItem::setBoolValue(bool val, View &view) if(val != boolValue()) { setBoolValue(val); - t2.compile(view.renderer()); + t2.compile(); view.postDraw(); return true; } @@ -215,10 +215,10 @@ void MultiChoiceMenuItem::draw(Gfx::RendererCommands &__restrict__ cmds, int xPo BaseDualTextMenuItem::draw2ndText(cmds, xPos, yPos, xSize, ySize, xIndent, align, color2); } -void MultiChoiceMenuItem::compile(Gfx::Renderer &r) +void MultiChoiceMenuItem::compile() { setDisplayString(selected_); - BaseDualTextMenuItem::compile(r); + BaseDualTextMenuItem::compile(); } int MultiChoiceMenuItem::selected() const @@ -234,7 +234,7 @@ size_t MultiChoiceMenuItem::items() const bool MultiChoiceMenuItem::setSelected(int idx, View &view) { bool selectChanged = setSelected(idx); - t2.compile(view.renderer()); + t2.compile(); view.postDraw(); return selectChanged; } @@ -247,12 +247,12 @@ bool MultiChoiceMenuItem::setSelected(int idx) return selectChanged; } -bool MultiChoiceMenuItem::setSelected(Id id, View &view) +bool MultiChoiceMenuItem::setSelected(MenuId id, View &view) { return setSelected(idxOfId(id), view); } -bool MultiChoiceMenuItem::setSelected(Id id) +bool MultiChoiceMenuItem::setSelected(MenuId id) { return setSelected(idxOfId(id)); } @@ -321,18 +321,18 @@ void MultiChoiceMenuItem::updateDisplayString() setDisplayString(selected_); } -int MultiChoiceMenuItem::idxOfId(IdInt id) +int MultiChoiceMenuItem::idxOfId(MenuId id) { auto items = items_(*this); auto item = item_; - Id lastId{}; + MenuId lastId{}; for(auto i : iotaCount(items)) { - lastId = item(*this, i).id(); + lastId = item(*this, i).id; if(lastId == id) return (int)i; } - if(lastId == DEFAULT_ID) // special case to simplify uses where the last menu item represents a custom value + if(lastId == defaultMenuId) // special case to simplify uses where the last menu item represents a custom value return items - 1; else return -1; diff --git a/imagine/src/gui/NavView.cc b/imagine/src/gui/NavView.cc index 62aa0962f..d25a9b3ef 100644 --- a/imagine/src/gui/NavView.cc +++ b/imagine/src/gui/NavView.cc @@ -29,7 +29,7 @@ constexpr SystemLogger log; NavView::NavView(ViewAttachParams attach, Gfx::GlyphTextureSet *face): View{attach}, - text{"", face} {} + text{attach.rendererTask, u"", face} {} void NavView::setOnPushLeftBtn(OnPushDelegate del) { @@ -146,12 +146,12 @@ bool NavView::inputEvent(const Input::Event &e) void NavView::prepareDraw() { - text.makeGlyphs(renderer()); + text.makeGlyphs(); } void NavView::place() { - text.compile(renderer()); + text.compile(); auto &textRect = control[1].rect; textRect.setPosRel(viewRect().pos(LT2DO), viewRect().size(), LT2DO); control[0].rect.setPosRel(viewRect().pos(LT2DO), viewRect().ySize(), LT2DO); @@ -215,7 +215,7 @@ void BasicNavView::setBackgroundGradient(std::span if(!gradStops.size()) { gradientStops = {}; - bgVerts = {}; + bgVerts.reset({.size = 0}); return; } gradientStops.resetForOverwrite(gradStops.size()); diff --git a/imagine/src/gui/ScrollView.cc b/imagine/src/gui/ScrollView.cc index fc2dbcd68..e61d96e2b 100644 --- a/imagine/src/gui/ScrollView.cc +++ b/imagine/src/gui/ScrollView.cc @@ -19,13 +19,12 @@ #include #include #include -#include +#include #include #include #include #include -#include -#include +#include #include #include diff --git a/imagine/src/gui/TableView.cc b/imagine/src/gui/TableView.cc index cb6b97452..d0374279e 100755 --- a/imagine/src/gui/TableView.cc +++ b/imagine/src/gui/TableView.cc @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include namespace IG @@ -60,10 +60,9 @@ void TableView::setAlign(_2DOrigin align) void TableView::prepareDraw() { - auto &r = renderer(); for(auto i : iotaCount(items(*this))) { - item(*this, i).prepareDraw(r); + item(*this, i).prepareDraw(); } } @@ -127,8 +126,9 @@ void TableView::draw(Gfx::RendererCommands &__restrict__ cmds) cmds.set(BlendMode::OFF); cmds.setColor(ColorName::WHITE); cmds.setVertexArray(separatorQuads); + cmds.setVertexBuffer(separatorQuads); cmds.vertexBufferData(0, vRect.data(), vRect.size() * sizeof(IColQuad)); - cmds.drawQuads(quadIndices(), 0, vRect.size()); + cmds.drawQuads(0, vRect.size()); } } @@ -165,7 +165,7 @@ void TableView::place() for(auto i : iotaCount(cells_)) { //logMsg("compile item %d", i); - item(*this, i).compile(renderer()); + item(*this, i).compile(); } if(cells_) { diff --git a/imagine/src/gui/TextEntry.cc b/imagine/src/gui/TextEntry.cc index 0a1074b61..985109d2c 100644 --- a/imagine/src/gui/TextEntry.cc +++ b/imagine/src/gui/TextEntry.cc @@ -25,12 +25,12 @@ namespace IG { -TextEntry::TextEntry(const char *initText, Gfx::Renderer &r, Gfx::GlyphTextureSet *face): - bgQuads{r.mainTask, {.size = 1}}, - t{initText, face}, +TextEntry::TextEntry(const char *initText, ViewAttachParams attach, Gfx::GlyphTextureSet *face): + bgQuads{attach.rendererTask, {.size = 1}}, + t{attach.rendererTask, initText, face}, str{initText} { - t.compile(r); + t.compile(); } void TextEntry::setAcceptingInput(bool on) @@ -100,9 +100,8 @@ bool TextEntry::inputEvent(View &parentView, const Input::Event &e) if(updateText) { { - parentView.waitForDrawFinished(); t.resetString(str); - t.compile(parentView.renderer()); + t.compile(); } parentView.postDraw(); } @@ -115,7 +114,7 @@ bool TextEntry::inputEvent(View &parentView, const Input::Event &e) void TextEntry::prepareDraw(Gfx::Renderer &r) { - t.makeGlyphs(r); + t.makeGlyphs(); } void TextEntry::draw(Gfx::RendererCommands &__restrict__ cmds) @@ -127,7 +126,7 @@ void TextEntry::draw(Gfx::RendererCommands &__restrict__ cmds) void TextEntry::place(Gfx::Renderer &r) { - t.compile(r); + t.compile(); } void TextEntry::place(Gfx::Renderer &r, WindowRect rect) @@ -150,6 +149,19 @@ WindowRect TextEntry::bgRect() const CollectTextInputView::CollectTextInputView(ViewAttachParams attach, CStringView msgText, CStringView initialContent, Gfx::TextureSpan closeRes, OnTextDelegate onText, Gfx::GlyphTextureSet *face): View{attach}, + cancelButton + { + [&] + { + return doIfUsed(cancelButton, [&](auto &) + { + if(!attach.viewManager.needsBackControl && !closeRes) + return CancelButton{}; + return CancelButton{.quad = {attach.rendererTask, {.size = 1}}, .texture = closeRes}; + }); + }() + }, + message{attach.rendererTask, msgText, face ? face : &attach.viewManager.defaultFace}, textField { attach.appContext(), @@ -173,22 +185,11 @@ CollectTextInputView::CollectTextInputView(ViewAttachParams attach, CStringView textEntry { initialContent, - attach.renderer(), + attach, face ? face : &attach.viewManager.defaultFace }, onTextD{onText} { - face = face ? face : &attach.viewManager.defaultFace; - doIfUsed(cancelButton, - [&](auto &cancelButton) - { - if(manager().needsBackControl && closeRes) - { - cancelButton.quad = {attach.rendererTask, {.size = 4}}; - cancelButton.texture = closeRes; - } - }); - message = {msgText, face}; doIfUsed(textEntry, [](auto &textEntry) { @@ -209,7 +210,7 @@ void CollectTextInputView::place() cancelButton.quad.write(0, {.bounds = cancelButton.bounds.template as(), .textureSpan = cancelButton.texture}); } }); - message.compile(renderer(), {.maxLineSize = int(viewRect().xSize() * 0.95f)}); + message.compile({.maxLineSize = int(viewRect().xSize() * 0.95f)}); WindowRect textRect; int xSize = viewRect().xSize() * 0.95f; int ySize = face.nominalHeight(); @@ -266,7 +267,7 @@ bool CollectTextInputView::inputEvent(const Input::Event &e) void CollectTextInputView::prepareDraw() { - message.makeGlyphs(renderer()); + message.makeGlyphs(); doIfUsed(textEntry, [this](auto &textEntry) { diff --git a/imagine/src/gui/TextTableView.cc b/imagine/src/gui/TextTableView.cc index 60a8579e8..196d660d6 100644 --- a/imagine/src/gui/TextTableView.cc +++ b/imagine/src/gui/TextTableView.cc @@ -14,7 +14,7 @@ along with EmuFramework. If not, see */ #include -#include +#include #include #include #include @@ -28,11 +28,6 @@ TextMenuItem &TextTableView::item(size_t idx) return textItem[idx]; } -void TextTableView::setItems(size_t items) -{ - textItem.resize(items); -} - void TextTableView::onAddedToController(ViewController *c, const Input::Event &e) { if(activeItem != -1 && e.keyEvent()) diff --git a/imagine/src/gui/ToastView.cc b/imagine/src/gui/ToastView.cc index b72de44b4..130466dbb 100644 --- a/imagine/src/gui/ToastView.cc +++ b/imagine/src/gui/ToastView.cc @@ -15,6 +15,7 @@ #define LOGTAG "ToastView" #include +#include #include #include #include @@ -22,13 +23,14 @@ #include #include #include -#include +#include #include namespace IG { ToastView::ToastView(ViewAttachParams attach): View{attach}, + text{attach.rendererTask, &attach.viewManager.defaultFace}, unpostTimer { "ToastView::unpostTimer", @@ -41,7 +43,6 @@ ToastView::ToastView(ViewAttachParams attach): View{attach}, void ToastView::setFace(Gfx::GlyphTextureSet &face) { - waitForDrawFinished(); text.setFace(&face); } @@ -50,14 +51,13 @@ void ToastView::clear() if(text.stringSize()) { unpostTimer.cancel(); - waitForDrawFinished(); text.resetString(); } } void ToastView::place() { - text.compile(renderer(), {.maxLineSize = int(viewRect().xSize() * 0.95f), .maxLines = 6, .alignment = Gfx::TextAlignment::center}); + text.compile({.maxLineSize = int(viewRect().xSize() * 0.95f), .maxLines = 6, .alignment = Gfx::TextAlignment::center}); int labelYSize = IG::makeEvenRoundedUp(text.fullHeight()); //logMsg("label y size:%d", labelYSize); msgFrame.setPosRel(viewRect().pos(CB2DO), @@ -68,7 +68,6 @@ void ToastView::place() void ToastView::unpost() { logMsg("unposting"); - waitForDrawFinished(); text.resetString(); postDraw(); } @@ -81,7 +80,7 @@ void ToastView::postContent(int secs) void ToastView::prepareDraw() { - text.makeGlyphs(renderer()); + text.makeGlyphs(); } void ToastView::draw(Gfx::RendererCommands &__restrict__ cmds) diff --git a/imagine/src/gui/View.cc b/imagine/src/gui/View.cc index a6011a817..f377b7ea4 100644 --- a/imagine/src/gui/View.cc +++ b/imagine/src/gui/View.cc @@ -20,13 +20,14 @@ #include #include #include -#include -#include +#include #include namespace IG { +constexpr SystemLogger log{"View"}; + Gfx::Renderer &ViewAttachParams::renderer() const { return rendererTask.renderer(); @@ -60,7 +61,7 @@ void ViewController::popAndShow() void ViewController::popTo(View &v) { - logErr("popTo() not implemented for this controller"); + log.error("popTo() not implemented for this controller"); } bool ViewController::inputEvent(const Input::Event &) @@ -85,7 +86,7 @@ void ViewManager::setTableXIndentMM(float indentMM, const Window &win) auto oldIndent = std::exchange(tableXIndentPx, win.widthMMInPixels(indentMM)); if(tableXIndentPx != oldIndent) { - logDMsg("setting X indent:%.2fmm (%d as pixels)", indentMM, tableXIndentPx); + //log.debug("setting X indent:{}mm ({} as pixels)", indentMM, tableXIndentPx); } } @@ -128,7 +129,7 @@ void View::dismiss(bool refreshLayout) } else { - logWarn("called dismiss with no controller"); + log.warn("called dismiss with no controller"); } } @@ -140,12 +141,10 @@ void View::dismissPrevious() } else { - logWarn("called dismissPrevious with no controller"); + log.warn("called dismissPrevious with no controller"); } } -Gfx::QuadIndexArray &View::quadIndices() { return manager().quadIndices; } - Gfx::GlyphTextureSet &View::defaultFace() { return manager().defaultFace; } Gfx::GlyphTextureSet &View::defaultBoldFace() { return manager().defaultBoldFace; } @@ -241,7 +240,6 @@ void View::show() { prepareDraw(); onShow(); - //logMsg("showed view"); postDraw(); } @@ -300,11 +298,4 @@ bool View::pointIsInView(WPt pos) return viewRect().overlaps(pos); } -void View::waitForDrawFinished() -{ - // currently a no-op due to RendererTask only running present() async - /*assumeExpr(rendererTask_); - rendererTask_->waitForDrawFinished();*/ -} - } diff --git a/imagine/src/gui/ViewStack.cc b/imagine/src/gui/ViewStack.cc index 2cce896e8..721311a3a 100644 --- a/imagine/src/gui/ViewStack.cc +++ b/imagine/src/gui/ViewStack.cc @@ -61,7 +61,6 @@ void BasicViewController::dismissView(int idx, bool) if(!view || idx != 0 || idx != -1) return; auto &win = view->window(); - view->waitForDrawFinished(); view.reset(); if(removeViewDel) removeViewDel(); @@ -79,7 +78,6 @@ void BasicViewController::place() if(!view) return; assert(viewRect.xSize() && viewRect.ySize()); - view->waitForDrawFinished(); view->setViewRect(viewRect); view->place(); } @@ -101,8 +99,6 @@ ViewStack::ViewStack(ViewAttachParams attach): void ViewStack::setNavView(std::unique_ptr navView) { - if(view.size()) - top().waitForDrawFinished(); nav = std::move(navView); if(nav) { @@ -127,7 +123,6 @@ void ViewStack::place() { if(!view.size()) return; - top().waitForDrawFinished(); assert(viewRect.xSize() && viewRect.ySize()); customViewRect = viewRect; customDisplayRect = displayRect; @@ -248,7 +243,6 @@ void ViewStack::push(std::unique_ptr v, const Input::Event &e) assumeExpr(v); if(view.size()) { - top().waitForDrawFinished(); top().onHide(); } v->setController(this, e); @@ -282,8 +276,7 @@ void ViewStack::pop() { if(!view.size()) return; - top().waitForDrawFinished(); - view.back().v->onDismiss(); + view.back().ptr->onDismiss(); view.pop_back(); logMsg("pop view, %d in stack", (int)view.size()); if(nav) @@ -355,20 +348,20 @@ void ViewStack::show() View &ViewStack::top() const { assumeExpr(view.size()); - return *view.back().v; + return *view.back().ptr; } View &ViewStack::viewAtIdx(int idx) const { assumeExpr(size_t(idx) < view.size()); - return *view[idx].v; + return *view[idx].ptr; } int ViewStack::viewIdx(View &v) const { for(int i = 0; auto &viewEntry : view) { - if(viewEntry.v.get() == &v) + if(viewEntry.ptr.get() == &v) return i; i++; } @@ -379,7 +372,7 @@ int ViewStack::viewIdx(std::u16string_view name) const { for(int i = 0; auto &viewEntry : view) { - if(viewEntry.v->name() == name) + if(viewEntry.ptr->name() == name) return i; i++; } @@ -445,7 +438,7 @@ void ViewStack::dismissView(int idx, bool refreshLayout) else { logMsg("dismissing view at index:%d", idx); - view[idx].v->onDismiss(); + view[idx].ptr->onDismiss(); view.erase(view.begin() + idx); } } diff --git a/imagine/src/input/evdev/evdev.cc b/imagine/src/input/evdev/evdev.cc index e19b60a5c..3032ce6cf 100644 --- a/imagine/src/input/evdev/evdev.cc +++ b/imagine/src/input/evdev/evdev.cc @@ -14,7 +14,7 @@ along with Imagine. If not, see */ #include -#include +#include #include #include #include diff --git a/imagine/src/io/IO.cc b/imagine/src/io/IO.cc index f803ff247..289591586 100644 --- a/imagine/src/io/IO.cc +++ b/imagine/src/io/IO.cc @@ -51,6 +51,29 @@ std::span IO::map() }, *this); }; +ssize_t IO::writeVector(std::span buffs, std::optional offset) +{ + return visit([&](auto &io) -> ssize_t + { + if constexpr(requires {io.writeVector(buffs, offset);}) + return io.writeVector(buffs, offset); + else + { + ssize_t totalSize{}; + for(auto buff : buffs) + { + auto written = write(buff.data(), buff.size(), offset); + if(written == -1) + return -1; + totalSize += written; + if(offset) + *offset += written; + } + return totalSize; + } + }, *this); +} + bool IO::truncate(off_t offset) { return visit([&](auto &io) diff --git a/imagine/src/io/PosixIO.cc b/imagine/src/io/PosixIO.cc index b4fc5b6c3..1e2753027 100755 --- a/imagine/src/io/PosixIO.cc +++ b/imagine/src/io/PosixIO.cc @@ -13,11 +13,11 @@ You should have received a copy of the GNU General Public License along with Imagine. If not, see */ -#define LOGTAG "PosixIO" #include #include #include #include +#include #include #include #include "utils.hh" @@ -28,18 +28,29 @@ #include #include +#if defined __ANDROID__ && ANDROID_MIN_API < 24 +#include + +static ssize_t pwritev(int fd, const struct iovec* _Nonnull iov, int count, off_t offset) +{ + return syscall(__NR_pwritev, fd, iov, count, offset); +} +#endif + namespace IG { template class IOUtils; +constexpr SystemLogger log{"PosixIO"}; + #if !defined __linux__ constexpr int MAP_POPULATE = 0; #endif static auto flagsString(OpenFlags openFlags) { - IG::StaticString<5> logFlagsStr{}; + StaticString<5> logFlagsStr{}; if(openFlags.read) logFlagsStr += 'r'; if(openFlags.write) logFlagsStr += 'w'; if(openFlags.create) logFlagsStr += 'c'; @@ -49,7 +60,7 @@ static auto flagsString(OpenFlags openFlags) static auto protectionFlagsString(int flags) { - IG::StaticString<3> logFlagsStr{}; + StaticString<3> logFlagsStr{}; if(flags & PROT_READ) logFlagsStr += 'r'; if(flags & PROT_WRITE) logFlagsStr += 'w'; return logFlagsStr; @@ -90,14 +101,14 @@ PosixIO::PosixIO(CStringView path, OpenFlags openFlags) if((fd_ = ::open(path, flags, openMode)) == -1) [[unlikely]] { if constexpr(Config::DEBUG_BUILD) - logErr("error opening file (%s) @ %s:%s", flagsString(openFlags).data(), path.data(), strerror(errno)); + log.error("error opening file ({}) @ {}:{}", flagsString(openFlags), path, strerror(errno)); if(openFlags.test) return; else throw std::system_error{errno, std::system_category(), path}; } if constexpr(Config::DEBUG_BUILD) - logMsg("opened (%s) fd:%d @ %s", flagsString(openFlags).data(), fd(), path.data()); + log.info("opened ({}) fd:{} @ {}", flagsString(openFlags), fd(), path); } ssize_t PosixIO::read(void *buff, size_t bytes, std::optional offset) @@ -107,7 +118,7 @@ ssize_t PosixIO::read(void *buff, size_t bytes, std::optional offset) auto bytesRead = ::pread(fd(), buff, bytes, *offset); if(bytesRead == -1) [[unlikely]] { - logErr("error reading %zu bytes at offset %lld", bytes, (long long)*offset); + log.error("error reading {} bytes at offset:{}", bytes, *offset); } return bytesRead; } @@ -117,7 +128,7 @@ ssize_t PosixIO::read(void *buff, size_t bytes, std::optional offset) if(bytesRead == -1) [[unlikely]] { if(Config::DEBUG_BUILD && errno != EAGAIN) - logErr("error reading %zu bytes", bytes); + log.error("error reading %zu bytes", bytes); } return bytesRead; } @@ -130,7 +141,7 @@ ssize_t PosixIO::write(const void *buff, size_t bytes, std::optional offs auto bytesWritten = ::pwrite(fd(), buff, bytes, *offset); if(bytesWritten == -1) { - logErr("error writing %zu bytes at offset %lld", bytes, (long long)*offset); + log.error("error writing {} bytes at offset {}", bytes, *offset); } return bytesWritten; } @@ -139,7 +150,31 @@ ssize_t PosixIO::write(const void *buff, size_t bytes, std::optional offs auto bytesWritten = ::write(fd(), buff, bytes); if(bytesWritten == -1) { - logErr("error writing %zu bytes", bytes); + log.error("error writing {} bytes", bytes); + } + return bytesWritten; + } +} + +ssize_t PosixIO::writeVector(std::span buffs, std::optional offset) +{ + if(!buffs.size()) + return 0; + if(offset) + { + auto bytesWritten = ::pwritev(fd(), buffs.data()->iovecPtr(), buffs.size(), *offset); + if(bytesWritten == -1) + { + log.error("error writing {} buffers at offset {}", buffs.size(), *offset); + } + return bytesWritten; + } + else + { + auto bytesWritten = ::writev(fd(), buffs.data()->iovecPtr(), buffs.size()); + if(bytesWritten == -1) + { + log.error("error writing {} buffers", buffs.size()); } return bytesWritten; } @@ -147,10 +182,10 @@ ssize_t PosixIO::write(const void *buff, size_t bytes, std::optional offs bool PosixIO::truncate(off_t offset) { - logMsg("truncating at offset %lld", (long long)offset); + log.info("truncating at offset {}", offset); if(ftruncate(fd(), offset) == -1) [[unlikely]] { - logErr("truncate failed"); + log.error("truncate failed"); return false; } return true; @@ -161,7 +196,7 @@ off_t PosixIO::seek(off_t offset, SeekMode mode) auto newPos = lseek(fd(), offset, (int)mode); if(newPos == -1) [[unlikely]] { - logErr("seek to offset %lld failed", (long long)offset); + log.error("seek to offset {} failed", offset); return -1; } return newPos; @@ -177,7 +212,7 @@ size_t PosixIO::size() auto s = fd_size(fd()); if(s == 0) { - logMsg("fd:%d is empty or a stream", fd()); + log.info("fd:{} is empty or a stream", fd()); } return s; } @@ -210,7 +245,7 @@ void PosixIO::advise(off_t offset, size_t bytes, Advice advice) int fAdv = adviceToFAdv(advice); if(posix_fadvise(fd(), offset, bytes, fAdv) != 0) { - logMsg("fadvise for offset 0x%llX with size %zu failed", (unsigned long long)offset, bytes); + log.error("fadvise for offset:{:X} with size:{} failed", offset, bytes); } #endif #endif @@ -227,7 +262,7 @@ IOBuffer PosixIO::releaseBuffer() if(flags == -1) [[unlikely]] { if(Config::DEBUG_BUILD) - logErr("fcntl(%d) failed:%s", fd(), strerror(errno)); + log.error("fcntl({}) failed:{}", fd(), strerror(errno)); flags = 0; } bool isWritable = (flags & O_WRONLY) || (flags & O_RDWR); @@ -245,10 +280,10 @@ IOBuffer PosixIO::mapRange(off_t start, size_t size, IOMapFlags mapFlags) void *data = mmap(nullptr, size, prot, flags, fd(), start); if(data == MAP_FAILED) [[unlikely]] { - logErr("mmap (%s) fd:%d @ %zu (%zu bytes) failed", protectionFlagsString(prot).data(), fd(), (size_t)start, size); + log.error("mmap ({}) fd:{} @ {} ({} bytes) failed", protectionFlagsString(prot), fd(), start, size); return {}; } - logMsg("mapped (%s) fd:%d @ %zu to %p (%zu bytes)", protectionFlagsString(prot).data(), fd(), (size_t)start, data, size); + log.info("mapped ({}) fd:{} @ {} to {} ({} bytes)", protectionFlagsString(prot), fd(), start, data, size); return byteBufferFromMmap(data, size); } @@ -259,11 +294,11 @@ IOBuffer PosixIO::byteBufferFromMmap(void *data, size_t size) {(uint8_t*)data, size}, {.mappedFile = true}, [](const uint8_t *ptr, size_t size) { - logMsg("unmapping:%p (%zu bytes)", ptr, size); + log.info("unmapping:{} ({} bytes)", (void*)ptr, size); if(munmap((void*)ptr, size) == -1) { if(Config::DEBUG_BUILD) - logErr("munmap(%p, %zu) error:%s", ptr, size, strerror(errno)); + log.error("munmap({}, {}) error:{}", (void*)ptr, size, strerror(errno)); } } }; diff --git a/imagine/tests/FrameRateTest/src/main/TestPicker.cc b/imagine/tests/FrameRateTest/src/main/TestPicker.cc index 2420ee57c..da07dedf1 100644 --- a/imagine/tests/FrameRateTest/src/main/TestPicker.cc +++ b/imagine/tests/FrameRateTest/src/main/TestPicker.cc @@ -38,7 +38,7 @@ void TestPicker::setTests(const TestDesc *testDesc, unsigned tests) testParam.reserve(tests); for(auto i : iotaCount(tests)) { - testEntry.emplace_back(testDesc[i].name, u"", &defaultFace(), + testEntry.emplace_back(testDesc[i].name, u"", attachParams(), [this, i](IG::DualTextMenuItem &, IG::View &, IG::Input::Event e) { auto &app = mainApp(appContext()); diff --git a/imagine/tests/FrameRateTest/src/main/TestPicker.hh b/imagine/tests/FrameRateTest/src/main/TestPicker.hh index ef9473b64..0d8a8c584 100644 --- a/imagine/tests/FrameRateTest/src/main/TestPicker.hh +++ b/imagine/tests/FrameRateTest/src/main/TestPicker.hh @@ -31,8 +31,8 @@ public: void setTests(const TestDesc *testParams, unsigned tests); private: - std::vector testEntry{}; - std::vector testParam{}; + std::vector testEntry; + std::vector testParam; }; } diff --git a/imagine/tests/FrameRateTest/src/main/main.cc b/imagine/tests/FrameRateTest/src/main/main.cc index acebb420e..3490f0cad 100755 --- a/imagine/tests/FrameRateTest/src/main/main.cc +++ b/imagine/tests/FrameRateTest/src/main/main.cc @@ -13,7 +13,6 @@ You should have received a copy of the GNU General Public License along with Imagine. If not, see */ -#define LOGTAG "main" #include #include #include @@ -36,6 +35,8 @@ namespace FrameRateTest { +constexpr SystemLogger log{"main"}; + static constexpr unsigned framesToRun = 60*60; struct WindowData @@ -69,7 +70,6 @@ FrameRateTestApplication::FrameRateTestApplication(IG::ApplicationInitParams ini defaultFace.precacheAlphaNum(renderer); defaultFace.precache(renderer, ":.%()"); viewManager.defaultFace = std::move(defaultFace); - viewManager.quadIndices = {renderer.mainTask, 32}; auto &winData = win.makeAppData(IG::ViewAttachParams{viewManager, win, renderer.task()}); std::vector testDesc; testDesc.emplace_back(TEST_CLEAR, "Clear"); @@ -193,6 +193,7 @@ void FrameRateTestApplication::setActiveTestHandlers(IG::Window &win) { activeTest->started = true; } + activeTest->presentTime = params.presentTime(1); activeTest->lastFramePresentTime.timestamp = params.timestamp; activeTest->lastFramePresentTime.atOnFrame = atOnFrame; if(activeTest->frames == framesToRun || activeTest->shouldEndTest) @@ -226,8 +227,7 @@ void FrameRateTestApplication::setActiveTestHandlers(IG::Window &win) cmds.basicEffect().setModelViewProjection(cmds, Gfx::Mat4::ident(), winData.projM); activeTest->draw(cmds, cmds.renderer().makeClipRect(win, rect), xIndent); activeTest->lastFramePresentTime.atWinPresent = SteadyClock::now(); - activeTest->presentFence = cmds.clientWaitSyncReset(activeTest->presentFence); - cmds.present(); + cmds.present(activeTest->presentTime); }); }, [&](Input::Event &e) @@ -239,7 +239,7 @@ void FrameRateTestApplication::setActiveTestHandlers(IG::Window &win) { if(motionEv.pushed() && Config::envIsIOS) { - logMsg("canceled activeTest from pointer input"); + log.info("canceled activeTest from pointer input"); activeTest->shouldEndTest = true; return true; } @@ -249,13 +249,13 @@ void FrameRateTestApplication::setActiveTestHandlers(IG::Window &win) { if(keyEv.pushed(Input::DefaultKey::CANCEL)) { - logMsg("canceled activeTest from key input"); + log.info("canceled activeTest from key input"); activeTest->shouldEndTest = true; return true; } else if(keyEv.pushed(IG::Input::Keycode::D)) { - logMsg("posting extra draw"); + log.info("posting extra draw"); win.postDraw(); return true; } @@ -293,7 +293,7 @@ void FrameRateTestApplication::finishTest(Window &win, SteadyClockTimePoint fram { activeTest->finish(renderer.task(), frameTime); } - renderer.task().awaitPending(); + renderer.mainTask.awaitPending(); activeTest.reset(); deinitCPUFreqStatus(); deinitCPULoadStatus(); @@ -310,26 +310,25 @@ void FrameRateTestApplication::finishTest(Window &win, SteadyClockTimePoint fram TestFramework *FrameRateTestApplication::startTest(IG::Window &win, const TestParams &t) { - auto &face = viewManager.defaultFace; - auto app = win.appContext(); + auto ctx = win.appContext(); #ifdef __ANDROID__ if(cpuFreq) cpuFreq->setLowLatency(); - app.setSustainedPerformanceMode(true); + ctx.setSustainedPerformanceMode(true); #endif + ViewAttachParams attach{viewManager, win, renderer.task()}; auto &activeTest = windowData(win).activeTest; activeTest = [&] -> std::unique_ptr { switch(t.test) { - case TEST_CLEAR: return std::make_unique(); - case TEST_DRAW: return std::make_unique(); - case TEST_WRITE: return std::make_unique(); + case TEST_CLEAR: return std::make_unique(attach); + case TEST_DRAW: return std::make_unique(ctx, attach, t.pixmapSize, t.bufferMode); + case TEST_WRITE: return std::make_unique(ctx, attach, t.pixmapSize, t.bufferMode); } bug_unreachable("invalid TestID"); }(); - activeTest->init(app, renderer, face, t.pixmapSize, t.bufferMode); - app.setIdleDisplayPowerSave(false); + ctx.setIdleDisplayPowerSave(false); initCPUFreqStatus(); initCPULoadStatus(); placeElements(win); diff --git a/imagine/tests/FrameRateTest/src/main/tests.cc b/imagine/tests/FrameRateTest/src/main/tests.cc index a739202b5..c892ac98e 100644 --- a/imagine/tests/FrameRateTest/src/main/tests.cc +++ b/imagine/tests/FrameRateTest/src/main/tests.cc @@ -15,6 +15,7 @@ #define LOGTAG "test" #include +#include #include #include #include @@ -39,14 +40,10 @@ const char *testIDToStr(TestID id) } } -void TestFramework::init(ApplicationContext ctx, Gfx::Renderer &r, - Gfx::GlyphTextureSet &face, WSize pixmapSize, Gfx::TextureBufferMode bufferMode) -{ - cpuStatsText = {&face}; - frameStatsText = {&face}; - statsRectQuads = {r.mainTask, {.size = 2}}; - initTest(ctx, r, pixmapSize, bufferMode); -} +TestFramework::TestFramework(ViewAttachParams attach): + statsRectQuads{attach.rendererTask, {.size = 2}}, + cpuStatsText{attach.rendererTask, &attach.viewManager.defaultFace}, + frameStatsText{attach.rendererTask, &attach.viewManager.defaultFace} {} void TestFramework::setCPUFreqText(std::string_view str) { @@ -60,9 +57,9 @@ void TestFramework::setCPUUseText(std::string_view str) cpuUseStr += str; } -void TestFramework::placeCPUStatsText(Gfx::Renderer &r) +void TestFramework::placeCPUStatsText() { - if(cpuStatsText.compile(r)) + if(cpuStatsText.compile()) { cpuStatsRect = viewBounds; cpuStatsRect.y2 = (cpuStatsRect.y + cpuStatsText.nominalHeight() * cpuStatsText.currentLines()) @@ -71,9 +68,9 @@ void TestFramework::placeCPUStatsText(Gfx::Renderer &r) } } -void TestFramework::placeFrameStatsText(Gfx::Renderer &r) +void TestFramework::placeFrameStatsText() { - if(frameStatsText.compile(r, {.maxLineSize = viewBounds.xSize()})) + if(frameStatsText.compile({.maxLineSize = viewBounds.xSize()})) { frameStatsRect = viewBounds; frameStatsRect.y = (frameStatsRect.y2 - frameStatsText.nominalHeight() * frameStatsText.currentLines()) @@ -85,8 +82,8 @@ void TestFramework::placeFrameStatsText(Gfx::Renderer &r) void TestFramework::place(Gfx::Renderer &r, WRect viewBounds_, WRect testRect) { viewBounds = viewBounds_; - placeCPUStatsText(r); - placeFrameStatsText(r); + placeCPUStatsText(); + placeFrameStatsText(); placeTest(testRect); } @@ -114,7 +111,7 @@ void TestFramework::frameUpdate(Gfx::RendererTask &rTask, IG::Window &win, IG::F str += '\n'; str += cpuFreqStr; cpuStatsText.resetString(str); - placeCPUStatsText(rTask.renderer()); + placeCPUStatsText(); } // frame stats @@ -157,7 +154,7 @@ void TestFramework::frameUpdate(Gfx::RendererTask &rTask, IG::Window &win, IG::F str += '\n'; str += statsStr; frameStatsText.resetString(str); - placeFrameStatsText(rTask.renderer()); + placeFrameStatsText(); } } // run frame @@ -166,10 +163,10 @@ void TestFramework::frameUpdate(Gfx::RendererTask &rTask, IG::Window &win, IG::F continuousFrames++; } -void TestFramework::prepareDraw(Gfx::Renderer &r) +void TestFramework::prepareDraw() { - cpuStatsText.makeGlyphs(r); - frameStatsText.makeGlyphs(r); + cpuStatsText.makeGlyphs(); + frameStatsText.makeGlyphs(); } void TestFramework::draw(Gfx::RendererCommands &cmds, Gfx::ClipRect bounds, int xIndent) @@ -203,8 +200,6 @@ void TestFramework::draw(Gfx::RendererCommands &cmds, Gfx::ClipRect bounds, int void TestFramework::finish(Gfx::RendererTask &task, SteadyClockTimePoint frameTime) { endTime = frameTime; - task.deleteSyncFence(presentFence); - presentFence = {}; if(onTestFinished) onTestFinished(*this); } @@ -233,23 +228,24 @@ void ClearTest::drawTest(Gfx::RendererCommands &cmds, Gfx::ClipRect) } } -void DrawTest::initTest(IG::ApplicationContext app, Gfx::Renderer &r, WSize pixmapSize, Gfx::TextureBufferMode bufferMode) +DrawTest::DrawTest(IG::ApplicationContext ctx, ViewAttachParams attach, WSize pixmapSize, Gfx::TextureBufferMode bufferMode): + TestFramework{attach}, + quad{attach.rendererTask, {.size = 1}} { using namespace IG::Gfx; + auto &r = attach.renderer(); IG::PixmapDesc pixmapDesc = {pixmapSize, IG::PIXEL_FMT_RGB565}; TextureConfig texConf{pixmapDesc, SamplerConfigs::noMipClamp}; - const bool canSingleBuffer = r.maxSwapChainImages() < 3 || r.supportsSyncFences(); - texture = r.makePixmapBufferTexture(texConf, bufferMode, canSingleBuffer); + texture = r.makePixmapBufferTexture(texConf, bufferMode); if(!texture) [[unlikely]] { - app.exitWithMessage(-1, "Can't init test texture"); + ctx.exitWithMessage(-1, "Can't init test texture"); return; } auto lockedBuff = texture.lock(); assert(lockedBuff); memset(lockedBuff.pixmap().data(), 0xFF, lockedBuff.pixmap().bytes()); texture.unlock(lockedBuff); - quad = {r.mainTask, {.size = 1}}; } void DrawTest::placeTest(WRect rect) @@ -286,7 +282,6 @@ void DrawTest::drawTest(Gfx::RendererCommands &cmds, Gfx::ClipRect bounds) void WriteTest::frameUpdateTest(Gfx::RendererTask &rendererTask, Screen &screen, SteadyClockTimePoint frameTime) { DrawTest::frameUpdateTest(rendererTask, screen, frameTime); - rendererTask.clientWaitSync(std::exchange(presentFence, {})); auto lockedBuff = texture.lock(); auto pix = lockedBuff.pixmap(); if(flash) diff --git a/imagine/tests/FrameRateTest/src/main/tests.hh b/imagine/tests/FrameRateTest/src/main/tests.hh index f5fd36797..82015b6b1 100644 --- a/imagine/tests/FrameRateTest/src/main/tests.hh +++ b/imagine/tests/FrameRateTest/src/main/tests.hh @@ -81,23 +81,21 @@ public: unsigned frames{}; unsigned droppedFrames{}; unsigned continuousFrames{}; + SteadyClockTimePoint presentTime{}; SteadyClockTimePoint startTime{}, endTime{}; TestFinishedDelegate onTestFinished; FramePresentTime lastFramePresentTime; - Gfx::SyncFence presentFence{}; Gfx::IQuads statsRectQuads; - TestFramework() {} + TestFramework(ViewAttachParams); virtual ~TestFramework() {} - virtual void initTest(IG::ApplicationContext, Gfx::Renderer &, WSize pixmapSize, Gfx::TextureBufferMode) {} virtual void placeTest(WRect testRect) {} virtual void frameUpdateTest(Gfx::RendererTask &, Screen &, SteadyClockTimePoint) = 0; virtual void drawTest(Gfx::RendererCommands &cmds, Gfx::ClipRect bounds) = 0; virtual void presentedTest(Gfx::RendererCommands &cmds) {} - void init(IG::ApplicationContext, Gfx::Renderer &, Gfx::GlyphTextureSet &face, WSize pixmapSize, Gfx::TextureBufferMode); void place(Gfx::Renderer &r, WRect viewBounds, WRect testRect); void frameUpdate(Gfx::RendererTask &rTask, IG::Window &win, IG::FrameParams frameParams); - void prepareDraw(Gfx::Renderer &r); + void prepareDraw(); void draw(Gfx::RendererCommands &cmds, Gfx::ClipRect bounds, int xIndent); void finish(Gfx::RendererTask &, SteadyClockTimePoint); void setCPUFreqText(std::string_view str); @@ -106,17 +104,17 @@ public: protected: Gfx::Text cpuStatsText; Gfx::Text frameStatsText; - std::string cpuFreqStr{}; - std::string cpuUseStr{}; - std::string skippedFrameStr{}; - std::string statsStr{}; + std::string cpuFreqStr; + std::string cpuUseStr; + std::string skippedFrameStr; + std::string statsStr; WRect viewBounds{}; WRect cpuStatsRect{}; WRect frameStatsRect{}; unsigned lostFrameProcessTime{}; - void placeCPUStatsText(Gfx::Renderer &r); - void placeFrameStatsText(Gfx::Renderer &r); + void placeCPUStatsText(); + void placeFrameStatsText(); }; class ClearTest : public TestFramework @@ -125,6 +123,7 @@ protected: bool flash{true}; public: + using TestFramework::TestFramework; void frameUpdateTest(Gfx::RendererTask &, Screen &, SteadyClockTimePoint) override; void drawTest(Gfx::RendererCommands &cmds, Gfx::ClipRect bounds) override; }; @@ -137,7 +136,7 @@ protected: Gfx::PixmapBufferTexture texture; public: - void initTest(IG::ApplicationContext, Gfx::Renderer &, WSize pixmapSize, Gfx::TextureBufferMode) override; + DrawTest(IG::ApplicationContext, ViewAttachParams attach, WSize pixmapSize, Gfx::TextureBufferMode); void placeTest(WRect testRect) override; void frameUpdateTest(Gfx::RendererTask &, Screen &, SteadyClockTimePoint) override; void drawTest(Gfx::RendererCommands &cmds, Gfx::ClipRect bounds) override; @@ -146,6 +145,7 @@ public: class WriteTest : public DrawTest { public: + using DrawTest::DrawTest; void frameUpdateTest(Gfx::RendererTask &, Screen &, SteadyClockTimePoint) override; void drawTest(Gfx::RendererCommands &cmds, Gfx::ClipRect bounds) override; };