bezels working now (TODO: testing, doc)

This commit is contained in:
thrust26 2023-08-19 18:12:32 +02:00
parent 88e737c6f4
commit 53b3d0901c
15 changed files with 259 additions and 123 deletions

View File

@ -273,9 +273,6 @@ 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};

View File

@ -78,19 +78,25 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface, VariantLi
// byte into separate bytes (useful for paletted and grayscale images).
png_set_packing(png_ptr);
// Only normal RBG(A) images are supported (without the alpha channel)
// Alpha channel is supported
if(color_type == PNG_COLOR_TYPE_RGBA)
{
hasAlpha = true;
//png_set_strip_alpha(png_ptr);
}
else if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
// TODO: preserve alpha
png_set_gray_to_rgb(png_ptr);
}
else if(color_type == PNG_COLOR_TYPE_PALETTE)
{
png_set_palette_to_rgb(png_ptr);
if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
{
png_set_tRNS_to_alpha(png_ptr);
hasAlpha = true;
}
else
png_set_palette_to_rgb(png_ptr);
}
else if(color_type != PNG_COLOR_TYPE_RGB)
{
@ -385,7 +391,7 @@ void PNGLibrary::takeSnapshot(uInt32 number)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PNGLibrary::allocateStorage(size_t width, size_t height, bool hasAlpha)
{
// Create space for the entire image (3 bytes per pixel in RGB format)
// Create space for the entire image (3(4) bytes per pixel in RGB(A) format)
const size_t req_buffer_size = width * height * (hasAlpha ? 4 : 3);
if(req_buffer_size > ReadInfo.buffer.capacity())
ReadInfo.buffer.reserve(req_buffer_size * 1.5);
@ -427,7 +433,7 @@ void PNGLibrary::loadImagetoSurface(FBSurface& surface, bool hasAlpha)
uInt32* s_ptr = s_buf;
if(hasAlpha)
for(uInt32 icol = 0; icol < ReadInfo.width; ++icol, i_ptr += 4)
*s_ptr++ = fb.mapRGBA(*i_ptr, *(i_ptr+1), *(i_ptr+2), 85/* *(i_ptr+3)*/);
*s_ptr++ = fb.mapRGBA(*i_ptr, *(i_ptr+1), *(i_ptr+2), *(i_ptr+3));
else
for(uInt32 icol = 0; icol < ReadInfo.width; ++icol, i_ptr += 3)
*s_ptr++ = fb.mapRGB(*i_ptr, *(i_ptr+1), *(i_ptr+2));

View File

@ -33,10 +33,9 @@ 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, bool showBezel)
{
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)
@ -57,7 +56,9 @@ const VideoModeHandler::Mode&
const float overscan = 1 - settings.getInt("tia.fs_overscan") / 100.0;
// First calculate maximum zoom that keeps aspect ratio
const float scaleX = myImage.w / myDisplay.w,
// Note: We are assuming a 16:9 bezel image here
const float bezelScaleW = showBezel ? (16.F / 9.F) / (4.F / 3.F) : 1;
const float scaleX = myImage.w / (myDisplay.w / bezelScaleW),
scaleY = static_cast<float>(myImage.h) / myDisplay.h;
float zoom = 1.F / std::max(scaleX, scaleY);
@ -114,22 +115,21 @@ VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh,
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;
// 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
if(fsIndex != -1) // fullscreen mode
{
switch(stretch)
{
case Stretch::Preserve:
iw *= overscan / scaleW;
iw *= overscan;
ih *= overscan;
break;
case Stretch::Fill:
// Scale to all available space
iw = screenS.w * (overscan / scaleW);
iw = screenS.w * (overscan / bezelScaleW);
ih = screenS.h * overscan;
break;
@ -148,7 +148,7 @@ VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh,
{
case Stretch::Preserve:
case Stretch::Fill:
screenS.w = iw * scaleW;
screenS.w = iw * bezelScaleW;
screenS.h = ih;
break;

View File

@ -95,7 +95,7 @@ class VideoModeHandler
@return A video mode based on the given criteria
*/
const VideoModeHandler::Mode& buildMode(const Settings& settings,
bool inTIAMode);
bool inTIAMode, bool showBezel);
private:
Common::Size myImage, myDisplay;

View File

@ -125,14 +125,13 @@ void BilinearBlitter::recreateTexturesIfNecessary()
SDL_UpdateTexture(myTexture, nullptr, myStaticData->pixels, myStaticData->pitch);
}
if (myAttributes.blending) {
const auto blendAlpha = static_cast<uInt8>(myAttributes.blendalpha * 2.55);
const std::array<SDL_Texture*, 2> textures = { myTexture, mySecondaryTexture };
for (SDL_Texture* texture: textures) {
if (!texture) continue;
const std::array<SDL_Texture*, 2> textures = { myTexture, mySecondaryTexture };
for (SDL_Texture* texture: textures) {
if (!texture) continue;
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
if (myAttributes.blending) {
const auto blendAlpha = static_cast<uInt8>(myAttributes.blendalpha * 2.55);
SDL_SetTextureAlphaMod(texture, blendAlpha);
}
}

View File

@ -71,8 +71,6 @@ FrameBuffer::FrameBuffer(OSystem& osystem)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBuffer::~FrameBuffer() // NOLINT (we need an empty d'tor)
{
if(myBezelSurface)
deallocateSurface(myBezelSurface);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -396,10 +394,10 @@ void FrameBuffer::update(UpdateMode mode)
{
myPausedCount = static_cast<uInt32>(7 * myOSystem.frameRate());
showTextMessage("Paused", MessagePosition::MiddleCenter);
myTIASurface->render(shade);
renderTIA(shade, false);
}
if(rerender)
myTIASurface->render(shade);
renderTIA(shade, false);
break; // EventHandlerState::PAUSE
}
@ -410,14 +408,12 @@ void FrameBuffer::update(UpdateMode mode)
redraw |= myOSystem.optionsMenu().needsRedraw();
if(redraw)
{
clear();
myTIASurface->render(true);
renderTIA(true);
myOSystem.optionsMenu().draw(forceRedraw);
}
else if(rerender)
{
clear();
myTIASurface->render(true);
renderTIA(true);
myOSystem.optionsMenu().render();
}
break; // EventHandlerState::OPTIONSMENU
@ -429,14 +425,12 @@ void FrameBuffer::update(UpdateMode mode)
redraw |= myOSystem.commandMenu().needsRedraw();
if(redraw)
{
clear();
myTIASurface->render(true);
renderTIA(true);
myOSystem.commandMenu().draw(forceRedraw);
}
else if(rerender)
{
clear();
myTIASurface->render(true);
renderTIA(true);
myOSystem.commandMenu().render();
}
break; // EventHandlerState::CMDMENU
@ -448,14 +442,12 @@ void FrameBuffer::update(UpdateMode mode)
redraw |= myOSystem.highscoresMenu().needsRedraw();
if(redraw)
{
clear();
myTIASurface->render(true);
renderTIA(true);
myOSystem.highscoresMenu().draw(forceRedraw);
}
else if(rerender)
{
clear();
myTIASurface->render(true);
renderTIA(true);
myOSystem.highscoresMenu().render();
}
break; // EventHandlerState::HIGHSCORESMENU
@ -467,8 +459,7 @@ void FrameBuffer::update(UpdateMode mode)
redraw |= myOSystem.messageMenu().needsRedraw();
if(redraw)
{
clear();
myTIASurface->render(true);
renderTIA(true);
myOSystem.messageMenu().draw(forceRedraw);
}
break; // EventHandlerState::MESSAGEMENU
@ -480,8 +471,7 @@ void FrameBuffer::update(UpdateMode mode)
redraw |= myOSystem.plusRomsMenu().needsRedraw();
if(redraw)
{
clear();
myTIASurface->render(true);
renderTIA(true);
myOSystem.plusRomsMenu().draw(forceRedraw);
}
break; // EventHandlerState::PLUSROMSMENU
@ -493,14 +483,12 @@ void FrameBuffer::update(UpdateMode mode)
redraw |= myOSystem.timeMachine().needsRedraw();
if(redraw)
{
clear();
myTIASurface->render();
renderTIA();
myOSystem.timeMachine().draw(forceRedraw);
}
else if(rerender)
{
clear();
myTIASurface->render();
renderTIA();
myOSystem.timeMachine().render();
}
break; // EventHandlerState::TIMEMACHINE
@ -532,7 +520,7 @@ void FrameBuffer::update(UpdateMode mode)
}
redraw |= success;
if(redraw)
myTIASurface->render();
renderTIA(false, false);
// Stop playback mode at the end of the state buffer
// and switch to Time Machine or Pause mode
@ -594,8 +582,7 @@ void FrameBuffer::updateInEmulationMode(float framesPerSecond)
// We don't worry about selective rendering here; the rendering
// always happens at the full framerate
clear(); // TODO - test this: it may cause slowdowns on older systems
myTIASurface->render();
renderTIA();
// Show frame statistics
if(myStatsMsg.enabled)
@ -608,7 +595,6 @@ void FrameBuffer::updateInEmulationMode(float framesPerSecond)
if(myMsg.enabled)
drawMessage();
myBezelSurface->render();
// Push buffers to screen
myBackend->renderToScreen();
}
@ -966,6 +952,17 @@ void FrameBuffer::resetSurfaces()
update(UpdateMode::REDRAW); // force full update
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::renderTIA(bool shade, bool doClear)
{
if(doClear)
clear(); // TODO - test this: it may cause slowdowns on older systems
myTIASurface->render(shade);
if(myBezelSurface)
myBezelSurface->render();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::setTIAPalette(const PaletteArray& rgb_palette)
{
@ -1273,9 +1270,14 @@ FBInitStatus FrameBuffer::applyVideoMode()
myVidModeHandler.setDisplaySize(myAbsDesktopSize[display]);
const bool inTIAMode = myOSystem.eventHandler().inTIAMode();
#ifdef IMAGE_SUPPORT
const bool showBezel = inTIAMode && myOSystem.settings().getBool("showbezel") && checkBezel();
#else
const bool showBezel = false;
#endif
// Build the new mode based on current settings
const VideoModeHandler::Mode& mode = myVidModeHandler.buildMode(s, inTIAMode);
const VideoModeHandler::Mode& mode = myVidModeHandler.buildMode(s, inTIAMode, showBezel);
if(mode.imageR.size() > mode.screenS)
return FBInitStatus::FailTooLarge;
@ -1307,22 +1309,12 @@ 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 (USA).png");
//loadBezel(path + "Asteroids (USA).png");
}
#ifdef IMAGE_SUPPORT
if(myBezelSurface)
deallocateSurface(myBezelSurface);
if(showBezel)
loadBezel();
#endif
resetSurfaces();
setCursorState();
@ -1337,48 +1329,63 @@ FBInitStatus FrameBuffer::applyVideoMode()
return status;
}
#ifdef IMAGE_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBuffer::loadBezel(const string& fileName)
bool FrameBuffer::checkBezel()
{
try
const string& path = myOSystem.bezelDir().getPath();
const string& cartName = myOSystem.console().properties().get(PropType::Cart_Name);
FSNode node(path + cartName + ".png");
if(!node.exists())
{
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<float>(myActiveVidMode.screenS.w) / src.w(),
static_cast<float>(myActiveVidMode.screenS.h) / src.h()
) * myOSystem.frameBuffer().hidpiScaleFactor();
myBezelSurface->setDstSize(
static_cast<uInt32>(std::round(src.w() * scale)),
static_cast<uInt32>(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;
FSNode defaultNode(path + "default.png");
return defaultNode.exists();
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBuffer::loadBezel()
{
const string& path = myOSystem.bezelDir().getPath();
const string& cartName = myOSystem.console().properties().get(PropType::Cart_Name);
bool isValid = true;
myBezelSurface = allocateSurface(myActiveVidMode.screenS.w, myActiveVidMode.screenS.h);
try
{
VariantList metaData;
myOSystem.png().loadImage(path + cartName + ".png", *myBezelSurface, metaData);
}
catch(const runtime_error&)
{
try
{
VariantList metaData;
myOSystem.png().loadImage(path + "default.png", *myBezelSurface, metaData);
}
catch(const runtime_error&)
{
isValid = false;
}
}
if(isValid)
{
// Scale bezel to fullscreen (preserve or stretch) or window size
const uInt32 bezelH = std::min(myActiveVidMode.screenS.h,
myActiveVidMode.imageR.h());
myBezelSurface->setDstSize(myActiveVidMode.screenS.w, bezelH);
myBezelSurface->setDstPos(0, (myActiveVidMode.screenS.h - bezelH) / 2); // center vertically
myBezelSurface->setScalingInterpolation(ScalingInterpolation::sharp);
}
if(myBezelSurface)
myBezelSurface->setVisible(isValid);
return isValid;
}
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
float FrameBuffer::maxWindowZoom() const
{

View File

@ -410,6 +410,14 @@ class FrameBuffer
*/
void resetSurfaces();
/**
Renders TIA and overlaying, optional bezel surface
@param shade Shade the TIA surface after rendering
@param doClear Clear the framebuffer before rendering
*/
void renderTIA(bool shade = false, bool doClear = true);
#ifdef GUI_SUPPORT
/**
Helps to create a basic message onscreen.
@ -454,10 +462,21 @@ class FrameBuffer
*/
FBInitStatus applyVideoMode();
#ifdef IMAGE_SUPPORT
/**
Load the bezel for the given ROM filename.
Check if a bezel for the current ROM name exists.
@return Whether the bezel was found or not
*/
bool loadBezel(const string& romFileName);
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
@ -537,7 +556,7 @@ class FrameBuffer
// The TIASurface class takes responsibility for TIA rendering
shared_ptr<TIASurface> myTIASurface;
// The BezelSurface class takes responsibility for TIA rendering
// The BezelSurface which blends over the TIA surface
shared_ptr<FBSurface> myBezelSurface;
// Used for onscreen messages and frame statistics

View File

@ -308,6 +308,14 @@ void OSystem::setConfigPaths()
mySnapshotLoadDir = FSNode(ssLoadDir);
if(!mySnapshotLoadDir.isDirectory())
mySnapshotLoadDir.makeDir();
const string_view bezelDir = mySettings->getString("bezeldir");
if(bezelDir == EmptyString)
myBezelDir = userDir();
else
myBezelDir = FSNode(bezelDir);
if(!myBezelDir.isDirectory())
myBezelDir.makeDir();
#endif
myCheatFile = myBaseDir; myCheatFile /= "stella.cht";

View File

@ -303,11 +303,12 @@ class OSystem
#ifdef IMAGE_SUPPORT
/**
Return the full/complete path name for saving and loading
PNG snapshots.
Return the full/complete path name for saving snapshots, loading
launcher images and loading bezels.
*/
const FSNode& snapshotSaveDir() const { return mySnapshotSaveDir; }
const FSNode& snapshotLoadDir() const { return mySnapshotLoadDir; }
const FSNode& bezelDir() const { return myBezelDir; }
#endif
/**
@ -599,7 +600,7 @@ class OSystem
private:
FSNode myBaseDir, myStateDir, mySnapshotSaveDir, mySnapshotLoadDir,
myNVRamDir, myCfgDir, myHomeDir, myUserDir;
myNVRamDir, myCfgDir, myHomeDir, myUserDir, myBezelDir;
FSNode myCheatFile, myPaletteFile;
FSNode myRomFile; string myRomMD5;

View File

@ -161,6 +161,7 @@ Settings::Settings()
setPermanent("romdir", "");
setPermanent("userdir", "");
setPermanent("saveuserdir", "false");
setPermanent("bezeldir", "");
// ROM browser options
setPermanent("exitlauncher", "false");
@ -539,6 +540,7 @@ void Settings::usage()
<< " -turbo <1|0> Enable 'Turbo' mode for maximum emulation speed\n"
<< " -uimessages <1|0> Show onscreen UI messages for different events\n"
<< " -pausedim <1|0> Enable emulation dimming in pause mode\n"
<< " -showbezel <1|0> Show bezel left and right of emulation\n"
<< endl
#ifdef SOUND_SUPPORT
<< " -audio.enabled <1|0> Enable audio\n"
@ -656,6 +658,7 @@ void Settings::usage()
<< " -followlauncher <0|1> Default ROM path follows launcher navigation\n"
<< " -userdir <dir> Set the path to save user files to\n"
<< " -saveuserdir <0|1> Update user path when navigating in browser\n"
<< " -bezeldir <dir> Set the path to load bezels from\n"
<< " -lastrom <name> Last played ROM, automatically selected in\n"
<< " launcher\n"
<< " -romloadcount <number> Number of ROM to load next from multicard\n"

View File

@ -299,7 +299,7 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent,
bwidth = font.getStringWidth("Image path" + ELLIPSIS) + fontWidth * 2 + 1;
myOpenBrowserButton = new ButtonWidget(myTab, font, xpos, ypos, bwidth, buttonHeight,
"Image path" + ELLIPSIS, kChooseSnapLoadDirCmd);
myOpenBrowserButton->setToolTip("Select path for snapshot images used in Launcher.");
myOpenBrowserButton->setToolTip("Select path for images used in Launcher.");
wid.push_back(myOpenBrowserButton);
mySnapLoadPath = new EditTextWidget(myTab, font, HBORDER + lwidth,

View File

@ -23,6 +23,7 @@
#include "Cart.hxx"
#include "CartDPC.hxx"
#include "Dialog.hxx"
#include "BrowserDialog.hxx"
#include "OSystem.hxx"
#include "EditTextWidget.hxx"
#include "PopUpWidget.hxx"
@ -79,6 +80,7 @@ VideoAudioDialog::VideoAudioDialog(OSystem& osystem, DialogContainer& parent,
addDisplayTab();
addPaletteTab();
addTVEffectsTab();
addBezelTab();
addAudioTab();
// Add Defaults, OK and Cancel buttons
@ -351,7 +353,7 @@ void VideoAudioDialog::addTVEffectsTab()
int pwidth = _font.getStringWidth("Bad adjust ");
WidgetArray wid;
VariantList items;
const int tabID = myTab->addTab(" TV Effects ", TabWidget::AUTO_WIDTH);
const int tabID = myTab->addTab("TV Effects", TabWidget::AUTO_WIDTH);
items.clear();
VarList::push_back(items, "Disabled", static_cast<uInt32>(NTSCFilter::Preset::OFF));
@ -438,6 +440,47 @@ void VideoAudioDialog::addTVEffectsTab()
myTab->parentWidget(tabID)->setHelpAnchor("VideoAudioEffects");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void VideoAudioDialog::addBezelTab()
{
const int lineHeight = Dialog::lineHeight(),
buttonHeight = Dialog::buttonHeight(),
fontWidth = Dialog::fontWidth(),
VBORDER = Dialog::vBorder(),
HBORDER = Dialog::hBorder(),
VGAP = Dialog::vGap();
const int INDENT = CheckboxWidget::prefixSize(_font);
int xpos = HBORDER,
ypos = VBORDER;
WidgetArray wid;
const int tabID = myTab->addTab(" Bezels ", TabWidget::AUTO_WIDTH);
// Enable bezels
myBezelEnableCheckbox = new CheckboxWidget(myTab, _font, xpos, ypos,
"Enable bezels", kBezelEnableChanged);
//myBezelEnableCheckbox->setToolTip(Event::BezelToggle);
wid.push_back(myBezelEnableCheckbox);
xpos += INDENT;
ypos += lineHeight + VGAP;
// Bezel path
int bwidth = _font.getStringWidth("Bezel path" + ELLIPSIS) + fontWidth * 2 + 1;
myOpenBrowserButton = new ButtonWidget(myTab, _font, xpos, ypos, bwidth, buttonHeight,
"Bezel path" + ELLIPSIS, kChooseBezelDirCmd);
myOpenBrowserButton->setToolTip("Select path for bezels.");
wid.push_back(myOpenBrowserButton);
myBezelPath = new EditTextWidget(myTab, _font, xpos + bwidth + fontWidth,
ypos + (buttonHeight - lineHeight) / 2 - 1,
_w - xpos - bwidth - fontWidth - HBORDER - 2, lineHeight, "");
wid.push_back(myBezelPath);
// Add items for tab 4
addToFocusList(wid, myTab, tabID);
myTab->parentWidget(tabID)->setHelpAnchor("TODO???");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void VideoAudioDialog::addAudioTab()
{
@ -450,7 +493,7 @@ void VideoAudioDialog::addAudioTab()
int lwidth = _font.getStringWidth("Volume "), pwidth = 0;
WidgetArray wid;
VariantList items;
const int tabID = myTab->addTab(" Audio ", TabWidget::AUTO_WIDTH);
const int tabID = myTab->addTab(" Audio ", TabWidget::AUTO_WIDTH);
int xpos = HBORDER, ypos = VBORDER;
@ -460,7 +503,7 @@ void VideoAudioDialog::addAudioTab()
mySoundEnableCheckbox->setToolTip(Event::SoundToggle);
wid.push_back(mySoundEnableCheckbox);
ypos += lineHeight + VGAP;
xpos += CheckboxWidget::prefixSize(_font);
xpos += INDENT;
// Volume
myVolumeSlider = new SliderWidget(myTab, _font, xpos, ypos,
@ -563,7 +606,7 @@ void VideoAudioDialog::addAudioTab()
myDpcPitch->setTickmarkIntervals(2);
wid.push_back(myDpcPitch);
// Add items for tab 4
// Add items for tab 5
addToFocusList(wid, myTab, tabID);
myTab->parentWidget(tabID)->setHelpAnchor("VideoAudioAudio");
@ -679,6 +722,12 @@ void VideoAudioDialog::loadConfig()
myTVScanIntense->setValue(settings.getInt("tv.scanlines"));
myTVScanMask->setSelected(settings.getString("tv.scanmask"), TIASurface::SETTING_STANDARD);
/////////////////////////////////////////////////////////////////////////////
// Bezel tab
myBezelEnableCheckbox->setState(settings.getBool("showbezel"));
myBezelPath->setText(settings.getString("bezeldir"));
handleBezelChange();
/////////////////////////////////////////////////////////////////////////////
// Audio tab
AudioSettings& audioSettings = instance().audioSettings();
@ -709,7 +758,7 @@ void VideoAudioDialog::loadConfig()
updateSettingsWithPreset(instance().audioSettings());
updateEnabledState();
updateAudioEnabledState();
myTab->loadConfig();
}
@ -803,6 +852,12 @@ void VideoAudioDialog::saveConfig()
settings.setValue("tv.scanlines", myTVScanIntense->getValueLabel());
settings.setValue("tv.scanmask", myTVScanMask->getSelectedTag());
/////////////////////////////////////////////////////////////////////////////
// Bezel tab
settings.setValue("showbezel", myBezelEnableCheckbox->getState());
settings.setValue("bezeldir", myBezelPath->getText());
// Note: The following has to happen after all video related setting have been saved
if(instance().hasConsole())
{
instance().console().setTIAProperties();
@ -936,7 +991,13 @@ void VideoAudioDialog::setDefaults()
loadTVAdjustables(NTSCFilter::Preset::CUSTOM);
break;
}
case 3: // Audio
case 3: // Bezels
myBezelEnableCheckbox->setState(true);
myBezelPath->setText(instance().userDir().getShortPath());
handleBezelChange();
break;
case 4: // Audio
mySoundEnableCheckbox->setState(AudioSettings::DEFAULT_ENABLED);
myVolumeSlider->setValue(AudioSettings::DEFAULT_VOLUME);
myDevicePopup->setSelected(AudioSettings::DEFAULT_DEVICE);
@ -953,7 +1014,7 @@ void VideoAudioDialog::setDefaults()
}
else updatePreset();
updateEnabledState();
updateAudioEnabledState();
break;
default: // satisfy compiler
@ -1098,6 +1159,13 @@ void VideoAudioDialog::handlePhosphorChange()
myTVPhosLevel->setEnabled(myTVPhosphor->getState());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void VideoAudioDialog::handleBezelChange()
{
myOpenBrowserButton->setEnabled(myBezelEnableCheckbox->getState());
myBezelPath->setEnabled(myBezelEnableCheckbox->getState());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void VideoAudioDialog::handleCommand(CommandSender* sender, int cmd,
int data, int id)
@ -1213,13 +1281,26 @@ void VideoAudioDialog::handleCommand(CommandSender* sender, int cmd,
myTVPhosLevel->setValueUnit("%");
break;
case kBezelEnableChanged:
handleBezelChange();
break;
case kChooseBezelDirCmd:
BrowserDialog::show(this, _font, "Select Bezel Directory",
myBezelPath->getText(),
BrowserDialog::Mode::Directories,
[this](bool OK, const FSNode& node) {
if(OK) myBezelPath->setText(node.getShortPath());
});
break;
case kSoundEnableChanged:
updateEnabledState();
updateAudioEnabledState();
break;
case kModeChanged:
updatePreset();
updateEnabledState();
updateAudioEnabledState();
break;
case kHeadroomChanged:
@ -1300,7 +1381,7 @@ void VideoAudioDialog::colorPalette()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void VideoAudioDialog::updateEnabledState()
void VideoAudioDialog::updateAudioEnabledState()
{
const bool active = mySoundEnableCheckbox->getState();
const auto preset = static_cast<AudioSettings::Preset>

View File

@ -26,6 +26,7 @@ class PopUpWidget;
class RadioButtonGroup;
class SliderWidget;
class StaticTextWidget;
class EditTextWidget;
class TabWidget;
class OSystem;
@ -49,7 +50,9 @@ class VideoAudioDialog : public Dialog
void addDisplayTab();
void addPaletteTab();
void addTVEffectsTab();
void addBezelTab();
void addAudioTab();
void handleTVModeChange(NTSCFilter::Preset);
void loadTVAdjustables(NTSCFilter::Preset preset);
void handleRendererChanged();
@ -59,11 +62,15 @@ class VideoAudioDialog : public Dialog
void handleFullScreenChange();
void handleOverscanChange();
void handlePhosphorChange();
void handleBezelChange();
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
void addPalette(int x, int y, int w, int h);
void colorPalette();
void updatePreset();
void updateEnabledState();
void updateAudioEnabledState();
void updateSettingsWithPreset(AudioSettings&);
private:
@ -123,6 +130,11 @@ class VideoAudioDialog : public Dialog
std::array<StaticTextWidget*, 16> myColorLbl{nullptr};
ColorWidget* myColor[16][8]{{nullptr}};
// Bezels
CheckboxWidget* myBezelEnableCheckbox{nullptr};
ButtonWidget* myOpenBrowserButton{nullptr};
EditTextWidget* myBezelPath{nullptr};
// Audio
CheckboxWidget* mySoundEnableCheckbox{nullptr};
SliderWidget* myVolumeSlider{nullptr};
@ -163,6 +175,9 @@ class VideoAudioDialog : public Dialog
kPhosBlendChanged = 'VDbl',
kScanlinesChanged = 'VDsc',
kBezelEnableChanged = 'BZen',
kChooseBezelDirCmd = 'BZsl',
kSoundEnableChanged = 'ADse',
kDeviceChanged = 'ADdc',
kModeChanged = 'ADmc',

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

BIN
test/bezels/default.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 KiB