diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 94fae8e6e..737640cb3 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -613,7 +613,7 @@ FBInitStatus Console::initializeVideo(bool full) const string& title = string("Stella ") + STELLA_VERSION + ": \"" + myProperties.get(PropType::Cart_Name) + "\""; fbstatus = myOSystem.frameBuffer().createDisplay(title, - TIAConstants::viewableWidth, TIAConstants::viewableHeight); + TIAConstants::viewableWidth, TIAConstants::viewableHeight, false); if(fbstatus != FBInitStatus::Success) return fbstatus; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index a12f9bc64..1cb4142ed 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -53,6 +53,7 @@ FrameBuffer::FrameBuffer(OSystem& osystem) myStatsEnabled(false), myLastScanlines(0), myGrabMouse(false), + myHiDPIEnabled(false), myCurrentModeList(nullptr) { } @@ -79,8 +80,22 @@ bool FrameBuffer::initialize() query_h = s.h; } // Various parts of the codebase assume a minimum screen size - myDesktopSize.w = std::max(query_w, FBMinimum::Width); - myDesktopSize.h = std::max(query_h, FBMinimum::Height); + myAbsDesktopSize.w = std::max(query_w, FBMinimum::Width); + myAbsDesktopSize.h = std::max(query_h, FBMinimum::Height); + myDesktopSize = myAbsDesktopSize; + + // Check for HiDPI mode (is it activated, and can we use it?) + myHiDPIEnabled = myOSystem.settings().getBool("hidpi") && + ((myAbsDesktopSize.w / 2) >= FBMinimum::Width) && + ((myAbsDesktopSize.h / 2) >= FBMinimum::Height); + + // In HiDPI mode, the desktop resolution is essentially halved + // Later, the output is scaled and rendered in 2x mode + if(hidpiEnabled()) + { + myDesktopSize.w = myAbsDesktopSize.w / hidpiScaleFactor(); + myDesktopSize.h = myAbsDesktopSize.h / hidpiScaleFactor(); + } #ifdef GUI_SUPPORT //////////////////////////////////////////////////////////////////// @@ -121,12 +136,11 @@ bool FrameBuffer::initialize() #endif // Determine possible TIA windowed zoom levels + uInt32 minZoom = 2 * hidpiScaleFactor(); uInt32 maxZoom = maxWindowSizeForScreen( TIAConstants::viewableWidth, TIAConstants::viewableHeight, - myDesktopSize.w, myDesktopSize.h); - - // Figure our the smallest zoom level we can use - for(uInt32 zoom = 2; zoom <= maxZoom; ++zoom) + myAbsDesktopSize.w, myAbsDesktopSize.h); + for(uInt32 zoom = minZoom; zoom <= maxZoom; ++zoom) { ostringstream desc; desc << "Zoom " << zoom << "x"; @@ -166,11 +180,19 @@ void FrameBuffer::setUIPalette() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus FrameBuffer::createDisplay(const string& title, - uInt32 width, uInt32 height) + uInt32 width, uInt32 height, + bool honourHiDPI) { ++myInitializedCount; myScreenTitle = title; + // In HiDPI mode, all created displays must be scaled by 2x + if(honourHiDPI && hidpiEnabled()) + { + width *= hidpiScaleFactor(); + height *= hidpiScaleFactor(); + } + // A 'windowed' system is defined as one where the window size can be // larger than the screen size, as there's some sort of window manager // that takes care of it (all current desktop systems fall in this category) @@ -245,9 +267,10 @@ FBInitStatus FrameBuffer::createDisplay(const string& title, myMsg.counter = 0; // Create surfaces for TIA statistics and general messages + const GUI::Font& f = hidpiEnabled() ? infoFont() : font(); myStatsMsg.color = kColorInfo; - myStatsMsg.w = font().getMaxCharWidth() * 40 + 3; - myStatsMsg.h = (font().getFontHeight() + 2) * 3; + myStatsMsg.w = f.getMaxCharWidth() * 40 + 3; + myStatsMsg.h = (f.getFontHeight() + 2) * 3; if(!myStatsMsg.surface) { @@ -427,7 +450,7 @@ void FrameBuffer::showMessage(const string& message, MessagePosition position, myMsg.w = font().getStringWidth(myMsg.text) + 10; myMsg.h = font().getFontHeight() + 8; myMsg.surface->setSrcSize(myMsg.w, myMsg.h); - myMsg.surface->setDstSize(myMsg.w, myMsg.h); + myMsg.surface->setDstSize(myMsg.w * hidpiScaleFactor(), myMsg.h * hidpiScaleFactor()); myMsg.position = position; myMsg.enabled = true; #endif @@ -439,7 +462,8 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) #ifdef GUI_SUPPORT const ConsoleInfo& info = myOSystem.console().about(); int xPos = 2, yPos = 0; - const int dy = font().getFontHeight() + 2; + const GUI::Font& f = hidpiEnabled() ? infoFont() : font(); + const int dy = f.getFontHeight() + 2; ostringstream ss; @@ -456,7 +480,7 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) << "Hz => " << info.DisplayFormat; - myStatsMsg.surface->drawString(font(), ss.str(), xPos, yPos, + myStatsMsg.surface->drawString(f, ss.str(), xPos, yPos, myStatsMsg.w, color, TextAlign::Left, 0, true, kBGColor); yPos += dy; @@ -468,7 +492,7 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) << std::fixed << std::setprecision(0) << 100 * myOSystem.settings().getFloat("speed") << "% speed"; - myStatsMsg.surface->drawString(font(), ss.str(), xPos, yPos, + myStatsMsg.surface->drawString(f, ss.str(), xPos, yPos, myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); yPos += dy; @@ -477,10 +501,12 @@ void FrameBuffer::drawFrameStats(float framesPerSecond) ss << info.BankSwitch; if (myOSystem.settings().getBool("dev.settings")) ss << "| Developer"; - myStatsMsg.surface->drawString(font(), ss.str(), xPos, yPos, - myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); + myStatsMsg.surface->drawString(f, ss.str(), xPos, yPos, + myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); myStatsMsg.surface->setDstPos(myImageRect.x() + 10, myImageRect.y() + 8); + myStatsMsg.surface->setDstSize(myStatsMsg.w * hidpiScaleFactor(), + myStatsMsg.h * hidpiScaleFactor()); myStatsMsg.surface->render(); #endif } @@ -850,8 +876,9 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) if(tiaMode) { // TIA windowed modes + uInt32 minZoom = 2 * hidpiScaleFactor(); uInt32 maxZoom = maxWindowSizeForScreen(baseWidth, baseHeight, - myDesktopSize.w, myDesktopSize.h); + myAbsDesktopSize.w, myAbsDesktopSize.h); #if 0 // FIXME - does this apply any longer?? // Aspect ratio @@ -861,7 +888,7 @@ void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) #endif // Determine all zoom levels - for(uInt32 zoom = 2; zoom <= maxZoom; ++zoom) + for(uInt32 zoom = minZoom; zoom <= maxZoom; ++zoom) { ostringstream desc; desc << "Zoom " << zoom << "x"; diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 3ecc80e74..a0e7484bb 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -104,10 +104,14 @@ class FrameBuffer @param title The title of the application / window @param width The width of the framebuffer @param height The height of the framebuffer + @param honourHiDPI If true, consult the 'hidpi' setting and enlarge + the display size accordingly; if false, use the + exact dimensions as given @return Status of initialization (see FBInitStatus 'enum') */ - FBInitStatus createDisplay(const string& title, uInt32 width, uInt32 height); + FBInitStatus createDisplay(const string& title, uInt32 width, uInt32 height, + bool honourHiDPI = true); /** Updates the display, which depending on the current mode could mean @@ -255,6 +259,13 @@ class FrameBuffer */ void stateChanged(EventHandlerState state); + /** + Answer whether hidpi mode is enabled. In this mode, all FBSurfaces + are scaled to 2x normal size. + */ + bool hidpiEnabled() const { return myHiDPIEnabled; } + uInt32 hidpiScaleFactor() const { return myHiDPIEnabled ? 2 : 1; } + #ifdef GUI_SUPPORT /** Get the font object(s) of the framebuffer @@ -498,8 +509,13 @@ class FrameBuffer Common::Size myScreenSize; // Maximum dimensions of the desktop area + // Note that this takes 'hidpi' mode into account, so in some cases + // it will be less than the absolute desktop size Common::Size myDesktopSize; + // Maximum absolute dimensions of the desktop area + Common::Size myAbsDesktopSize; + // The resolution of the attached displays in fullscreen mode // The primary display is typically the first in the array // Windowed modes use myDesktopSize directly @@ -546,6 +562,7 @@ class FrameBuffer uInt32 myLastScanlines; bool myGrabMouse; + bool myHiDPIEnabled; // The list of all available video modes for this framebuffer VideoModeList* myCurrentModeList; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index a6bfa5657..a5133e229 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -41,6 +41,7 @@ Settings::Settings() setPermanent("center", "false"); setPermanent("palette", "standard"); setPermanent("uimessages", "true"); + setPermanent("hidpi", "false"); // TIA specific options setPermanent("tia.zoom", "3"); diff --git a/src/gui/Dialog.cxx b/src/gui/Dialog.cxx index e50ef7c9c..0574ed1fa 100644 --- a/src/gui/Dialog.cxx +++ b/src/gui/Dialog.cxx @@ -100,6 +100,9 @@ void Dialog::open() _surface = instance().frameBuffer().allocateSurface(_w, _h); _layer = parent().addDialog(this); + if(instance().frameBuffer().hidpiEnabled()) + _surface->setDstSize(_w*2, _h*2); + center(); if(_myTabList.size()) diff --git a/src/gui/LauncherDialog.cxx b/src/gui/LauncherDialog.cxx index 1b7a50c99..7636f6bb7 100644 --- a/src/gui/LauncherDialog.cxx +++ b/src/gui/LauncherDialog.cxx @@ -459,11 +459,8 @@ void LauncherDialog::handleKeyDown(StellaKey key, StellaMod mod) // Control-R (reload ROM listing) if(StellaModTest::isControl(mod) && key == KBDK_R) updateListing(); - // FIXME - use the R77 define in the final release - // use the '1' define for testing - #if defined(RETRON77) -// #if 1 else +#if defined(RETRON77) // handle keys used by R77 switch(key) { @@ -489,10 +486,9 @@ void LauncherDialog::handleKeyDown(StellaKey key, StellaMod mod) Dialog::handleKeyDown(key, mod); break; } - #else - else +#else Dialog::handleKeyDown(key, mod); - #endif +#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gui/RomInfoWidget.cxx b/src/gui/RomInfoWidget.cxx index 5b523b1c6..1d900e314 100644 --- a/src/gui/RomInfoWidget.cxx +++ b/src/gui/RomInfoWidget.cxx @@ -110,7 +110,8 @@ void RomInfoWidget::parseProperties(const FilesystemNode& node) // Scale surface to available image area const Common::Rect& src = mySurface->srcRect(); - float scale = std::min(float(myAvail.w) / src.width(), float(myAvail.h) / src.height()); + float scale = std::min(float(myAvail.w) / src.width(), float(myAvail.h) / src.height()) * + instance().frameBuffer().hidpiScaleFactor(); mySurface->setDstSize(uInt32(src.width() * scale), uInt32(src.height() * scale)); mySurfaceIsValid = true; } @@ -179,8 +180,9 @@ void RomInfoWidget::drawWidget(bool hilite) if(mySurfaceIsValid) { const Common::Rect& dst = mySurface->dstRect(); - uInt32 x = _x + ((_w - dst.width()) >> 1); - uInt32 y = _y + ((yoff - dst.height()) >> 1); + const uInt32 scale = instance().frameBuffer().hidpiScaleFactor(); + uInt32 x = _x*scale + ((_w*scale - dst.width()) >> 1); + uInt32 y = _y*scale + ((yoff*scale - dst.height()) >> 1); // Make sure when positioning the snapshot surface that we take // the dialog surface position into account