mirror of https://github.com/stella-emu/stella.git
refactored bezel code
added variable bezel window support
This commit is contained in:
parent
e0374fe681
commit
c31ab36afe
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
* Added 2nd UI theme and hotkey for toggling UI theme.
|
* Added 2nd UI theme and hotkey for toggling UI theme.
|
||||||
|
|
||||||
* Adde bezel support.
|
* Added bezel support. (TODO: Doc)
|
||||||
|
|
||||||
* Added optional type format detection based on colors used.
|
* Added optional type format detection based on colors used.
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,18 @@ class FBBackendSDL2 : public FBBackend
|
||||||
FORCE_INLINE void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override
|
FORCE_INLINE void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override
|
||||||
{ SDL_GetRGB(pixel, myPixelFormat, r, g, b); }
|
{ SDL_GetRGB(pixel, myPixelFormat, r, g, b); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
This method is called to retrieve the R/G/B/A data from the given pixel.
|
||||||
|
|
||||||
|
@param pixel The pixel containing R/G/B data
|
||||||
|
@param r The red component of the color
|
||||||
|
@param g The green component of the color
|
||||||
|
@param b The blue component of the color
|
||||||
|
@param a The alpha component of the color.
|
||||||
|
*/
|
||||||
|
FORCE_INLINE void getRGBA(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b, uInt8* a) const override
|
||||||
|
{ SDL_GetRGBA(pixel, myPixelFormat, r, g, b, a); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This method is called to map a given R/G/B triple to the screen palette.
|
This method is called to map a given R/G/B triple to the screen palette.
|
||||||
|
|
||||||
|
@ -111,6 +123,14 @@ class FBBackendSDL2 : public FBBackend
|
||||||
inline uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override
|
inline uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override
|
||||||
{ return SDL_MapRGB(myPixelFormat, r, g, b); }
|
{ return SDL_MapRGB(myPixelFormat, r, g, b); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
This method is called to map a given R/G/B/A triple to the screen palette.
|
||||||
|
|
||||||
|
@param r The red component of the color.
|
||||||
|
@param g The green component of the color.
|
||||||
|
@param b The blue component of the color.
|
||||||
|
@param a The alpha component of the color.
|
||||||
|
*/
|
||||||
inline uInt32 mapRGBA(uInt8 r, uInt8 g, uInt8 b, uInt8 a) const override
|
inline uInt32 mapRGBA(uInt8 r, uInt8 g, uInt8 b, uInt8 a) const override
|
||||||
{ return SDL_MapRGBA(myPixelFormat, r, g, b, a); }
|
{ return SDL_MapRGBA(myPixelFormat, r, g, b, a); }
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include "Settings.hxx"
|
#include "Settings.hxx"
|
||||||
|
#include "Bezel.hxx"
|
||||||
|
|
||||||
#include "VideoModeHandler.hxx"
|
#include "VideoModeHandler.hxx"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -33,7 +35,7 @@ void VideoModeHandler::setDisplaySize(const Common::Size& display, Int32 fsIndex
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
const VideoModeHandler::Mode&
|
const VideoModeHandler::Mode&
|
||||||
VideoModeHandler::buildMode(const Settings& settings, bool inTIAMode, bool showBezel)
|
VideoModeHandler::buildMode(const Settings& settings, bool inTIAMode, Bezel::Info bezelInfo)
|
||||||
{
|
{
|
||||||
const bool windowedRequested = myFSIndex == -1;
|
const bool windowedRequested = myFSIndex == -1;
|
||||||
|
|
||||||
|
@ -42,25 +44,24 @@ const VideoModeHandler::Mode&
|
||||||
{
|
{
|
||||||
if(windowedRequested)
|
if(windowedRequested)
|
||||||
{
|
{
|
||||||
const float zoom = settings.getFloat("tia.zoom");
|
const double zoom = settings.getFloat("tia.zoom");
|
||||||
ostringstream desc;
|
ostringstream desc;
|
||||||
desc << (zoom * 100) << "%";
|
desc << (zoom * 100) << "%";
|
||||||
|
|
||||||
// Image and screen (aka window) dimensions are the same
|
// Image and screen (aka window) dimensions are the same
|
||||||
// Overscan is not applicable in this mode
|
// Overscan is not applicable in this mode
|
||||||
myMode = Mode(myImage.w * zoom, myImage.h * zoom, Mode::Stretch::Fill,
|
myMode = Mode(myImage.w, myImage.h,
|
||||||
myFSIndex, desc.str(), zoom, showBezel);
|
Mode::Stretch::Fill, myFSIndex,
|
||||||
|
desc.str(), zoom, bezelInfo);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const float overscan = 1 - settings.getInt("tia.fs_overscan") / 100.0;
|
const double overscan = 1 - settings.getInt("tia.fs_overscan") / 100.0;
|
||||||
|
|
||||||
// First calculate maximum zoom that keeps aspect ratio
|
// First calculate maximum zoom that keeps aspect ratio
|
||||||
// Note: We are assuming a 16:9 bezel image here
|
const double scaleX = static_cast<double>(myImage.w) / (myDisplay.w / bezelInfo.ratioW()),
|
||||||
const float bezelScaleW = showBezel ? (16.F / 9.F) / (4.F / 3.F) : 1;
|
scaleY = static_cast<double>(myImage.h) / (myDisplay.h / bezelInfo.ratioH());
|
||||||
const float scaleX = myImage.w / (myDisplay.w / bezelScaleW),
|
double zoom = 1. / std::max(scaleX, scaleY);
|
||||||
scaleY = static_cast<float>(myImage.h) / myDisplay.h;
|
|
||||||
float zoom = 1.F / std::max(scaleX, scaleY);
|
|
||||||
|
|
||||||
// When aspect ratio correction is off, we want pixel-exact images,
|
// When aspect ratio correction is off, we want pixel-exact images,
|
||||||
// so we default to integer zooming
|
// so we default to integer zooming
|
||||||
|
@ -69,20 +70,19 @@ const VideoModeHandler::Mode&
|
||||||
|
|
||||||
if(!settings.getBool("tia.fs_stretch")) // preserve aspect, use all space
|
if(!settings.getBool("tia.fs_stretch")) // preserve aspect, use all space
|
||||||
{
|
{
|
||||||
myMode = Mode(myImage.w * zoom, myImage.h * zoom,
|
myMode = Mode(myImage.w, myImage.h,
|
||||||
myDisplay.w, myDisplay.h,
|
myDisplay.w, myDisplay.h,
|
||||||
Mode::Stretch::Preserve, myFSIndex,
|
Mode::Stretch::Preserve, myFSIndex,
|
||||||
"Fullscreen: Preserve aspect, no stretch",
|
"Fullscreen: Preserve aspect, no stretch",
|
||||||
zoom, overscan,
|
zoom, overscan, bezelInfo);
|
||||||
showBezel, showBezel ? settings.getInt("bezel.border") : 0);
|
|
||||||
}
|
}
|
||||||
else // ignore aspect, use all space
|
else // ignore aspect, use all space
|
||||||
{
|
{
|
||||||
myMode = Mode(myImage.w * zoom, myImage.h * zoom,
|
myMode = Mode(myImage.w, myImage.h,
|
||||||
myDisplay.w, myDisplay.h,
|
myDisplay.w, myDisplay.h,
|
||||||
Mode::Stretch::Fill, myFSIndex,
|
Mode::Stretch::Fill, myFSIndex,
|
||||||
"Fullscreen: Ignore aspect, full stretch",
|
"Fullscreen: Ignore aspect, full stretch",
|
||||||
zoom, overscan, showBezel);
|
zoom, overscan, bezelInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,54 +94,48 @@ const VideoModeHandler::Mode&
|
||||||
myMode = Mode(myImage.w, myImage.h, myDisplay.w, myDisplay.h,
|
myMode = Mode(myImage.w, myImage.h, myDisplay.w, myDisplay.h,
|
||||||
Mode::Stretch::None, myFSIndex);
|
Mode::Stretch::None, myFSIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return myMode;
|
return myMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, Stretch smode,
|
VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, Stretch smode,
|
||||||
Int32 fsindex, string_view desc,
|
Int32 fsindex, string_view desc,
|
||||||
float zoomLevel,
|
double zoomLevel, Bezel::Info bezelInfo)
|
||||||
bool showBezel, Int32 bezelBorder)
|
: Mode(iw, ih, iw, ih, smode, fsindex, desc, zoomLevel, 1., bezelInfo)
|
||||||
: Mode(iw, ih, iw, ih, smode, fsindex, desc, zoomLevel, 1.F, showBezel, bezelBorder)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh,
|
VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh,
|
||||||
Stretch smode, Int32 fsindex, string_view desc,
|
Stretch smode, Int32 fsindex, string_view desc,
|
||||||
float zoomLevel, float overscan,
|
double zoomLevel, double overscan, Bezel::Info bezelInfo)
|
||||||
bool showBezel, Int32 bezelBorder)
|
|
||||||
: screenS{sw, sh},
|
: screenS{sw, sh},
|
||||||
stretch{smode},
|
stretch{smode},
|
||||||
description{desc},
|
description{desc},
|
||||||
zoom{zoomLevel},
|
zoom{zoomLevel}, //hZoom{zoomLevel}, vZoom{zoomLevel},
|
||||||
fsIndex{fsindex}
|
fsIndex{fsindex}
|
||||||
{
|
{
|
||||||
// Note: We are assuming a 16:9 bezel image here
|
|
||||||
const float bezelScaleW = showBezel ? (16.F / 9.F) / (4.F / 3.F) : 1;
|
|
||||||
// Now resize based on windowed/fullscreen mode and stretch factor
|
// Now resize based on windowed/fullscreen mode and stretch factor
|
||||||
if(fsIndex != -1) // fullscreen mode
|
if(fsIndex != -1) // fullscreen mode
|
||||||
{
|
{
|
||||||
switch(stretch)
|
switch(stretch)
|
||||||
{
|
{
|
||||||
case Stretch::Preserve:
|
case Stretch::Preserve:
|
||||||
iw = (iw - bezelBorder * 4.F / 3.F * zoomLevel) * overscan;
|
iw = std::round(iw * overscan * zoomLevel);
|
||||||
ih = (ih - bezelBorder * zoomLevel) * overscan;
|
ih = std::round(ih * overscan * zoomLevel);
|
||||||
//iw *= overscan;
|
|
||||||
//ih *= overscan;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Stretch::Fill:
|
case Stretch::Fill:
|
||||||
|
{
|
||||||
// Scale to all available space
|
// Scale to all available space
|
||||||
iw = screenS.w * (overscan / bezelScaleW);
|
iw = std::round(screenS.w * overscan / bezelInfo.ratioW());
|
||||||
ih = screenS.h * overscan;
|
ih = std::round(screenS.h * overscan / bezelInfo.ratioH());
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Stretch::None: // UI Mode
|
case Stretch::None: // UI Mode
|
||||||
// Don't do any scaling at all
|
// Don't do any scaling at all
|
||||||
iw = std::min(iw, screenS.w) * overscan;
|
iw = std::min(static_cast<uInt32>(iw * zoomLevel), screenS.w) * overscan;
|
||||||
ih = std::min(ih, screenS.h) * overscan;
|
ih = std::min(static_cast<uInt32>(ih * zoomLevel), screenS.h) * overscan;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,8 +147,10 @@ VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh,
|
||||||
{
|
{
|
||||||
case Stretch::Preserve:
|
case Stretch::Preserve:
|
||||||
case Stretch::Fill:
|
case Stretch::Fill:
|
||||||
screenS.w = iw * bezelScaleW;
|
iw *= zoomLevel;
|
||||||
screenS.h = ih;
|
ih *= zoomLevel;
|
||||||
|
screenS.w = std::round(iw * bezelInfo.ratioW());
|
||||||
|
screenS.h = std::round(ih * bezelInfo.ratioH());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Stretch::None: // UI Mode
|
case Stretch::None: // UI Mode
|
||||||
|
@ -166,7 +162,17 @@ VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh,
|
||||||
iw = std::min(iw, screenS.w);
|
iw = std::min(iw, screenS.w);
|
||||||
ih = std::min(ih, screenS.h);
|
ih = std::min(ih, screenS.h);
|
||||||
|
|
||||||
imageR.moveTo((screenS.w - iw) >> 1, (screenS.h - ih) >> 1);
|
// Allow variable image positions in asymmetric bezels
|
||||||
|
// (works in case of no bezel too)
|
||||||
|
const uInt32 wx = bezelInfo.window().x() * iw / bezelInfo.window().w();
|
||||||
|
const uInt32 wy = bezelInfo.window().y() * ih / bezelInfo.window().h();
|
||||||
|
const uInt32 bezelW = std::min(screenS.w,
|
||||||
|
static_cast<uInt32>(std::round(iw * bezelInfo.ratioW())));
|
||||||
|
const uInt32 bezelH = std::min(screenS.h,
|
||||||
|
static_cast<uInt32>(std::round(ih * bezelInfo.ratioH())));
|
||||||
|
// Center image (no bezel) or move image relative to centered bezel
|
||||||
|
imageR.moveTo(((screenS.w - bezelW) >> 1) + wx, ((screenS.h - bezelH) >> 1) + wy);
|
||||||
|
|
||||||
imageR.setWidth(iw);
|
imageR.setWidth(iw);
|
||||||
imageR.setHeight(ih);
|
imageR.setHeight(ih);
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ class Settings;
|
||||||
|
|
||||||
#include "Rect.hxx"
|
#include "Rect.hxx"
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
#include "Bezel.hxx"
|
||||||
|
|
||||||
class VideoModeHandler
|
class VideoModeHandler
|
||||||
{
|
{
|
||||||
|
@ -38,35 +39,23 @@ class VideoModeHandler
|
||||||
Fill, // Stretch to fill all available space
|
Fill, // Stretch to fill all available space
|
||||||
None // No stretching (1x zoom)
|
None // No stretching (1x zoom)
|
||||||
};
|
};
|
||||||
struct BezelInfo
|
|
||||||
{
|
|
||||||
bool enabled{false};
|
|
||||||
bool windowedMode{false};
|
|
||||||
uInt32 topBorder{0};
|
|
||||||
uInt32 bottomBorder{0};
|
|
||||||
|
|
||||||
BezelInfo() = default;
|
|
||||||
BezelInfo(bool _enabled, bool _windowedMode, uInt32 _topBorder, uInt32 _bottomBorder)
|
|
||||||
: enabled{_enabled}, windowedMode{_windowedMode},
|
|
||||||
topBorder{_topBorder}, bottomBorder(_bottomBorder) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
Common::Rect imageR;
|
Common::Rect imageR;
|
||||||
Common::Rect screenR;
|
Common::Rect screenR;
|
||||||
Common::Size screenS;
|
Common::Size screenS;
|
||||||
Stretch stretch{Mode::Stretch::None};
|
Stretch stretch{Mode::Stretch::None};
|
||||||
string description;
|
string description;
|
||||||
float zoom{1.F};
|
double zoom{1.};
|
||||||
Int32 fsIndex{-1}; // -1 indicates windowed mode
|
Int32 fsIndex{-1}; // -1 indicates windowed mode
|
||||||
|
|
||||||
Mode() = default;
|
Mode() = default;
|
||||||
Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, Stretch smode,
|
Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, Stretch smode,
|
||||||
Int32 fsindex = -1, string_view desc = "",
|
Int32 fsindex = -1, string_view desc = "",
|
||||||
float zoomLevel = 1.F, float overscan = 1.F,
|
double zoomLevel = 1., double overscan = 1.,
|
||||||
bool showBezel = false, Int32 bezelBorder = 0);
|
Bezel::Info bezelInfo = Bezel::Info());
|
||||||
Mode(uInt32 iw, uInt32 ih, Stretch smode, Int32 fsindex = -1,
|
Mode(uInt32 iw, uInt32 ih, Stretch smode, Int32 fsindex = -1,
|
||||||
string_view desc = "", float zoomLevel = 1.F,
|
string_view desc = "", double zoomLevel = 1.,
|
||||||
bool showBezel = false, Int32 bezelBorder = 0);
|
Bezel::Info bezelInfo = Bezel::Info());
|
||||||
|
|
||||||
friend ostream& operator<<(ostream& os, const Mode& vm)
|
friend ostream& operator<<(ostream& os, const Mode& vm)
|
||||||
{
|
{
|
||||||
|
@ -108,8 +97,8 @@ class VideoModeHandler
|
||||||
|
|
||||||
@return A video mode based on the given criteria
|
@return A video mode based on the given criteria
|
||||||
*/
|
*/
|
||||||
const VideoModeHandler::Mode& buildMode(const Settings& settings,
|
const VideoModeHandler::Mode& buildMode(const Settings& settings, bool inTIAMode,
|
||||||
bool inTIAMode, bool showBezel);
|
Bezel::Info bezelInfo = Bezel::Info());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Common::Size myImage, myDisplay;
|
Common::Size myImage, myDisplay;
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// SSSS tt lll lll
|
||||||
|
// SS SS tt ll ll
|
||||||
|
// SS tttttt eeee ll ll aaaa
|
||||||
|
// SSSS tt ee ee ll ll aa
|
||||||
|
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||||
|
// SS SS tt ee ll ll aa aa
|
||||||
|
// SSSS ttt eeeee llll llll aaaaa
|
||||||
|
//
|
||||||
|
// Copyright (c) 1995-2023 by Bradford W. Mott, Stephen Anthony
|
||||||
|
// and the Stella Team
|
||||||
|
//
|
||||||
|
// See the file "License.txt" for information on usage and redistribution of
|
||||||
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
#include "OSystem.hxx"
|
||||||
|
#include "Console.hxx"
|
||||||
|
#include "EventHandler.hxx"
|
||||||
|
#include "FBSurface.hxx"
|
||||||
|
#include "PNGLibrary.hxx"
|
||||||
|
|
||||||
|
#include "Bezel.hxx"
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Bezel::Bezel(OSystem& osystem)
|
||||||
|
: myOSystem{osystem},
|
||||||
|
myFB{osystem.frameBuffer()}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
const string Bezel::getName(int& index) const
|
||||||
|
{
|
||||||
|
if(++index == 1)
|
||||||
|
return myOSystem.console().properties().get(PropType::Bezel_Name);
|
||||||
|
|
||||||
|
// Try to generate bezel name from cart name
|
||||||
|
const string& cartName = myOSystem.console().properties().get(PropType::Cart_Name);
|
||||||
|
const size_t pos = cartName.find_first_of("(");
|
||||||
|
if(index < 10 && pos != std::string::npos && pos > 0)
|
||||||
|
{
|
||||||
|
// The following suffixes are from "The Official No-Intro Convention",
|
||||||
|
// covering all used combinations by "The Bezel Project" (except single ones)
|
||||||
|
// (Unl) = unlicensed (Homebrews)
|
||||||
|
const std::array<string, 8> suffixes = {
|
||||||
|
" (USA)", " (USA) (Proto)", " (USA) (Unl)", " (USA) (Hack)",
|
||||||
|
" (Europe)", " (Germany)", " (France) (Unl)", " (Australia)"
|
||||||
|
};
|
||||||
|
return cartName.substr(0, pos - 1) + suffixes[index - 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(index == 10)
|
||||||
|
{
|
||||||
|
index = -1;
|
||||||
|
return "default";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
uInt32 Bezel::borderSize(uInt32 x, uInt32 y, uInt32 size, Int32 step) const
|
||||||
|
{
|
||||||
|
uInt32 *pixels{nullptr}, pitch;
|
||||||
|
uInt32 i;
|
||||||
|
|
||||||
|
mySurface->basePtr(pixels, pitch);
|
||||||
|
pixels += x + y * pitch;
|
||||||
|
|
||||||
|
for(i = 0; i < size; ++i, pixels += step)
|
||||||
|
{
|
||||||
|
uInt8 r, g, b, a;
|
||||||
|
|
||||||
|
myFB.getRGBA(*pixels, &r, &g, &b, &a);
|
||||||
|
if(a < 255)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Bezel::load()
|
||||||
|
{
|
||||||
|
bool isValid = false;
|
||||||
|
|
||||||
|
#ifdef IMAGE_SUPPORT
|
||||||
|
const bool isShown = myOSystem.eventHandler().inTIAMode() &&
|
||||||
|
myOSystem.settings().getBool("bezel.show") &&
|
||||||
|
(myFB.fullScreen() || myOSystem.settings().getBool("bezel.windowed"));
|
||||||
|
|
||||||
|
if(mySurface)
|
||||||
|
myFB.deallocateSurface(mySurface);
|
||||||
|
mySurface = nullptr;
|
||||||
|
|
||||||
|
if(isShown)
|
||||||
|
{
|
||||||
|
double aspectRatio = 1;
|
||||||
|
|
||||||
|
mySurface = myFB.allocateSurface(1, 1); // dummy size
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const string& path = myOSystem.bezelDir().getPath();
|
||||||
|
string imageName;
|
||||||
|
VariantList metaData;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const string& name = getName(index);
|
||||||
|
if(name != EmptyString)
|
||||||
|
{
|
||||||
|
imageName = path + name + ".png";
|
||||||
|
FSNode node(imageName);
|
||||||
|
if(node.exists())
|
||||||
|
{
|
||||||
|
isValid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(index != -1);
|
||||||
|
if(isValid)
|
||||||
|
myOSystem.png().loadImage(imageName, *mySurface, &aspectRatio, metaData);
|
||||||
|
}
|
||||||
|
catch(const runtime_error&)
|
||||||
|
{
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(isValid)
|
||||||
|
{
|
||||||
|
const Settings& settings = myOSystem.settings();
|
||||||
|
const Int32 w = mySurface->width();
|
||||||
|
const Int32 h = mySurface->height();
|
||||||
|
uInt32 top, bottom, left, right;
|
||||||
|
|
||||||
|
if(settings.getBool("bezel.autoborders"))
|
||||||
|
{
|
||||||
|
// Determine transparent window inside bezel image
|
||||||
|
top = borderSize(w >> 1, 0, h, w);
|
||||||
|
bottom = h - 1 - borderSize(w >> 1, h - 1, h, -w);
|
||||||
|
left = borderSize(0, (bottom + top) >> 1, w, 1);
|
||||||
|
right = w - 1 - borderSize(w - 1, (bottom + top) >> 1, w, -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
left = std::min(w, settings.getInt("bezel.leftborder"));
|
||||||
|
right = w - 1 - std::min(w, settings.getInt("bezel.rightborder"));
|
||||||
|
top = std::min(h, settings.getInt("bezel.topborder"));
|
||||||
|
bottom = h - 1 - std::min(h, settings.getInt("bezel.bottomborder"));
|
||||||
|
}
|
||||||
|
//cerr << right - left + 1 << " x " << bottom - top + 1 << " = "
|
||||||
|
// << double(right - left + 1) / double(bottom - top + 1);
|
||||||
|
myInfo = Info(Common::Size(w, h), Common::Rect(left, top, right, bottom));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
myInfo = Info();
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Bezel::apply()
|
||||||
|
{
|
||||||
|
if(isShown())
|
||||||
|
{
|
||||||
|
const uInt32 bezelW =
|
||||||
|
std::min(myFB.screenSize().w,
|
||||||
|
static_cast<uInt32>(std::round(myFB.imageRect().w() * myInfo.ratioW())));
|
||||||
|
const uInt32 bezelH =
|
||||||
|
std::min(myFB.screenSize().h,
|
||||||
|
static_cast<uInt32>(std::round(myFB.imageRect().h() * myInfo.ratioH())));
|
||||||
|
|
||||||
|
// Position and scale bezel
|
||||||
|
mySurface->setDstSize(bezelW, bezelH);
|
||||||
|
mySurface->setDstPos((myFB.screenSize().w - bezelW) / 2, // center
|
||||||
|
(myFB.screenSize().h - bezelH) / 2);
|
||||||
|
mySurface->setScalingInterpolation(ScalingInterpolation::sharp);
|
||||||
|
// Note: Variable bezel window positions are handled in VideoModeHandler::Mode
|
||||||
|
|
||||||
|
// Enable blending to allow overlaying the bezel over the TIA output
|
||||||
|
mySurface->attributes().blending = true;
|
||||||
|
mySurface->attributes().blendalpha = 100;
|
||||||
|
mySurface->applyAttributes();
|
||||||
|
mySurface->setVisible(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(mySurface)
|
||||||
|
mySurface->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Bezel::render()
|
||||||
|
{
|
||||||
|
if(mySurface)
|
||||||
|
mySurface->render();
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// SSSS tt lll lll
|
||||||
|
// SS SS tt ll ll
|
||||||
|
// SS tttttt eeee ll ll aaaa
|
||||||
|
// SSSS tt ee ee ll ll aa
|
||||||
|
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||||
|
// SS SS tt ee ll ll aa aa
|
||||||
|
// SSSS ttt eeeee llll llll aaaaa
|
||||||
|
//
|
||||||
|
// Copyright (c) 1995-2023 by Bradford W. Mott, Stephen Anthony
|
||||||
|
// and the Stella Team
|
||||||
|
//
|
||||||
|
// See the file "License.txt" for information on usage and redistribution of
|
||||||
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
#ifndef BEZEL_HXX
|
||||||
|
#define BEZEL_HXX
|
||||||
|
|
||||||
|
class OSystem;
|
||||||
|
class FBSurface;
|
||||||
|
class FrameBuffer;
|
||||||
|
|
||||||
|
#include "Rect.hxx"
|
||||||
|
|
||||||
|
/**
|
||||||
|
This class handles the bezels.
|
||||||
|
|
||||||
|
Bezels are loaded using a file name which is either a bezel name property or
|
||||||
|
is autogenerated from the cart name property. The bezels can be any size and
|
||||||
|
their transparent emulation window can be at any position. The position of
|
||||||
|
the window can be determined automatically.
|
||||||
|
|
||||||
|
+--------------------------------------+
|
||||||
|
| | display.h
|
||||||
|
+--------------------------------------+
|
||||||
|
| |
|
||||||
|
| +---------------+ |
|
||||||
|
| | window | |
|
||||||
|
| | | |
|
||||||
|
| | tia.h * zoom | |
|
||||||
|
| | | | bezel.h * zoom
|
||||||
|
| | | |
|
||||||
|
| +---------------+ |
|
||||||
|
| |
|
||||||
|
+--------------------------------------+ size
|
||||||
|
| |
|
||||||
|
+--------------------------------------+
|
||||||
|
|
||||||
|
The bezel and window sizes and their ratios are used for correct scaling.
|
||||||
|
|
||||||
|
@author Thomas Jentzsch
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Bezel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Bezel(OSystem& osystem);
|
||||||
|
~Bezel() = default;
|
||||||
|
|
||||||
|
struct Info
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
bool _isShown{false}; // Is bezel shown?
|
||||||
|
Common::Size _size{1, 1}; // Bezel size
|
||||||
|
Common::Rect _window{1, 1}; // Area of transparent TIA window inside bezel
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Info() = default;
|
||||||
|
explicit Info(Common::Size size, Common::Rect window)
|
||||||
|
: _isShown{true}, _size{size}, _window{window} { }
|
||||||
|
|
||||||
|
bool isShown() const { return _isShown; }
|
||||||
|
Common::Size size() const { return _size; }
|
||||||
|
Common::Rect window() const { return _window; }
|
||||||
|
|
||||||
|
// Ratios between bezel sizes and TIA window sizes
|
||||||
|
double ratioW() const { return static_cast<double>(size().w) / window().w(); }
|
||||||
|
double ratioH() const { return static_cast<double>(size().h) / window().h(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Structure access methods
|
||||||
|
const Info& info() const { return myInfo; }
|
||||||
|
bool isShown() const { return myInfo.isShown(); }
|
||||||
|
Common::Size size() const { return myInfo.size(); }
|
||||||
|
Common::Rect window() const { return myInfo.window(); }
|
||||||
|
// Ratio between bezel size and TIA window size
|
||||||
|
double ratioW() const { return myInfo.ratioW(); }
|
||||||
|
double ratioH() const { return myInfo.ratioH(); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
Calculate size of a bezel border.
|
||||||
|
*/
|
||||||
|
uInt32 borderSize(uInt32 x, uInt32 y, uInt32 size, Int32 step) const;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Load the bezel.
|
||||||
|
*/
|
||||||
|
bool load();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Display scaled bezel.
|
||||||
|
*/
|
||||||
|
void apply();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Render bezel surface
|
||||||
|
*/
|
||||||
|
void render();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*
|
||||||
|
Generate bezel file name.
|
||||||
|
*/
|
||||||
|
const string getName(int& index) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The parent system for the bezel
|
||||||
|
OSystem& myOSystem;
|
||||||
|
|
||||||
|
// Pointer to the FrameBuffer object
|
||||||
|
FrameBuffer& myFB;
|
||||||
|
|
||||||
|
// The bezel surface which blends over the TIA surface
|
||||||
|
shared_ptr<FBSurface> mySurface;
|
||||||
|
|
||||||
|
// Bezel info structure
|
||||||
|
Info myInfo;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Following constructors and assignment operators not supported
|
||||||
|
Bezel() = delete;
|
||||||
|
Bezel(const Bezel&) = delete;
|
||||||
|
Bezel(Bezel&&) = delete;
|
||||||
|
Bezel& operator=(const Bezel&) = delete;
|
||||||
|
Bezel& operator=(Bezel&&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -128,6 +128,17 @@ class FBBackend
|
||||||
*/
|
*/
|
||||||
virtual void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const = 0;
|
virtual void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
This method is called to retrieve the R/G/B/A data from the given pixel.
|
||||||
|
|
||||||
|
@param pixel The pixel containing R/G/B data
|
||||||
|
@param r The red component of the color
|
||||||
|
@param g The green component of the color
|
||||||
|
@param b The blue component of the color
|
||||||
|
@param a The alpha component of the color.
|
||||||
|
*/
|
||||||
|
virtual void getRGBA(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b, uInt8* a) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This method is called to map a given R/G/B triple to the screen palette.
|
This method is called to map a given R/G/B triple to the screen palette.
|
||||||
|
|
||||||
|
@ -143,6 +154,7 @@ class FBBackend
|
||||||
@param r The red component of the color.
|
@param r The red component of the color.
|
||||||
@param g The green component of the color.
|
@param g The green component of the color.
|
||||||
@param b The blue component of the color.
|
@param b The blue component of the color.
|
||||||
|
@param a The alpha component of the color.
|
||||||
*/
|
*/
|
||||||
virtual uInt32 mapRGBA(uInt8 r, uInt8 g, uInt8 b, uInt8 a) const = 0;
|
virtual uInt32 mapRGBA(uInt8 r, uInt8 g, uInt8 b, uInt8 a) const = 0;
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include "FBSurface.hxx"
|
#include "FBSurface.hxx"
|
||||||
#include "TIASurface.hxx"
|
#include "TIASurface.hxx"
|
||||||
|
#include "Bezel.hxx"
|
||||||
#include "FrameBuffer.hxx"
|
#include "FrameBuffer.hxx"
|
||||||
#include "PaletteHandler.hxx"
|
#include "PaletteHandler.hxx"
|
||||||
#include "StateManager.hxx"
|
#include "StateManager.hxx"
|
||||||
|
@ -126,6 +127,8 @@ void FrameBuffer::initialize()
|
||||||
|
|
||||||
// Create a TIA surface; we need it for rendering TIA images
|
// Create a TIA surface; we need it for rendering TIA images
|
||||||
myTIASurface = make_unique<TIASurface>(myOSystem);
|
myTIASurface = make_unique<TIASurface>(myOSystem);
|
||||||
|
// Create a bezel surface for TIA overlays
|
||||||
|
myBezel = make_unique<Bezel>(myOSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -278,8 +281,10 @@ FBInitStatus FrameBuffer::createDisplay(string_view title, BufferType type,
|
||||||
|
|
||||||
if(myBufferType == BufferType::Emulator)
|
if(myBufferType == BufferType::Emulator)
|
||||||
{
|
{
|
||||||
|
myBezel->load();
|
||||||
|
|
||||||
// Determine possible TIA windowed zoom levels
|
// Determine possible TIA windowed zoom levels
|
||||||
const float currentTIAZoom = myOSystem.settings().getFloat("tia.zoom");
|
const double currentTIAZoom = myOSystem.settings().getFloat("tia.zoom");
|
||||||
myOSystem.settings().setValue("tia.zoom",
|
myOSystem.settings().setValue("tia.zoom",
|
||||||
BSPF::clampw(currentTIAZoom, supportedTIAMinZoom(), supportedTIAMaxZoom()));
|
BSPF::clampw(currentTIAZoom, supportedTIAMinZoom(), supportedTIAMaxZoom()));
|
||||||
}
|
}
|
||||||
|
@ -960,8 +965,8 @@ void FrameBuffer::renderTIA(bool shade, bool doClear)
|
||||||
clear(); // TODO - test this: it may cause slowdowns on older systems
|
clear(); // TODO - test this: it may cause slowdowns on older systems
|
||||||
|
|
||||||
myTIASurface->render(shade);
|
myTIASurface->render(shade);
|
||||||
if(myBezelSurface)
|
if(myBezel)
|
||||||
myBezelSurface->render();
|
myBezel->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -1146,7 +1151,7 @@ void FrameBuffer::toggleFullscreen(bool toggle)
|
||||||
msg << "enabled (" << myBackend->refreshRate() << " Hz, ";
|
msg << "enabled (" << myBackend->refreshRate() << " Hz, ";
|
||||||
else
|
else
|
||||||
msg << "disabled (";
|
msg << "disabled (";
|
||||||
msg << "Zoom " << myActiveVidMode.zoom * 100 << "%)";
|
msg << "Zoom " << round(myActiveVidMode.zoom * 100) << "%)";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1228,7 +1233,7 @@ void FrameBuffer::switchVideoMode(int direction)
|
||||||
if(!fullScreen())
|
if(!fullScreen())
|
||||||
{
|
{
|
||||||
// Windowed TIA modes support variable zoom levels
|
// Windowed TIA modes support variable zoom levels
|
||||||
float zoom = myOSystem.settings().getFloat("tia.zoom");
|
double zoom = myOSystem.settings().getFloat("tia.zoom");
|
||||||
if(direction == +1) zoom += ZOOM_STEPS;
|
if(direction == +1) zoom += ZOOM_STEPS;
|
||||||
else if(direction == -1) zoom -= ZOOM_STEPS;
|
else if(direction == -1) zoom -= ZOOM_STEPS;
|
||||||
|
|
||||||
|
@ -1271,17 +1276,10 @@ FBInitStatus FrameBuffer::applyVideoMode()
|
||||||
myVidModeHandler.setDisplaySize(myAbsDesktopSize[display]);
|
myVidModeHandler.setDisplaySize(myAbsDesktopSize[display]);
|
||||||
|
|
||||||
const bool inTIAMode = myOSystem.eventHandler().inTIAMode();
|
const bool inTIAMode = myOSystem.eventHandler().inTIAMode();
|
||||||
#ifdef IMAGE_SUPPORT
|
|
||||||
const bool showBezel = inTIAMode &&
|
|
||||||
myOSystem.settings().getBool("bezel.show") &&
|
|
||||||
(fullScreen() || myOSystem.settings().getBool("bezel.windowed")) &&
|
|
||||||
checkBezel();
|
|
||||||
#else
|
|
||||||
const bool showBezel = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Build the new mode based on current settings
|
// Build the new mode based on current settings
|
||||||
const VideoModeHandler::Mode& mode = myVidModeHandler.buildMode(s, inTIAMode, showBezel);
|
const VideoModeHandler::Mode& mode
|
||||||
|
= myVidModeHandler.buildMode(s, inTIAMode, myBezel->info());
|
||||||
if(mode.imageR.size() > mode.screenS)
|
if(mode.imageR.size() > mode.screenS)
|
||||||
return FBInitStatus::FailTooLarge;
|
return FBInitStatus::FailTooLarge;
|
||||||
|
|
||||||
|
@ -1306,11 +1304,7 @@ FBInitStatus FrameBuffer::applyVideoMode()
|
||||||
if(inTIAMode)
|
if(inTIAMode)
|
||||||
{
|
{
|
||||||
#ifdef IMAGE_SUPPORT
|
#ifdef IMAGE_SUPPORT
|
||||||
if(myBezelSurface)
|
myBezel->apply();
|
||||||
deallocateSurface(myBezelSurface);
|
|
||||||
myBezelSurface = nullptr;
|
|
||||||
if(showBezel)
|
|
||||||
loadBezel();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
myTIASurface->initialize(myOSystem.console(), myActiveVidMode);
|
myTIASurface->initialize(myOSystem.console(), myActiveVidMode);
|
||||||
|
@ -1334,147 +1328,18 @@ FBInitStatus FrameBuffer::applyVideoMode()
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef IMAGE_SUPPORT
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
const string FrameBuffer::getBezelName(int& index) const
|
|
||||||
{
|
|
||||||
if(++index == 1)
|
|
||||||
return myOSystem.console().properties().get(PropType::Bezel_Name);
|
|
||||||
|
|
||||||
// Try to generate bezel name from cart name
|
|
||||||
const string& cartName = myOSystem.console().properties().get(PropType::Cart_Name);
|
|
||||||
const size_t pos = cartName.find_first_of("(");
|
|
||||||
if(index < 10 && pos != std::string::npos && pos > 0)
|
|
||||||
{
|
|
||||||
// The following suffixes are from "The Official No-Intro Convention",
|
|
||||||
// covering all used combinations by "The Bezel Project" (except single ones)
|
|
||||||
// (Unl) = unlicensed (Homebrews)
|
|
||||||
const std::array<string, 8> suffixes = {
|
|
||||||
" (USA)", " (USA) (Proto)", " (USA) (Unl)", " (USA) (Hack)",
|
|
||||||
" (Europe)", " (Germany)", " (France) (Unl)", " (Australia)"
|
|
||||||
};
|
|
||||||
return cartName.substr(0, pos - 1) + suffixes[index - 2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(index == 10)
|
|
||||||
{
|
|
||||||
index = -1;
|
|
||||||
return "default";
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool FrameBuffer::checkBezel()
|
double FrameBuffer::maxWindowZoom() const
|
||||||
{
|
|
||||||
const string& path = myOSystem.bezelDir().getPath();
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
const string& name = getBezelName(index);
|
|
||||||
|
|
||||||
if(name != EmptyString)
|
|
||||||
{
|
|
||||||
FSNode node(path + name + ".png");
|
|
||||||
if(node.exists())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} while (index != -1);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
bool FrameBuffer::loadBezel()
|
|
||||||
{
|
|
||||||
bool isValid = false;
|
|
||||||
double aspectRatio = 1;
|
|
||||||
|
|
||||||
myBezelSurface = allocateSurface(myActiveVidMode.screenS.w, myActiveVidMode.screenS.h);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const string& path = myOSystem.bezelDir().getPath();
|
|
||||||
string imageName;
|
|
||||||
VariantList metaData;
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
const string& name = getBezelName(index);
|
|
||||||
if(name != EmptyString)
|
|
||||||
{
|
|
||||||
imageName = path + name + ".png";
|
|
||||||
FSNode node(imageName);
|
|
||||||
if(node.exists())
|
|
||||||
{
|
|
||||||
isValid = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (index != -1);
|
|
||||||
if(isValid)
|
|
||||||
myOSystem.png().loadImage(imageName, *myBezelSurface, &aspectRatio, metaData);
|
|
||||||
}
|
|
||||||
catch(const runtime_error&)
|
|
||||||
{
|
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isValid)
|
|
||||||
{
|
|
||||||
const float overscan = 1 - myOSystem.settings().getInt("tia.fs_overscan") / 100.F;
|
|
||||||
|
|
||||||
uInt32 imageW, imageH;
|
|
||||||
if(fullScreen())
|
|
||||||
{
|
|
||||||
const float bezelBorder = myOSystem.settings().getInt("bezel.border") * overscan * myActiveVidMode.zoom;
|
|
||||||
imageW = (myActiveVidMode.imageR.w() + static_cast<int>(bezelBorder * 4.F / 3.F)) * (16.F / 9.F) / (4.F / 3.F);
|
|
||||||
imageH = myActiveVidMode.imageR.h() + static_cast<int>(bezelBorder);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
imageW = static_cast<uInt32>(myActiveVidMode.imageR.w() * (16.F / 9.F) / (4.F / 3.F));
|
|
||||||
imageH = myActiveVidMode.imageR.h();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scale bezel to fullscreen (preserve or stretch) or window size
|
|
||||||
const uInt32 bezelW = std::min(
|
|
||||||
myActiveVidMode.screenS.w, imageW);
|
|
||||||
//static_cast<uInt32>(myActiveVidMode.imageR.w() * (16.F / 9.F) / (4.F / 3.F)) + static_cast<int>(40 * myActiveVidMode.zoom));
|
|
||||||
const uInt32 bezelH = std::min(
|
|
||||||
myActiveVidMode.screenS.h, imageH);
|
|
||||||
//myActiveVidMode.imageR.h() + static_cast<int>(30 * myActiveVidMode.zoom));
|
|
||||||
//cerr << bezelW << " x " << bezelH << endl;
|
|
||||||
myBezelSurface->setDstSize(bezelW, bezelH);
|
|
||||||
myBezelSurface->setDstPos((myActiveVidMode.screenS.w - bezelW) / 2,
|
|
||||||
(myActiveVidMode.screenS.h - bezelH) / 2); // center
|
|
||||||
myBezelSurface->setScalingInterpolation(ScalingInterpolation::sharp);
|
|
||||||
|
|
||||||
// Enable blending to allow overlaying the bezel over the TIA output
|
|
||||||
myBezelSurface->attributes().blending = true;
|
|
||||||
myBezelSurface->attributes().blendalpha = 100;
|
|
||||||
myBezelSurface->applyAttributes();
|
|
||||||
}
|
|
||||||
if(myBezelSurface)
|
|
||||||
myBezelSurface->setVisible(isValid);
|
|
||||||
return isValid;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
float FrameBuffer::maxWindowZoom() const
|
|
||||||
{
|
{
|
||||||
const int display = displayId(BufferType::Emulator);
|
const int display = displayId(BufferType::Emulator);
|
||||||
float multiplier = 1;
|
double multiplier = 1;
|
||||||
|
|
||||||
const bool showBezel = myOSystem.settings().getBool("bezel.show");
|
|
||||||
const float scaleW = showBezel ? (16.F / 9.F) / (4.F / 3.F) : 1.F; // = 1.333
|
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
// Figure out the zoomed size of the window
|
// Figure out the zoomed size of the window (incl. the bezel)
|
||||||
const uInt32 width = TIAConstants::viewableWidth * multiplier * scaleW;
|
const uInt32 width = static_cast<double>(TIAConstants::viewableWidth) * myBezel->ratioW() * multiplier;
|
||||||
const uInt32 height = TIAConstants::viewableHeight * multiplier;
|
const uInt32 height = static_cast<double>(TIAConstants::viewableHeight) * myBezel->ratioH() * multiplier;
|
||||||
|
|
||||||
if((width > myAbsDesktopSize[display].w) ||
|
if((width > myAbsDesktopSize[display].w) ||
|
||||||
(height > myAbsDesktopSize[display].h))
|
(height > myAbsDesktopSize[display].h))
|
||||||
|
|
|
@ -25,6 +25,7 @@ class Console;
|
||||||
class Settings;
|
class Settings;
|
||||||
class FBSurface;
|
class FBSurface;
|
||||||
class TIASurface;
|
class TIASurface;
|
||||||
|
class Bezel;
|
||||||
|
|
||||||
#ifdef GUI_SUPPORT
|
#ifdef GUI_SUPPORT
|
||||||
#include "Font.hxx"
|
#include "Font.hxx"
|
||||||
|
@ -53,7 +54,7 @@ class FrameBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Zoom level step interval
|
// Zoom level step interval
|
||||||
static constexpr float ZOOM_STEPS = 0.25;
|
static constexpr double ZOOM_STEPS = 0.25;
|
||||||
|
|
||||||
enum UpdateMode {
|
enum UpdateMode {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
|
@ -219,8 +220,8 @@ class FrameBuffer
|
||||||
Get the minimum/maximum supported TIA zoom level (windowed mode)
|
Get the minimum/maximum supported TIA zoom level (windowed mode)
|
||||||
for the framebuffer.
|
for the framebuffer.
|
||||||
*/
|
*/
|
||||||
float supportedTIAMinZoom() const { return myTIAMinZoom * hidpiScaleFactor(); }
|
double supportedTIAMinZoom() const { return myTIAMinZoom * hidpiScaleFactor(); }
|
||||||
float supportedTIAMaxZoom() const { return maxWindowZoom(); }
|
double supportedTIAMaxZoom() const { return maxWindowZoom(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get the TIA surface associated with the framebuffer.
|
Get the TIA surface associated with the framebuffer.
|
||||||
|
@ -349,6 +350,19 @@ class FrameBuffer
|
||||||
myBackend->getRGB(pixel, r, g, b);
|
myBackend->getRGB(pixel, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This method is called to retrieve the R/G/B/A data from the given pixel.
|
||||||
|
|
||||||
|
@param pixel The pixel containing R/G/B data
|
||||||
|
@param r The red component of the color
|
||||||
|
@param g The green component of the color
|
||||||
|
@param b The blue component of the color
|
||||||
|
@param a The alpha component of the color.
|
||||||
|
*/
|
||||||
|
void getRGBA(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b, uInt8* a) const {
|
||||||
|
myBackend->getRGBA(pixel, r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This method is called to map a given R/G/B triple to the screen palette.
|
This method is called to map a given R/G/B triple to the screen palette.
|
||||||
|
|
||||||
|
@ -361,11 +375,12 @@ class FrameBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This method is called to map a given R/G/B triple to the screen palette.
|
This method is called to map a given R/G/B/A triple to the screen palette.
|
||||||
|
|
||||||
@param r The red component of the color.
|
@param r The red component of the color.
|
||||||
@param g The green component of the color.
|
@param g The green component of the color.
|
||||||
@param b The blue component of the color.
|
@param b The blue component of the color.
|
||||||
|
@param a The alpha component of the color.
|
||||||
*/
|
*/
|
||||||
uInt32 mapRGBA(uInt8 r, uInt8 g, uInt8 b, uInt8 a) const {
|
uInt32 mapRGBA(uInt8 r, uInt8 g, uInt8 b, uInt8 a) const {
|
||||||
return myBackend->mapRGBA(r, g, b, a);
|
return myBackend->mapRGBA(r, g, b, a);
|
||||||
|
@ -462,37 +477,11 @@ class FrameBuffer
|
||||||
*/
|
*/
|
||||||
FBInitStatus applyVideoMode();
|
FBInitStatus applyVideoMode();
|
||||||
|
|
||||||
#ifdef IMAGE_SUPPORT
|
|
||||||
/**
|
|
||||||
Return bezel names, which are either read from the properties
|
|
||||||
or generated from the cart name.
|
|
||||||
|
|
||||||
@param index The index of the returned bezel name
|
|
||||||
|
|
||||||
@return The bezel name for the given index
|
|
||||||
*/
|
|
||||||
const string getBezelName(int& index) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Check if a bezel for the current ROM name exists.
|
|
||||||
|
|
||||||
@return Whether the bezel was found or not
|
|
||||||
*/
|
|
||||||
bool checkBezel();
|
|
||||||
|
|
||||||
/**
|
|
||||||
Load the bezel for the current ROM.
|
|
||||||
|
|
||||||
@return Whether the bezel was loaded or not
|
|
||||||
*/
|
|
||||||
bool loadBezel();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Calculate the maximum level by which the base window can be zoomed and
|
Calculate the maximum level by which the base window can be zoomed and
|
||||||
still fit in the desktop screen.
|
still fit in the desktop screen.
|
||||||
*/
|
*/
|
||||||
float maxWindowZoom() const;
|
double maxWindowZoom() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Enables/disables fullscreen mode.
|
Enables/disables fullscreen mode.
|
||||||
|
@ -567,7 +556,7 @@ class FrameBuffer
|
||||||
shared_ptr<TIASurface> myTIASurface;
|
shared_ptr<TIASurface> myTIASurface;
|
||||||
|
|
||||||
// The BezelSurface which blends over the TIA surface
|
// The BezelSurface which blends over the TIA surface
|
||||||
shared_ptr<FBSurface> myBezelSurface;
|
unique_ptr<Bezel> myBezel;
|
||||||
|
|
||||||
// Used for onscreen messages and frame statistics
|
// Used for onscreen messages and frame statistics
|
||||||
// (scanline count and framerate)
|
// (scanline count and framerate)
|
||||||
|
@ -594,7 +583,7 @@ class FrameBuffer
|
||||||
vector<bool> myHiDPIEnabled;
|
vector<bool> myHiDPIEnabled;
|
||||||
|
|
||||||
// Minimum TIA zoom level that can be used for this framebuffer
|
// Minimum TIA zoom level that can be used for this framebuffer
|
||||||
float myTIAMinZoom{2.F};
|
double myTIAMinZoom{2.F};
|
||||||
|
|
||||||
// Holds a reference to all the surfaces that have been created
|
// Holds a reference to all the surfaces that have been created
|
||||||
std::list<shared_ptr<FBSurface>> mySurfaceList;
|
std::list<shared_ptr<FBSurface>> mySurfaceList;
|
||||||
|
|
|
@ -64,7 +64,11 @@ Settings::Settings()
|
||||||
setPermanent("pausedim", "true");
|
setPermanent("pausedim", "true");
|
||||||
setPermanent("bezel.show", "true");
|
setPermanent("bezel.show", "true");
|
||||||
setPermanent("bezel.windowed", "false");
|
setPermanent("bezel.windowed", "false");
|
||||||
setPermanent("bezel.border", "30");
|
setPermanent("bezel.autoborders", "true");
|
||||||
|
setPermanent("bezel.leftborder", "0");
|
||||||
|
setPermanent("bezel.rightborder", "0");
|
||||||
|
setPermanent("bezel.topborder", "0");
|
||||||
|
setPermanent("bezel.bottomborder", "0");
|
||||||
// TIA specific options
|
// TIA specific options
|
||||||
setPermanent("tia.inter", "false");
|
setPermanent("tia.inter", "false");
|
||||||
setPermanent("tia.zoom", "3");
|
setPermanent("tia.zoom", "3");
|
||||||
|
@ -542,8 +546,13 @@ void Settings::usage()
|
||||||
<< " -turbo <1|0> Enable 'Turbo' mode for maximum emulation speed\n"
|
<< " -turbo <1|0> Enable 'Turbo' mode for maximum emulation speed\n"
|
||||||
<< " -uimessages <1|0> Show onscreen UI messages for different events\n"
|
<< " -uimessages <1|0> Show onscreen UI messages for different events\n"
|
||||||
<< " -pausedim <1|0> Enable emulation dimming in pause mode\n"
|
<< " -pausedim <1|0> Enable emulation dimming in pause mode\n"
|
||||||
<< " -bezel.show <1|0> Show bezel left and right of emulation\n"
|
<< " -bezel.show <1|0> Show bezel left and right of emulation\n"
|
||||||
<< " -bezel.windowed <1|0> Show bezel in windowed modes\n"
|
<< " -bezel.windowed <1|0> Show bezel in windowed modes\n"
|
||||||
|
<< " -bezel.autoborders <1|0> Automatically set bezel window borders\n"
|
||||||
|
<< " -bezel.leftborder <number> Set left bezel window border\n"
|
||||||
|
<< " -bezel.rightborder <number> Set right bezel window border\n"
|
||||||
|
<< " -bezel.topborder <number> Set top bezel window border\n"
|
||||||
|
<< " -bezel.bottomborder <number> Set bottom bezel window border\n"
|
||||||
<< endl
|
<< endl
|
||||||
#ifdef SOUND_SUPPORT
|
#ifdef SOUND_SUPPORT
|
||||||
<< " -audio.enabled <1|0> Enable audio\n"
|
<< " -audio.enabled <1|0> Enable audio\n"
|
||||||
|
|
|
@ -2,6 +2,7 @@ MODULE := src/emucore
|
||||||
|
|
||||||
MODULE_OBJS := \
|
MODULE_OBJS := \
|
||||||
src/emucore/AtariVox.o \
|
src/emucore/AtariVox.o \
|
||||||
|
src/emucore/Bezel.o
|
||||||
src/emucore/Bankswitch.o \
|
src/emucore/Bankswitch.o \
|
||||||
src/emucore/Booster.o \
|
src/emucore/Booster.o \
|
||||||
src/emucore/Cart.o \
|
src/emucore/Cart.o \
|
||||||
|
|
|
@ -1410,7 +1410,7 @@ void DeveloperDialog::handleDebugColours(int idx, int color)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void DeveloperDialog::handleDebugColours(string_view colors)
|
void DeveloperDialog::handleDebugColours(string_view colors)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < DEBUG_COLORS; ++i)
|
for(int i = 0; i < DEBUG_COLORS && i < colors.length(); ++i)
|
||||||
{
|
{
|
||||||
switch(colors[i])
|
switch(colors[i])
|
||||||
{
|
{
|
||||||
|
|
|
@ -478,21 +478,47 @@ void VideoAudioDialog::addBezelTab()
|
||||||
ypos += lineHeight + VGAP * 3;
|
ypos += lineHeight + VGAP * 3;
|
||||||
myBezelShowWindowed = new CheckboxWidget(myTab, _font, xpos, ypos,
|
myBezelShowWindowed = new CheckboxWidget(myTab, _font, xpos, ypos,
|
||||||
"Show in windowed modes");
|
"Show in windowed modes");
|
||||||
//myBezelEnableCheckbox->setToolTip(Event::BezelToggle);
|
//myBezelShowWindowed->setToolTip(Event::BezelToggle);
|
||||||
wid.push_back(myBezelShowWindowed);
|
wid.push_back(myBezelShowWindowed);
|
||||||
|
|
||||||
|
// Disable auto borders
|
||||||
ypos += lineHeight + VGAP * 1;
|
ypos += lineHeight + VGAP * 1;
|
||||||
myTopBorderSlider = new SliderWidget(myTab, _font, xpos, ypos,
|
myManualBorders = new CheckboxWidget(myTab, _font, xpos, ypos,
|
||||||
"Top border ", 0, 0, 6 * fontWidth, "px");
|
"Manual borders", kAutoBordersChanged);
|
||||||
myTopBorderSlider->setMinValue(0); myTopBorderSlider->setMaxValue(50);
|
myManualBorders->setToolTip("Enable if automatic border detection fails.");
|
||||||
|
wid.push_back(myManualBorders);
|
||||||
|
xpos += INDENT;
|
||||||
|
|
||||||
|
const int lWidth = _font.getStringWidth("Bottom ");
|
||||||
|
const int sWidth = myBezelPath->getRight() - xpos - lWidth - 5.5 * fontWidth; // _w - HBORDER - xpos - lwidth;
|
||||||
|
ypos += lineHeight + VGAP * 1;
|
||||||
|
myLeftBorderSlider = new SliderWidget(myTab, _font, xpos, ypos, sWidth, lineHeight,
|
||||||
|
"Left ", 0, 0, 5 * fontWidth, "px");
|
||||||
|
myLeftBorderSlider->setMinValue(0); myLeftBorderSlider->setMaxValue(500);
|
||||||
|
myLeftBorderSlider->setTickmarkIntervals(10);
|
||||||
|
//myLeftBorderSlider->setToolTip(Event::VolumeDecrease, Event::VolumeIncrease);
|
||||||
|
wid.push_back(myLeftBorderSlider);
|
||||||
|
|
||||||
|
ypos += lineHeight + VGAP * 1;
|
||||||
|
myRightBorderSlider = new SliderWidget(myTab, _font, xpos, ypos, sWidth, lineHeight,
|
||||||
|
"Right ", 0, 0, 5 * fontWidth, "px");
|
||||||
|
myRightBorderSlider->setMinValue(0); myRightBorderSlider->setMaxValue(500);
|
||||||
|
myRightBorderSlider->setTickmarkIntervals(10);
|
||||||
|
//myRightBorderSlider->setToolTip(Event::VolumeDecrease, Event::VolumeIncrease);
|
||||||
|
wid.push_back(myRightBorderSlider);
|
||||||
|
|
||||||
|
ypos += lineHeight + VGAP * 1;
|
||||||
|
myTopBorderSlider = new SliderWidget(myTab, _font, xpos, ypos, sWidth, lineHeight,
|
||||||
|
"Top ", 0, 0, 5 * fontWidth, "px");
|
||||||
|
myTopBorderSlider->setMinValue(0); myTopBorderSlider->setMaxValue(250);
|
||||||
myTopBorderSlider->setTickmarkIntervals(5);
|
myTopBorderSlider->setTickmarkIntervals(5);
|
||||||
//myTopBorderSlider->setToolTip(Event::VolumeDecrease, Event::VolumeIncrease);
|
//myTopBorderSlider->setToolTip(Event::VolumeDecrease, Event::VolumeIncrease);
|
||||||
wid.push_back(myTopBorderSlider);
|
wid.push_back(myTopBorderSlider);
|
||||||
|
|
||||||
ypos += lineHeight + VGAP;
|
ypos += lineHeight + VGAP;
|
||||||
myBtmBorderSlider = new SliderWidget(myTab, _font, xpos, ypos,
|
myBtmBorderSlider = new SliderWidget(myTab, _font, xpos, ypos, sWidth, lineHeight,
|
||||||
"Bottom border ", 0, 0, 6 * fontWidth, "px");
|
"Bottom ", 0, 0, 5 * fontWidth, "px");
|
||||||
myBtmBorderSlider->setMinValue(0); myBtmBorderSlider->setMaxValue(50);
|
myBtmBorderSlider->setMinValue(0); myBtmBorderSlider->setMaxValue(250);
|
||||||
myBtmBorderSlider->setTickmarkIntervals(5);
|
myBtmBorderSlider->setTickmarkIntervals(5);
|
||||||
//myBtmBorderSlider->setToolTip(Event::VolumeDecrease, Event::VolumeIncrease);
|
//myBtmBorderSlider->setToolTip(Event::VolumeDecrease, Event::VolumeIncrease);
|
||||||
wid.push_back(myBtmBorderSlider);
|
wid.push_back(myBtmBorderSlider);
|
||||||
|
@ -748,6 +774,9 @@ void VideoAudioDialog::loadConfig()
|
||||||
myBezelEnableCheckbox->setState(settings.getBool("bezel.show"));
|
myBezelEnableCheckbox->setState(settings.getBool("bezel.show"));
|
||||||
myBezelPath->setText(settings.getString("bezel.dir"));
|
myBezelPath->setText(settings.getString("bezel.dir"));
|
||||||
myBezelShowWindowed->setState(settings.getBool("bezel.windowed"));
|
myBezelShowWindowed->setState(settings.getBool("bezel.windowed"));
|
||||||
|
myManualBorders->setState(!settings.getBool("bezel.autoborders"));
|
||||||
|
myLeftBorderSlider->setValue(settings.getInt("bezel.leftborder"));
|
||||||
|
myRightBorderSlider->setValue(settings.getInt("bezel.rightborder"));
|
||||||
myTopBorderSlider->setValue(settings.getInt("bezel.topborder"));
|
myTopBorderSlider->setValue(settings.getInt("bezel.topborder"));
|
||||||
myBtmBorderSlider->setValue(settings.getInt("bezel.bottomborder"));
|
myBtmBorderSlider->setValue(settings.getInt("bezel.bottomborder"));
|
||||||
handleBezelChange();
|
handleBezelChange();
|
||||||
|
@ -880,9 +909,11 @@ void VideoAudioDialog::saveConfig()
|
||||||
settings.setValue("bezel.show", myBezelEnableCheckbox->getState());
|
settings.setValue("bezel.show", myBezelEnableCheckbox->getState());
|
||||||
settings.setValue("bezel.dir", myBezelPath->getText());
|
settings.setValue("bezel.dir", myBezelPath->getText());
|
||||||
settings.setValue("bezel.windowed", myBezelShowWindowed->getState());
|
settings.setValue("bezel.windowed", myBezelShowWindowed->getState());
|
||||||
|
settings.setValue("bezel.autoborders", !myManualBorders->getState());
|
||||||
|
settings.setValue("bezel.leftborder", myLeftBorderSlider->getValueLabel());
|
||||||
|
settings.setValue("bezel.rightborder", myRightBorderSlider->getValueLabel());
|
||||||
settings.setValue("bezel.topborder", myTopBorderSlider->getValueLabel());
|
settings.setValue("bezel.topborder", myTopBorderSlider->getValueLabel());
|
||||||
settings.setValue("bezel.bottomborder", myBtmBorderSlider->getValueLabel());
|
settings.setValue("bezel.bottomborder", myBtmBorderSlider->getValueLabel());
|
||||||
cerr << myTopBorderSlider << endl;
|
|
||||||
|
|
||||||
// Note: The following has to happen after all video related setting have been saved
|
// Note: The following has to happen after all video related setting have been saved
|
||||||
if(instance().hasConsole())
|
if(instance().hasConsole())
|
||||||
|
@ -1022,8 +1053,7 @@ void VideoAudioDialog::setDefaults()
|
||||||
myBezelEnableCheckbox->setState(true);
|
myBezelEnableCheckbox->setState(true);
|
||||||
myBezelPath->setText(instance().userDir().getShortPath());
|
myBezelPath->setText(instance().userDir().getShortPath());
|
||||||
myBezelShowWindowed->setState(false);
|
myBezelShowWindowed->setState(false);
|
||||||
myTopBorderSlider->setValue(0);
|
myManualBorders->setState(false);
|
||||||
myBtmBorderSlider->setValue(0);
|
|
||||||
handleBezelChange();
|
handleBezelChange();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1193,12 +1223,15 @@ void VideoAudioDialog::handlePhosphorChange()
|
||||||
void VideoAudioDialog::handleBezelChange()
|
void VideoAudioDialog::handleBezelChange()
|
||||||
{
|
{
|
||||||
const bool enable = myBezelEnableCheckbox->getState();
|
const bool enable = myBezelEnableCheckbox->getState();
|
||||||
|
const bool nonAuto = myManualBorders->getState();
|
||||||
|
|
||||||
myOpenBrowserButton->setEnabled(enable);
|
myOpenBrowserButton->setEnabled(enable);
|
||||||
myBezelPath->setEnabled(enable);
|
myBezelPath->setEnabled(enable);
|
||||||
myBezelShowWindowed->setEnabled(enable);
|
myBezelShowWindowed->setEnabled(enable);
|
||||||
myTopBorderSlider->setEnabled(enable);
|
myLeftBorderSlider->setEnabled(enable && nonAuto);
|
||||||
myBtmBorderSlider->setEnabled(enable);
|
myRightBorderSlider->setEnabled(enable && nonAuto);
|
||||||
|
myTopBorderSlider->setEnabled(enable && nonAuto);
|
||||||
|
myBtmBorderSlider->setEnabled(enable && nonAuto);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -1317,6 +1350,7 @@ void VideoAudioDialog::handleCommand(CommandSender* sender, int cmd,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kBezelEnableChanged:
|
case kBezelEnableChanged:
|
||||||
|
case kAutoBordersChanged:
|
||||||
handleBezelChange();
|
handleBezelChange();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,9 @@ class VideoAudioDialog : public Dialog
|
||||||
ButtonWidget* myOpenBrowserButton{nullptr};
|
ButtonWidget* myOpenBrowserButton{nullptr};
|
||||||
EditTextWidget* myBezelPath{nullptr};
|
EditTextWidget* myBezelPath{nullptr};
|
||||||
CheckboxWidget* myBezelShowWindowed{nullptr};
|
CheckboxWidget* myBezelShowWindowed{nullptr};
|
||||||
|
CheckboxWidget* myManualBorders{nullptr};
|
||||||
|
SliderWidget* myLeftBorderSlider{nullptr};
|
||||||
|
SliderWidget* myRightBorderSlider{nullptr};
|
||||||
SliderWidget* myTopBorderSlider{nullptr};
|
SliderWidget* myTopBorderSlider{nullptr};
|
||||||
SliderWidget* myBtmBorderSlider{nullptr};
|
SliderWidget* myBtmBorderSlider{nullptr};
|
||||||
|
|
||||||
|
@ -180,6 +183,7 @@ class VideoAudioDialog : public Dialog
|
||||||
|
|
||||||
kBezelEnableChanged = 'BZen',
|
kBezelEnableChanged = 'BZen',
|
||||||
kChooseBezelDirCmd = 'BZsl',
|
kChooseBezelDirCmd = 'BZsl',
|
||||||
|
kAutoBordersChanged = 'BZab',
|
||||||
|
|
||||||
kSoundEnableChanged = 'ADse',
|
kSoundEnableChanged = 'ADse',
|
||||||
kDeviceChanged = 'ADdc',
|
kDeviceChanged = 'ADdc',
|
||||||
|
|
|
@ -993,6 +993,7 @@
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-NoDebugger|x64'">true</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-NoDebugger|x64'">true</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\emucore\Bankswitch.cxx" />
|
<ClCompile Include="..\..\emucore\Bankswitch.cxx" />
|
||||||
|
<ClCompile Include="..\..\emucore\Bezel.cxx" />
|
||||||
<ClCompile Include="..\..\emucore\Cart03E0.cxx" />
|
<ClCompile Include="..\..\emucore\Cart03E0.cxx" />
|
||||||
<ClCompile Include="..\..\emucore\Cart3EPlus.cxx" />
|
<ClCompile Include="..\..\emucore\Cart3EPlus.cxx" />
|
||||||
<ClCompile Include="..\..\emucore\Cart3EX.cxx" />
|
<ClCompile Include="..\..\emucore\Cart3EX.cxx" />
|
||||||
|
@ -2320,6 +2321,7 @@
|
||||||
<ClInclude Include="..\..\emucore\AmigaMouse.hxx" />
|
<ClInclude Include="..\..\emucore\AmigaMouse.hxx" />
|
||||||
<ClInclude Include="..\..\emucore\AtariMouse.hxx" />
|
<ClInclude Include="..\..\emucore\AtariMouse.hxx" />
|
||||||
<ClInclude Include="..\..\emucore\Bankswitch.hxx" />
|
<ClInclude Include="..\..\emucore\Bankswitch.hxx" />
|
||||||
|
<ClInclude Include="..\..\emucore\Bezel.hxx" />
|
||||||
<ClInclude Include="..\..\emucore\Cart03E0.hxx" />
|
<ClInclude Include="..\..\emucore\Cart03E0.hxx" />
|
||||||
<ClInclude Include="..\..\emucore\Cart3EPlus.hxx" />
|
<ClInclude Include="..\..\emucore\Cart3EPlus.hxx" />
|
||||||
<ClInclude Include="..\..\emucore\Cart3EX.hxx" />
|
<ClInclude Include="..\..\emucore\Cart3EX.hxx" />
|
||||||
|
|
|
@ -1209,6 +1209,9 @@
|
||||||
<ClCompile Include="..\..\debugger\gui\Cart03E0Widget.cxx">
|
<ClCompile Include="..\..\debugger\gui\Cart03E0Widget.cxx">
|
||||||
<Filter>Source Files\debugger\gui</Filter>
|
<Filter>Source Files\debugger\gui</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\emucore\Bezel.cxx">
|
||||||
|
<Filter>Source Files\emucore</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\common\bspf.hxx">
|
<ClInclude Include="..\..\common\bspf.hxx">
|
||||||
|
@ -2465,6 +2468,9 @@
|
||||||
<ClInclude Include="..\..\debugger\gui\Cart03E0Widget.hxx">
|
<ClInclude Include="..\..\debugger\gui\Cart03E0Widget.hxx">
|
||||||
<Filter>Header Files\debugger\gui</Filter>
|
<Filter>Header Files\debugger\gui</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\emucore\Bezel.hxx">
|
||||||
|
<Filter>Header Files\emucore</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="stella.ico">
|
<None Include="stella.ico">
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 994 KiB After Width: | Height: | Size: 549 KiB |
Loading…
Reference in New Issue