mirror of https://github.com/stella-emu/stella.git
bezels working now (TODO: testing, doc)
This commit is contained in:
parent
88e737c6f4
commit
53b3d0901c
|
@ -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};
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 |
Binary file not shown.
After Width: | Height: | Size: 994 KiB |
Loading…
Reference in New Issue