From 9e268dda0c395b29ca20be096e117c08fcd4cdc5 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Thu, 17 Aug 2023 18:18:15 +0200 Subject: [PATCH] first try --- src/common/FBBackendSDL2.hxx | 3 ++ src/common/FBSurfaceSDL2.cxx | 2 + src/common/PNGLibrary.cxx | 1 + src/common/VideoModeHandler.cxx | 34 ++++++++++------- src/common/VideoModeHandler.hxx | 4 +- src/emucore/FrameBuffer.cxx | 68 ++++++++++++++++++++++++++++++++- src/emucore/FrameBuffer.hxx | 10 ++++- src/emucore/Settings.cxx | 1 + src/emucore/TIASurface.cxx | 2 +- 9 files changed, 106 insertions(+), 19 deletions(-) diff --git a/src/common/FBBackendSDL2.hxx b/src/common/FBBackendSDL2.hxx index 003ad3386..76098d971 100644 --- a/src/common/FBBackendSDL2.hxx +++ b/src/common/FBBackendSDL2.hxx @@ -268,6 +268,9 @@ class FBBackendSDL2 : public FBBackend // Center setting of current window bool myCenter{false}; + // Flag for bezel mode + bool myShowBezel{false}; + // Does the renderer support render targets? bool myRenderTargetSupport{false}; diff --git a/src/common/FBSurfaceSDL2.cxx b/src/common/FBSurfaceSDL2.cxx index c156b83ba..288341b4f 100644 --- a/src/common/FBSurfaceSDL2.cxx +++ b/src/common/FBSurfaceSDL2.cxx @@ -48,6 +48,7 @@ FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend, : myBackend{backend}, myInterpolationMode{inter} { + //cerr << width << " x " << height << endl; createSurface(width, height, staticData); } @@ -233,6 +234,7 @@ void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height, mySurface = SDL_CreateRGBSurface(0, width, height, pf.BitsPerPixel, pf.Rmask, pf.Gmask, pf.Bmask, pf.Amask); + //SDL_SetSurfaceBlendMode(mySurface, SDL_BLENDMODE_ADD); // default: SDL_BLENDMODE_BLEND // We start out with the src and dst rectangles containing the same // dimensions, indicating no scaling or re-positioning diff --git a/src/common/PNGLibrary.cxx b/src/common/PNGLibrary.cxx index 2c530714f..56459aab5 100644 --- a/src/common/PNGLibrary.cxx +++ b/src/common/PNGLibrary.cxx @@ -35,6 +35,7 @@ PNGLibrary::PNGLibrary(OSystem& osystem) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::loadImage(const string& filename, FBSurface& surface, VariantList& metaData) { + png_structp png_ptr{nullptr}; png_infop info_ptr{nullptr}; png_uint_32 iwidth{0}, iheight{0}; diff --git a/src/common/VideoModeHandler.cxx b/src/common/VideoModeHandler.cxx index 3f969ad3d..fcc1275dd 100644 --- a/src/common/VideoModeHandler.cxx +++ b/src/common/VideoModeHandler.cxx @@ -33,9 +33,10 @@ void VideoModeHandler::setDisplaySize(const Common::Size& display, Int32 fsIndex // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const VideoModeHandler::Mode& -VideoModeHandler::buildMode(const Settings& settings, bool inTIAMode) + VideoModeHandler::buildMode(const Settings& settings, bool inTIAMode) { const bool windowedRequested = myFSIndex == -1; + const bool showBezel = inTIAMode&& settings.getBool("showbezel"); // TIA mode allows zooming at non-integral factors in most cases if(inTIAMode) @@ -49,14 +50,14 @@ VideoModeHandler::buildMode(const Settings& settings, bool inTIAMode) // Image and screen (aka window) dimensions are the same // Overscan is not applicable in this mode myMode = Mode(myImage.w * zoom, myImage.h * zoom, Mode::Stretch::Fill, - myFSIndex, desc.str(), zoom); + myFSIndex, desc.str(), zoom, showBezel); } else { const float overscan = 1 - settings.getInt("tia.fs_overscan") / 100.0; // First calculate maximum zoom that keeps aspect ratio - const float scaleX = static_cast(myImage.w) / myDisplay.w, + const float scaleX = myImage.w / myDisplay.w, scaleY = static_cast(myImage.h) / myDisplay.h; float zoom = 1.F / std::max(scaleX, scaleY); @@ -67,17 +68,19 @@ VideoModeHandler::buildMode(const Settings& settings, bool inTIAMode) if(!settings.getBool("tia.fs_stretch")) // preserve aspect, use all space { - myMode = Mode(myImage.w * zoom, myImage.h * zoom, + myMode = Mode(myImage.w * zoom, myImage.h * zoom, myDisplay.w, myDisplay.h, Mode::Stretch::Preserve, myFSIndex, - "Fullscreen: Preserve aspect, no stretch", zoom, overscan); + "Fullscreen: Preserve aspect, no stretch", + zoom, overscan, showBezel); } else // ignore aspect, use all space { myMode = Mode(myImage.w * zoom, myImage.h * zoom, myDisplay.w, myDisplay.h, Mode::Stretch::Fill, myFSIndex, - "Fullscreen: Ignore aspect, full stretch", zoom, overscan); + "Fullscreen: Ignore aspect, full stretch", + zoom, overscan, showBezel); } } } @@ -96,38 +99,41 @@ VideoModeHandler::buildMode(const Settings& settings, bool inTIAMode) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, Stretch smode, Int32 fsindex, string_view desc, - float zoomLevel) - : Mode(iw, ih, iw, ih, smode, fsindex, desc, zoomLevel) + float zoomLevel, bool showBezel) + : Mode(iw, ih, iw, ih, smode, fsindex, desc, zoomLevel, 1.F, showBezel) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, Stretch smode, Int32 fsindex, string_view desc, - float zoomLevel, float overscan) + float zoomLevel, float overscan, bool showBezel) : screenS{sw, sh}, stretch{smode}, description{desc}, zoom{zoomLevel}, fsIndex{fsindex} { + const float scaleW = showBezel ? (16.F / 9.F) / (4.F / 3.F) : 1; + //const Int32 imageW = iw * scaleW; + //screenS.w = screenS.w * scaleW; // Now resize based on windowed/fullscreen mode and stretch factor if(fsIndex != -1) // fullscreen mode { switch(stretch) { case Stretch::Preserve: - iw *= overscan; + iw *= overscan / scaleW; ih *= overscan; break; case Stretch::Fill: // Scale to all available space - iw = screenS.w * overscan; + iw = screenS.w * (overscan / scaleW); ih = screenS.h * overscan; break; - case Stretch::None: + case Stretch::None: // UI Mode // Don't do any scaling at all iw = std::min(iw, screenS.w) * overscan; ih = std::min(ih, screenS.h) * overscan; @@ -142,11 +148,11 @@ VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, { case Stretch::Preserve: case Stretch::Fill: - screenS.w = iw; + screenS.w = iw * scaleW; screenS.h = ih; break; - case Stretch::None: + case Stretch::None: // UI Mode break; // Do not change image or screen rects whatsoever } } diff --git a/src/common/VideoModeHandler.hxx b/src/common/VideoModeHandler.hxx index f3c62c91d..5ff15dfba 100644 --- a/src/common/VideoModeHandler.hxx +++ b/src/common/VideoModeHandler.hxx @@ -50,9 +50,9 @@ class VideoModeHandler Mode() = default; Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, Stretch smode, Int32 fsindex = -1, string_view desc = "", - float zoomLevel = 1.F, float overscan = 1.F); + float zoomLevel = 1.F, float overscan = 1.F, bool showBezel = false); Mode(uInt32 iw, uInt32 ih, Stretch smode, Int32 fsindex = -1, - string_view desc = "", float zoomLevel = 1.F); + string_view desc = "", float zoomLevel = 1.F, bool showBezel = false); friend ostream& operator<<(ostream& os, const Mode& vm) { diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 9eef64bc9..9fe62f406 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -27,6 +27,7 @@ #include "Sound.hxx" #include "AudioSettings.hxx" #include "MediaFactory.hxx" +#include "PNGLibrary.hxx" #include "FBSurface.hxx" #include "TIASurface.hxx" @@ -70,6 +71,8 @@ FrameBuffer::FrameBuffer(OSystem& osystem) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBuffer::~FrameBuffer() // NOLINT (we need an empty d'tor) { + if(myBezelSurface) + deallocateSurface(myBezelSurface); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -605,6 +608,7 @@ void FrameBuffer::updateInEmulationMode(float framesPerSecond) if(myMsg.enabled) drawMessage(); + myBezelSurface->render(); // Push buffers to screen myBackend->renderToScreen(); } @@ -1303,6 +1307,23 @@ FBInitStatus FrameBuffer::applyVideoMode() myOSystem.settings().setValue("tia.zoom", myActiveVidMode.zoom); } + if(inTIAMode) + { + if(myBezelSurface) + deallocateSurface(myBezelSurface); + + myBezelSurface = allocateSurface( + myActiveVidMode.screenS.w, + myActiveVidMode.screenS.h); + + // Get a valid filename representing a snapshot file for this rom and load the snapshot + const string& path = myOSystem.snapshotLoadDir().getPath(); + + //loadBezel(path + "Atari-2600.png"); + //loadBezel(path + "Combat.png"); + loadBezel(path + "Asteroids (USA).png"); + } + resetSurfaces(); setCursorState(); myPendingRender = true; @@ -1316,16 +1337,61 @@ FBInitStatus FrameBuffer::applyVideoMode() return status; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool FrameBuffer::loadBezel(const string& fileName) +{ + try + { + VariantList metaData; + myOSystem.png().loadImage(fileName, *myBezelSurface, metaData); + + // Scale surface to available image area + const Common::Rect& src = myBezelSurface->srcRect(); + const float scale = std::min( + static_cast(myActiveVidMode.screenS.w) / src.w(), + static_cast(myActiveVidMode.screenS.h) / src.h() + ) * myOSystem.frameBuffer().hidpiScaleFactor(); + myBezelSurface->setDstSize( + static_cast(std::round(src.w() * scale)), + static_cast(round(src.h() * scale))); + //myActiveVidMode.screenS.w, + //myActiveVidMode.screenS.h); + myBezelSurface->setScalingInterpolation(ScalingInterpolation::sharp); + + //Int32 w = round(src.w() * scale); + //Int32 h = round(src.h() * scale); + //cerr << scale << ": " << w << " x " << h << endl; + + //// temp workaround: + //FBSurface::Attributes& attr = myBezelSurface->attributes(); + //attr.blendalpha = 50; // 0..100 + //attr.blending = true; + //myBezelSurface->applyAttributes(); + ////SDL_SetSurfaceBlendMode(myBezelSurface, SDL_BLENDMODE_BLEND); + + if(myBezelSurface) + myBezelSurface->setVisible(true); + } + catch(const runtime_error&) + { + return false; + } + return true; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - float FrameBuffer::maxWindowZoom() const { const int display = displayId(BufferType::Emulator); float multiplier = 1; + const bool showBezel = myOSystem.settings().getBool("showbezel"); + const double scaleW = showBezel ? (16. / 9.) / (4. / 3.) : 1; // = 1.333 + for(;;) { // Figure out the zoomed size of the window - const uInt32 width = TIAConstants::viewableWidth * multiplier; + const uInt32 width = TIAConstants::viewableWidth * multiplier * scaleW; const uInt32 height = TIAConstants::viewableHeight * multiplier; if((width > myAbsDesktopSize[display].w) || (height > myAbsDesktopSize[display].h)) diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 475ba04f9..7ec5b5c62 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -443,6 +443,11 @@ class FrameBuffer */ FBInitStatus applyVideoMode(); + /** + Load the bezel for the given ROM filename. + */ + bool loadBezel(const string& romFileName); + /** Calculate the maximum level by which the base window can be zoomed and still fit in the desktop screen. @@ -519,7 +524,10 @@ class FrameBuffer #endif // The TIASurface class takes responsibility for TIA rendering - unique_ptr myTIASurface; + shared_ptr myTIASurface; + + // The BezelSurface class takes responsibility for TIA rendering + shared_ptr myBezelSurface; // Used for onscreen messages and frame statistics // (scanline count and framerate) diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index 1af44ceb5..4c7c32214 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -62,6 +62,7 @@ Settings::Settings() setPermanent("display", 0); setPermanent("uimessages", "true"); setPermanent("pausedim", "true"); + setPermanent("showbezel", "true"); // TIA specific options setPermanent("tia.inter", "false"); setPermanent("tia.zoom", "3"); diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 0a40dfb70..f36f15067 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -432,7 +432,7 @@ void TIASurface::createScanlineSurface() mySLineSurface = myFB.allocateSurface(width, height, interpolationModeFromSettings(myOSystem.settings()), data.data()); - mySLineSurface->setSrcSize(mySLineSurface->width(), height); + //mySLineSurface->setSrcSize(mySLineSurface->width(), height); mySLineSurface->setDstRect(myTiaSurface->dstRect()); updateSurfaceSettings();