diff --git a/docs/graphics/options_video_tv.png b/docs/graphics/options_video_tv.png index 91e361c64..062db25da 100644 Binary files a/docs/graphics/options_video_tv.png and b/docs/graphics/options_video_tv.png differ diff --git a/docs/index.html b/docs/index.html index 3ea94ea6d..c9ff8a32d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1553,6 +1553,16 @@ Alt + 5 Cmd + 5 + + Switch to previous scanline mask + Shift-Alt + 6 + Shift-Cmd + 6 + + + Switch to next scanline mask + Alt + 6 + Cmd + 6 +
These settings can also be changed using Global Keys
@@ -2964,6 +2974,12 @@
Note: No scanlines in 1x mode snapshots + +
-tv.scanmask <standard|thin|pixel|aperture|mame>
+ Set the scanline mask. +
Note: All masks (except 'standard') work better at higher zoom levels. + +
-cheat <code>
Use the specified cheatcode (see Cheat section for description). @@ -3782,11 +3798,13 @@ (needs to be manually adjusted for your particular hardware)-tv.phosblend Scanline intensitySets scanline black-level intensity.
Note: No scanlines in 1x mode snapshots-tv.scanlines + (Scanline) MaskSets the scanline mask.
+ Note: All masks (except 'standard') work better at higher zoom levels-tv.scanmask Clone RGBCopy 'RGB' attributes to 'Custom' TV mode sliders  Clone S-VideoCopy 'S-Video' attributes to 'Custom' TV mode sliders  Clone CompositeCopy 'Composite' attributes to 'Custom' TV mode sliders  Clone Bad adjustCopy 'Bad Adjust' attributes to 'Custom' TV mode sliders  - RevertRevert attribute sliders to saved 'Custom' TV mode settings  + RevertRevert attribute sliders to previously saved 'Custom' TV mode settings  diff --git a/src/common/FBSurfaceSDL2.cxx b/src/common/FBSurfaceSDL2.cxx index a2b8d0166..b1588db73 100644 --- a/src/common/FBSurfaceSDL2.cxx +++ b/src/common/FBSurfaceSDL2.cxx @@ -278,6 +278,10 @@ void FBSurfaceSDL2::applyAttributes() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::setScalingInterpolation(ScalingInterpolation interpolation) { + if (interpolation == ScalingInterpolation::sharp + && mySrcGUIR.h() >= myDstGUIR.h()) + interpolation = ScalingInterpolation::blur; + if (interpolation == myInterpolationMode) return; myInterpolationMode = interpolation; diff --git a/src/common/sdl_blitter/QisBlitter.cxx b/src/common/sdl_blitter/QisBlitter.cxx index cf9ea16e9..a6633364b 100644 --- a/src/common/sdl_blitter/QisBlitter.cxx +++ b/src/common/sdl_blitter/QisBlitter.cxx @@ -147,14 +147,8 @@ void QisBlitter::recreateTexturesIfNecessary() SDL_TextureAccess texAccess = myStaticData == nullptr ? SDL_TEXTUREACCESS_STREAMING : SDL_TEXTUREACCESS_STATIC; - if(myDstRect.w > mySrcRect.w) - myIntermediateRect.w = (myDstRect.w / mySrcRect.w) * mySrcRect.w; - else - myIntermediateRect.w = mySrcRect.w; - if(myDstRect.h > mySrcRect.h) - myIntermediateRect.h = (myDstRect.h / mySrcRect.h) * mySrcRect.h; - else - myIntermediateRect.h = mySrcRect.h; + myIntermediateRect.w = (myDstRect.w / mySrcRect.w) * mySrcRect.w; + myIntermediateRect.h = (myDstRect.h / mySrcRect.h) * mySrcRect.h; myIntermediateRect.x = 0; myIntermediateRect.y = 0; diff --git a/src/emucore/GlobalKeyHandler.cxx b/src/emucore/GlobalKeyHandler.cxx index 7fdd87648..8815b6189 100644 --- a/src/emucore/GlobalKeyHandler.cxx +++ b/src/emucore/GlobalKeyHandler.cxx @@ -197,6 +197,8 @@ bool GlobalKeyHandler::skipAVSetting() const myOSystem.settings().getString("palette") == PaletteHandler::SETTING_CUSTOM; const bool isCustomFilter = myOSystem.settings().getInt("tv.filter") == int(NTSCFilter::Preset::CUSTOM); + const bool hasScanlines = + myOSystem.settings().getInt("tv.scanlines") > 0; const bool isSoftwareRenderer = myOSystem.settings().getString("video") == "software"; @@ -210,6 +212,7 @@ bool GlobalKeyHandler::skipAVSetting() const || (mySetting >= Setting::NTSC_SHARPNESS && mySetting <= Setting::NTSC_BLEEDING && !isCustomFilter) + || (mySetting == Setting::SCANLINE_MASK && !hasScanlines) || (mySetting == Setting::INTERPOLATION && isSoftwareRenderer); } @@ -375,7 +378,7 @@ GlobalKeyHandler::SettingData GlobalKeyHandler::getSettingData(const Setting set // Other TV effects adjustables {Setting::PHOSPHOR, {true, std::bind(&Console::changePhosphor, &myOSystem.console(), _1)}}, {Setting::SCANLINES, {true, std::bind(&TIASurface::changeScanlineIntensity, &myOSystem.frameBuffer().tiaSurface(), _1)}}, - {Setting::SCANLINE_MASK, {false, std::bind(&TIASurface::cycleScanlineMask, &myOSystem.frameBuffer().tiaSurface(), _1)}}, + {Setting::SCANLINE_MASK, {false, std::bind(&TIASurface::cycleScanlineMask, &myOSystem.frameBuffer().tiaSurface(), _1)}}, {Setting::INTERPOLATION, {false, std::bind(&Console::toggleInter, &myOSystem.console(), _1)}}, // *** Input group *** {Setting::DIGITAL_DEADZONE, {true, std::bind(&PhysicalJoystickHandler::changeDigitalDeadZone, &joyHandler(), _1)}}, diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index d77d40261..53f91359c 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -319,9 +319,10 @@ void Settings::validate() s = getString("tv.scanmask"); if(s != TIASurface::SETTING_STANDARD - && s != TIASurface::SETTING_THIN - && s != TIASurface::SETTING_PIXELS - && s != TIASurface::SETTING_MAME) + && s != TIASurface::SETTING_THIN + && s != TIASurface::SETTING_PIXELS + && s != TIASurface::SETTING_APERTURE + && s != TIASurface::SETTING_MAME) setValue("tv.scanmask", TIASurface::SETTING_STANDARD); i = getInt("tv.filter"); diff --git a/src/emucore/TIASurface.cxx b/src/emucore/TIASurface.cxx index 102355e1c..c95be538b 100644 --- a/src/emucore/TIASurface.cxx +++ b/src/emucore/TIASurface.cxx @@ -277,6 +277,7 @@ TIASurface::ScanlineMask TIASurface::scanlineMaskType(int direction) SETTING_STANDARD, SETTING_THIN, SETTING_PIXELS, + SETTING_APERTURE, SETTING_MAME }; int i = 0; @@ -302,10 +303,11 @@ TIASurface::ScanlineMask TIASurface::scanlineMaskType(int direction) void TIASurface::cycleScanlineMask(int direction) { const string Names[int(ScanlineMask::NumMasks)] = { - "'Standard'", - "'Thin lines'", - "'Pixelated'", - "'MAME'" + "Standard", + "Thin lines", + "Pixelated", + "Aperture Grille", + "MAME" }; int i = int(scanlineMaskType(direction)); @@ -314,7 +316,7 @@ void TIASurface::cycleScanlineMask(int direction) ostringstream msg; - msg << "Scanline pattern " << Names[i]; + msg << "Scanline pattern '" << Names[i] << "'"; myOSystem.frameBuffer().showTextMessage(msg.str()); } @@ -331,6 +333,10 @@ void TIASurface::enablePhosphor(bool enable, int blend) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::createScanlineSurface() { + // Idea: Emulate + // - Dot-Trio Shadow-Mask + // - Slot-Mask (NEC 'CromaClear') + // - Aperture-Grille (Sony 'Trinitron') struct PatternSize { uInt16 width{1}; @@ -345,15 +351,17 @@ void TIASurface::createScanlineSurface() {} }; std::array Sizes = {{ - PatternSize(1, 2, 1), - PatternSize(1, 3, 1), - PatternSize(3, 3, 2), - PatternSize(3, 4, 3) + PatternSize(1, 2, 1), // standard + PatternSize(1, 3, 1), // thin + PatternSize(3, 3, 2), // pixel + PatternSize(6, 3, 1), // aperture + PatternSize(3, 4, 3), // mame }}; + // Note: With RGB = 0,0,0, the average alpha should be ~0x55 (85) std::array>, int(ScanlineMask::NumMasks)> Pattern = {{ { // standard { 0x00000000 }, - { 0xff000000 }, + { 0xaa000000 }, // 0xff decreased to 0xaa (67%) to match overall brightness of other pattern }, { // thin lines { 0x00000000 }, { 0x00000000 }, @@ -367,12 +375,26 @@ void TIASurface::createScanlineSurface() //{ 0x04ffffff, 0x80e7e7e7, 0x20ffffff }, //{ 0xff282828, 0xff282828, 0xff282828 }, // same but using RGB = 0,0,0 - { 0x08000000, 0x02000000, 0x80000000 }, - { 0x08000000, 0x80000000, 0x40000000 }, - { 0xff000000, 0xff000000, 0xff000000 }, - { 0x80000000, 0x04000000, 0x04000000 }, - { 0x04000000, 0x80000000, 0x20000000 }, - { 0xff000000, 0xff000000, 0xff000000 }, + //{ 0x08000000, 0x02000000, 0x80000000 }, + //{ 0x08000000, 0x80000000, 0x40000000 }, + //{ 0xff000000, 0xff000000, 0xff000000 }, + //{ 0x80000000, 0x04000000, 0x04000000 }, + //{ 0x04000000, 0x80000000, 0x20000000 }, + //{ 0xff000000, 0xff000000, 0xff000000 }, + // brightened + { 0x06000000, 0x01000000, 0x5a000000 }, + { 0x06000000, 0x5a000000, 0x3d000000 }, + { 0xb4000000, 0xb4000000, 0xb4000000 }, + { 0x5a000000, 0x03000000, 0x03000000 }, + { 0x03000000, 0x5a000000, 0x17000000 }, + { 0xb4000000, 0xb4000000, 0xb4000000 }, + }, { // aperture (doubled & darkened, alpha */ 1.75) + //{ 0x2cf31d00, 0x1500ffce, 0x1c1200a4 }, + //{ 0x557e0f00, 0x40005044, 0x45070067 }, + //{ 0x800c0200, 0x89000606, 0x8d02000d }, + { 0x19f31d00, 0x0c00ffce, 0x101200a4, 0x19f31d00, 0x0c00ffce, 0x101200a4 }, + { 0x317e0f00, 0x25005044, 0x37070067, 0x317e0f00, 0x25005044, 0x37070067 }, + { 0xe00c0200, 0xf0000606, 0xf702000d, 0xe00c0200, 0xf0000606, 0xf702000d }, }, { // mame // original tile data from https://wiki.arcadeotaku.com/w/MAME_CRT_Simulation //{ 0xffb4b4b4, 0xffa5a5a5, 0xffc3c3c3 }, @@ -427,6 +449,7 @@ void TIASurface::createScanlineSurface() mySLineSurface->setSrcSize(mySLineSurface->width(), height); mySLineSurface->setDstRect(myTiaSurface->dstRect()); + updateSurfaceSettings(); enableNTSC(ntscEnabled()); } @@ -664,12 +687,13 @@ void TIASurface::renderForSnapshot() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::updateSurfaceSettings() { - myTiaSurface->setScalingInterpolation( - interpolationModeFromSettings(myOSystem.settings()) - ); - mySLineSurface->setScalingInterpolation( - interpolationModeFromSettings(myOSystem.settings()) - ); + if(myTiaSurface != nullptr) + myTiaSurface->setScalingInterpolation( + interpolationModeFromSettings(myOSystem.settings())); + + if(mySLineSurface != nullptr) + mySLineSurface->setScalingInterpolation( + interpolationModeFromSettings(myOSystem.settings())); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/TIASurface.hxx b/src/emucore/TIASurface.hxx index 09d914975..c9f3772ef 100644 --- a/src/emucore/TIASurface.hxx +++ b/src/emucore/TIASurface.hxx @@ -49,6 +49,7 @@ class TIASurface static constexpr const char* SETTING_STANDARD = "standard"; static constexpr const char* SETTING_THIN = "thin"; static constexpr const char* SETTING_PIXELS = "pixels"; + static constexpr const char* SETTING_APERTURE = "aperture"; static constexpr const char* SETTING_MAME = "mame"; /** @@ -198,6 +199,7 @@ class TIASurface Standard, Thin, Pixels, + Aperture, Mame, NumMasks }; diff --git a/src/gui/VideoAudioDialog.cxx b/src/gui/VideoAudioDialog.cxx index 0fdaa262e..1a8b984e7 100644 --- a/src/gui/VideoAudioDialog.cxx +++ b/src/gui/VideoAudioDialog.cxx @@ -384,10 +384,12 @@ void VideoAudioDialog::addTVEffectsTab() VarList::push_back(items, "Standard", TIASurface::SETTING_STANDARD); VarList::push_back(items, "Thin lines", TIASurface::SETTING_THIN); VarList::push_back(items, "Pixelated", TIASurface::SETTING_PIXELS); + VarList::push_back(items, "Aperture Gr.", TIASurface::SETTING_APERTURE); VarList::push_back(items, "MAME", TIASurface::SETTING_MAME); - pwidth = _font.getStringWidth("Thin lines"); - myTVScanMask = new PopUpWidget(myTab, _font, myTVScanIntense->getRight() + fontWidth * 2, + xpos = myTVScanIntense->getRight() + fontWidth * 2; + pwidth = _w - HBORDER - xpos - fontWidth * 5 - PopUpWidget::dropDownWidth(_font) - 2 * 2; + myTVScanMask = new PopUpWidget(myTab, _font, xpos, myTVScanIntense->getTop() + 1, pwidth, lineHeight, items, "Mask "); wid.push_back(myTVScanMask); @@ -894,7 +896,7 @@ void VideoAudioDialog::setDefaults() myTVPhosLevel->setValue(50); // TV scanline intensity & mask - myTVScanIntense->setValue(25); + myTVScanIntense->setValue(0); myTVScanMask->setSelected(TIASurface::SETTING_STANDARD); // Make sure that mutually-exclusive items are not enabled at the same time @@ -1155,9 +1157,13 @@ void VideoAudioDialog::handleCommand(CommandSender* sender, int cmd, { myTVScanIntense->setValueLabel("Off"); myTVScanIntense->setValueUnit(""); + myTVScanMask->setEnabled(false); } else + { myTVScanIntense->setValueUnit("%"); + myTVScanMask->setEnabled(true); + } break; case kPhosphorChanged: