mirror of https://github.com/stella-emu/stella.git
added different mask pattern for scanline emulation
This commit is contained in:
parent
18db3456f4
commit
6238b5efbb
|
@ -25,6 +25,8 @@
|
|||
|
||||
* Added 'Check for Update' button to Help dialog.
|
||||
|
||||
* Added different mask pattern for scanline emulation (TODO: doc)
|
||||
|
||||
* Fixed MindLink controller.
|
||||
|
||||
* Fixed SaveKey not working with QuadTari.
|
||||
|
|
|
@ -23,7 +23,7 @@ class OSystem;
|
|||
#include <array>
|
||||
|
||||
/**
|
||||
This class takes care developer settings sets.
|
||||
This class takes care of developer settings sets.
|
||||
|
||||
@author Thomas Jentzsch
|
||||
*/
|
||||
|
@ -33,7 +33,7 @@ class DevSettingsHandler
|
|||
enum SettingsSet {
|
||||
player,
|
||||
developer,
|
||||
numSettings
|
||||
numSets
|
||||
};
|
||||
|
||||
DevSettingsHandler(OSystem& osystem);
|
||||
|
@ -45,40 +45,40 @@ class DevSettingsHandler
|
|||
protected:
|
||||
OSystem& myOSystem;
|
||||
// Emulator sets
|
||||
std::array<bool, numSettings> myFrameStats;
|
||||
std::array<bool, numSettings> myDetectedInfo;
|
||||
std::array<bool, numSettings> myExternAccess;
|
||||
std::array<int, numSettings> myConsole;
|
||||
std::array<bool, numSettings> myRandomBank;
|
||||
std::array<bool, numSettings> myRandomizeTIA;
|
||||
std::array<bool, numSettings> myRandomizeRAM;
|
||||
std::array<string, numSettings> myRandomizeCPU;
|
||||
std::array<bool, numSettings> myColorLoss;
|
||||
std::array<bool, numSettings> myTVJitter;
|
||||
std::array<int, numSettings> myTVJitterRec;
|
||||
std::array<bool, numSettings> myDebugColors;
|
||||
std::array<bool, numSettings> myUndrivenPins;
|
||||
std::array<bool, numSets> myFrameStats;
|
||||
std::array<bool, numSets> myDetectedInfo;
|
||||
std::array<bool, numSets> myExternAccess;
|
||||
std::array<int, numSets> myConsole;
|
||||
std::array<bool, numSets> myRandomBank;
|
||||
std::array<bool, numSets> myRandomizeTIA;
|
||||
std::array<bool, numSets> myRandomizeRAM;
|
||||
std::array<string, numSets> myRandomizeCPU;
|
||||
std::array<bool, numSets> myColorLoss;
|
||||
std::array<bool, numSets> myTVJitter;
|
||||
std::array<int, numSets> myTVJitterRec;
|
||||
std::array<bool, numSets> myDebugColors;
|
||||
std::array<bool, numSets> myUndrivenPins;
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
std::array<bool, numSettings> myRWPortBreak;
|
||||
std::array<bool, numSettings> myWRPortBreak;
|
||||
std::array<bool, numSets> myRWPortBreak;
|
||||
std::array<bool, numSets> myWRPortBreak;
|
||||
#endif
|
||||
std::array<bool, numSettings> myThumbException;
|
||||
std::array<bool, numSets> myThumbException;
|
||||
// TIA sets
|
||||
std::array<string, numSettings> myTIAType;
|
||||
std::array<bool, numSettings> myPlInvPhase;
|
||||
std::array<bool, numSettings> myMsInvPhase;
|
||||
std::array<bool, numSettings> myBlInvPhase;
|
||||
std::array<bool, numSettings> myPFBits;
|
||||
std::array<bool, numSettings> myPFColor;
|
||||
std::array<bool, numSettings> myBKColor;
|
||||
std::array<bool, numSettings> myPlSwap;
|
||||
std::array<bool, numSettings> myBlSwap;
|
||||
std::array<string, numSets> myTIAType;
|
||||
std::array<bool, numSets> myPlInvPhase;
|
||||
std::array<bool, numSets> myMsInvPhase;
|
||||
std::array<bool, numSets> myBlInvPhase;
|
||||
std::array<bool, numSets> myPFBits;
|
||||
std::array<bool, numSets> myPFColor;
|
||||
std::array<bool, numSets> myBKColor;
|
||||
std::array<bool, numSets> myPlSwap;
|
||||
std::array<bool, numSets> myBlSwap;
|
||||
// States sets
|
||||
std::array<bool, numSettings> myTimeMachine;
|
||||
std::array<int, numSettings> myStateSize;
|
||||
std::array<int, numSettings> myUncompressed;
|
||||
std::array<string, numSettings> myStateInterval;
|
||||
std::array<string, numSettings> myStateHorizon;
|
||||
std::array<bool, numSets> myTimeMachine;
|
||||
std::array<int, numSets> myStateSize;
|
||||
std::array<int, numSets> myUncompressed;
|
||||
std::array<string, numSets> myStateInterval;
|
||||
std::array<string, numSets> myStateHorizon;
|
||||
|
||||
private:
|
||||
void handleEnableDebugColors(bool enable);
|
||||
|
|
|
@ -644,6 +644,8 @@ PhysicalKeyboardHandler::DefaultCommonMapping = {
|
|||
{ Event::TogglePhosphor, KBDK_P, MOD3 },
|
||||
{ Event::ScanlinesDecrease, KBDK_5, KBDM_SHIFT | MOD3 },
|
||||
{ Event::ScanlinesIncrease, KBDK_5, MOD3 },
|
||||
{ Event::PreviousScanlineMask, KBDK_6, KBDM_SHIFT | MOD3 },
|
||||
{ Event::NextScanlineMask, KBDK_6, MOD3 },
|
||||
{ Event::PreviousPaletteAttribute, KBDK_9, KBDM_SHIFT | MOD3 },
|
||||
{ Event::NextPaletteAttribute, KBDK_9, MOD3 },
|
||||
{ Event::PaletteAttributeDecrease, KBDK_0, KBDM_SHIFT | MOD3 },
|
||||
|
|
|
@ -345,6 +345,8 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
|
|||
{Event::NextAttribute, "NextAttribute"},
|
||||
{Event::DecreaseAttribute, "DecreaseAttribute"},
|
||||
{Event::IncreaseAttribute, "IncreaseAttribute"},
|
||||
{Event::PreviousScanlineMask, "PreviousScanlineMask"},
|
||||
{Event::NextScanlineMask, "NextScanlineMask"},
|
||||
{Event::ScanlinesDecrease, "ScanlinesDecrease"},
|
||||
{Event::ScanlinesIncrease, "ScanlinesIncrease"},
|
||||
{Event::PhosphorDecrease, "PhosphorDecrease"},
|
||||
|
|
|
@ -147,8 +147,14 @@ void QisBlitter::recreateTexturesIfNecessary()
|
|||
|
||||
SDL_TextureAccess texAccess = myStaticData == nullptr ? SDL_TEXTUREACCESS_STREAMING : SDL_TEXTUREACCESS_STATIC;
|
||||
|
||||
myIntermediateRect.w = (myDstRect.w / mySrcRect.w) * mySrcRect.w;
|
||||
myIntermediateRect.h = (myDstRect.h / mySrcRect.h) * mySrcRect.h;
|
||||
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.x = 0;
|
||||
myIntermediateRect.y = 0;
|
||||
|
||||
|
|
|
@ -111,6 +111,7 @@ class Event
|
|||
PreviousVideoMode, NextVideoMode,
|
||||
PreviousAttribute, NextAttribute, DecreaseAttribute, IncreaseAttribute,
|
||||
ScanlinesDecrease, ScanlinesIncrease,
|
||||
PreviousScanlineMask, NextScanlineMask,
|
||||
PhosphorDecrease, PhosphorIncrease, TogglePhosphor, ToggleInter,
|
||||
ToggleDeveloperSet, JitterDecrease, JitterIncrease, ToggleJitter,
|
||||
|
||||
|
|
|
@ -713,7 +713,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
case Event::ScanlinesDecrease:
|
||||
if(pressed)
|
||||
{
|
||||
myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-1);
|
||||
myOSystem.frameBuffer().tiaSurface().changeScanlineIntensity(-1);
|
||||
myGlobalKeyHandler->setSetting(GlobalKeyHandler::Setting::SCANLINES);
|
||||
}
|
||||
return;
|
||||
|
@ -721,11 +721,27 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
case Event::ScanlinesIncrease:
|
||||
if(pressed)
|
||||
{
|
||||
myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+1);
|
||||
myOSystem.frameBuffer().tiaSurface().changeScanlineIntensity(+1);
|
||||
myGlobalKeyHandler->setSetting(GlobalKeyHandler::Setting::SCANLINES);
|
||||
}
|
||||
return;
|
||||
|
||||
case Event::PreviousScanlineMask:
|
||||
if(pressed && !repeated)
|
||||
{
|
||||
myOSystem.frameBuffer().tiaSurface().cycleScanlineMask(-1);
|
||||
myGlobalKeyHandler->setSetting(GlobalKeyHandler::Setting::SCANLINE_MASK);
|
||||
}
|
||||
return;
|
||||
|
||||
case Event::NextScanlineMask:
|
||||
if(pressed && !repeated)
|
||||
{
|
||||
myOSystem.frameBuffer().tiaSurface().cycleScanlineMask(+1);
|
||||
myGlobalKeyHandler->setSetting(GlobalKeyHandler::Setting::SCANLINE_MASK);
|
||||
}
|
||||
return;
|
||||
|
||||
case Event::ToggleInter:
|
||||
if(pressed && !repeated)
|
||||
{
|
||||
|
@ -2882,6 +2898,8 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { {
|
|||
{ Event::PhosphorIncrease, "Increase 'phosphor' blend", "" },
|
||||
{ Event::ScanlinesDecrease, "Decrease scanlines", "" },
|
||||
{ Event::ScanlinesIncrease, "Increase scanlines", "" },
|
||||
{ Event::PreviousScanlineMask, "Switch to previous scanline mask", "" },
|
||||
{ Event::NextScanlineMask, "Switch to next scanline mask", "" },
|
||||
|
||||
{ Event::PreviousSettingGroup, "Select previous setting group", "" },
|
||||
{ Event::NextSettingGroup, "Select next setting group", "" },
|
||||
|
@ -3050,6 +3068,7 @@ const Event::EventSet EventHandler::AudioVideoEvents = {
|
|||
Event::PreviousAttribute, Event::NextAttribute, Event::DecreaseAttribute, Event::IncreaseAttribute,
|
||||
Event::PhosphorDecrease, Event::PhosphorIncrease, Event::TogglePhosphor,
|
||||
Event::ScanlinesDecrease, Event::ScanlinesIncrease,
|
||||
Event::PreviousScanlineMask, Event::NextScanlineMask,
|
||||
Event::ToggleInter,
|
||||
};
|
||||
|
||||
|
|
|
@ -522,7 +522,7 @@ class EventHandler
|
|||
#else
|
||||
REFRESH_SIZE = 0,
|
||||
#endif
|
||||
EMUL_ACTIONLIST_SIZE = 219 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE,
|
||||
EMUL_ACTIONLIST_SIZE = 221 + PNG_SIZE + COMBO_SIZE + REFRESH_SIZE,
|
||||
MENU_ACTIONLIST_SIZE = 19
|
||||
;
|
||||
|
||||
|
|
|
@ -1201,7 +1201,7 @@ void FrameBuffer::switchVideoMode(int direction)
|
|||
}
|
||||
|
||||
saveCurrentWindowPosition();
|
||||
if(applyVideoMode() == FBInitStatus::Success)
|
||||
if(!direction || applyVideoMode() == FBInitStatus::Success)
|
||||
{
|
||||
if(fullScreen())
|
||||
showTextMessage(myActiveVidMode.description);
|
||||
|
|
|
@ -374,7 +374,8 @@ GlobalKeyHandler::SettingData GlobalKeyHandler::getSettingData(const Setting set
|
|||
int(NTSCFilter::Adjustables::BLEEDING), _1)}},
|
||||
// Other TV effects adjustables
|
||||
{Setting::PHOSPHOR, {true, std::bind(&Console::changePhosphor, &myOSystem.console(), _1)}},
|
||||
{Setting::SCANLINES, {true, std::bind(&TIASurface::setScanlineIntensity, &myOSystem.frameBuffer().tiaSurface(), _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::INTERPOLATION, {false, std::bind(&Console::toggleInter, &myOSystem.console(), _1)}},
|
||||
// *** Input group ***
|
||||
{Setting::DIGITAL_DEADZONE, {true, std::bind(&PhysicalJoystickHandler::changeDigitalDeadZone, &joyHandler(), _1)}},
|
||||
|
|
|
@ -70,6 +70,7 @@ class GlobalKeyHandler
|
|||
// Other TV effects adjustables
|
||||
PHOSPHOR,
|
||||
SCANLINES,
|
||||
SCANLINE_MASK,
|
||||
INTERPOLATION,
|
||||
// *** Input group ***
|
||||
DIGITAL_DEADZONE,
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "Version.hxx"
|
||||
#include "Logger.hxx"
|
||||
#include "AudioSettings.hxx"
|
||||
#include "TIASurface.hxx"
|
||||
#include "PaletteHandler.hxx"
|
||||
#include "Joystick.hxx"
|
||||
#include "Paddles.hxx"
|
||||
|
@ -80,6 +81,7 @@ Settings::Settings()
|
|||
setPermanent("tv.phosphor", "byrom");
|
||||
setPermanent("tv.phosblend", "50");
|
||||
setPermanent("tv.scanlines", "0");
|
||||
setPermanent("tv.scanmask", TIASurface::SETTING_STANDARD);
|
||||
// TV options when using 'custom' mode
|
||||
setPermanent("tv.sharpness", "0.0");
|
||||
setPermanent("tv.resolution", "0.0");
|
||||
|
@ -315,6 +317,13 @@ void Settings::validate()
|
|||
i = getInt("tv.phosblend");
|
||||
if(i < 0 || i > 100) setValue("tv.phosblend", "50");
|
||||
|
||||
s = getString("tv.scanmask");
|
||||
if(s != TIASurface::SETTING_STANDARD
|
||||
&& s != TIASurface::SETTING_THIN
|
||||
&& s != TIASurface::SETTING_PIXELS
|
||||
&& s != TIASurface::SETTING_MAME)
|
||||
setValue("tv.scanmask", TIASurface::SETTING_STANDARD);
|
||||
|
||||
i = getInt("tv.filter");
|
||||
if(i < 0 || i > 5) setValue("tv.filter", "0");
|
||||
|
||||
|
@ -506,6 +515,9 @@ void Settings::usage() const
|
|||
<< " -tv.phosblend <0-100> Set default blend level in phosphor mode\n"
|
||||
<< " -tv.scanlines <0-100> Set scanline intensity to percentage\n"
|
||||
<< " (0 disables completely)\n"
|
||||
<< " -tv.scanmask <standard| Use the specified scanline mask\n"
|
||||
<< " thin|pixel|\n"
|
||||
<< " mame>\n"
|
||||
<< " -tv.sharpness <-1.0 - 1.0> Set TV effects custom sharpness\n"
|
||||
<< " -tv.resolution <-1.0 - 1.0> Set TV effects custom resolution\n"
|
||||
<< " -tv.artifacts <-1.0 - 1.0> Set TV effects custom artifacts\n"
|
||||
|
|
|
@ -61,16 +61,6 @@ TIASurface::TIASurface(OSystem& system)
|
|||
: interpolationModeFromSettings(myOSystem.settings())
|
||||
);
|
||||
|
||||
// Generate scanline data, and a pre-defined scanline surface
|
||||
constexpr uInt32 scanHeight = TIAConstants::frameBufferHeight * 2;
|
||||
std::array<uInt32, scanHeight> scanData;
|
||||
for(uInt32 i = 0; i < scanHeight; i += 2)
|
||||
{
|
||||
scanData[i] = 0x00000000;
|
||||
scanData[i+1] = 0xff000000;
|
||||
}
|
||||
mySLineSurface = myFB.allocateSurface(1, scanHeight, interpolationModeFromSettings(myOSystem.settings()), scanData.data());
|
||||
|
||||
// Base TIA surface for use in taking snapshots in 1x mode
|
||||
myBaseTiaSurface = myFB.allocateSurface(TIAConstants::frameBufferWidth*2,
|
||||
TIAConstants::frameBufferHeight);
|
||||
|
@ -108,8 +98,6 @@ void TIASurface::initialize(const Console& console,
|
|||
|
||||
myTiaSurface->setDstPos(mode.imageR.x(), mode.imageR.y());
|
||||
myTiaSurface->setDstSize(mode.imageR.w(), mode.imageR.h());
|
||||
mySLineSurface->setDstPos(mode.imageR.x(), mode.imageR.y());
|
||||
mySLineSurface->setDstSize(mode.imageR.w(), mode.imageR.h());
|
||||
|
||||
myPaletteHandler->setPalette();
|
||||
|
||||
|
@ -129,6 +117,7 @@ void TIASurface::initialize(const Console& console,
|
|||
}
|
||||
enablePhosphor(enable, p_blend);
|
||||
|
||||
createScanlineSurface();
|
||||
setNTSC(NTSCFilter::Preset(myOSystem.settings().getInt("tv.filter")), false);
|
||||
|
||||
#if 0
|
||||
|
@ -260,14 +249,20 @@ void TIASurface::changeCurrentNTSCAdjustable(int direction)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIASurface::setScanlineIntensity(int direction)
|
||||
void TIASurface::changeScanlineIntensity(int direction)
|
||||
{
|
||||
ostringstream buf;
|
||||
uInt32 intensity = enableScanlines(direction * 2);
|
||||
FBSurface::Attributes& attr = mySLineSurface->attributes();
|
||||
|
||||
attr.blendalpha += direction * 2;
|
||||
attr.blendalpha = BSPF::clamp(Int32(attr.blendalpha), 0, 100);
|
||||
mySLineSurface->applyAttributes();
|
||||
|
||||
uInt32 intensity = attr.blendalpha;
|
||||
|
||||
myOSystem.settings().setValue("tv.scanlines", intensity);
|
||||
enableNTSC(ntscEnabled());
|
||||
|
||||
ostringstream buf;
|
||||
if(intensity)
|
||||
buf << intensity << "%";
|
||||
else
|
||||
|
@ -276,15 +271,51 @@ void TIASurface::setScanlineIntensity(int direction)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 TIASurface::enableScanlines(int change)
|
||||
TIASurface::ScanlineMask TIASurface::scanlineMaskType(int direction)
|
||||
{
|
||||
FBSurface::Attributes& attr = mySLineSurface->attributes();
|
||||
const string Masks[int(ScanlineMask::NumMasks)] = {
|
||||
SETTING_STANDARD,
|
||||
SETTING_THIN,
|
||||
SETTING_PIXELS,
|
||||
SETTING_MAME
|
||||
};
|
||||
int i = 0;
|
||||
const string& name = myOSystem.settings().getString("tv.scanmask");
|
||||
|
||||
attr.blendalpha += change;
|
||||
attr.blendalpha = BSPF::clamp(Int32(attr.blendalpha), 0, 100);
|
||||
mySLineSurface->applyAttributes();
|
||||
for(auto& mask : Masks)
|
||||
{
|
||||
if(mask == name)
|
||||
{
|
||||
if(direction)
|
||||
{
|
||||
i = BSPF::clampw(i + direction, 0, int(ScanlineMask::NumMasks) - 1);
|
||||
myOSystem.settings().setValue("tv.scanmask", Masks[i]);
|
||||
}
|
||||
return ScanlineMask(i);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return ScanlineMask::Standard;
|
||||
}
|
||||
|
||||
return attr.blendalpha;
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIASurface::cycleScanlineMask(int direction)
|
||||
{
|
||||
const string Names[int(ScanlineMask::NumMasks)] = {
|
||||
"'Standard'",
|
||||
"'Thin lines'",
|
||||
"'Pixelated'",
|
||||
"'MAME'"
|
||||
};
|
||||
int i = int(scanlineMaskType(direction));
|
||||
|
||||
if(direction)
|
||||
createScanlineSurface();
|
||||
|
||||
ostringstream msg;
|
||||
|
||||
msg << "Scanline pattern " << Names[i];
|
||||
myOSystem.frameBuffer().showTextMessage(msg.str());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -297,6 +328,109 @@ void TIASurface::enablePhosphor(bool enable, int blend)
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIASurface::createScanlineSurface()
|
||||
{
|
||||
struct PatternSize
|
||||
{
|
||||
uInt16 width{1};
|
||||
uInt16 height{1};
|
||||
uInt16 hRepeats{1};
|
||||
|
||||
explicit PatternSize(uInt16 c_width, uInt16 c_height, uInt16 c_yRepeats)
|
||||
: width(c_width), height(c_height), hRepeats(c_yRepeats)
|
||||
{}
|
||||
PatternSize(const PatternSize& size)
|
||||
: width(size.width), height(size.height), hRepeats(size.hRepeats)
|
||||
{}
|
||||
};
|
||||
std::array <PatternSize, int(ScanlineMask::NumMasks)> Sizes = {{
|
||||
PatternSize(1, 2, 1),
|
||||
PatternSize(1, 3, 1),
|
||||
PatternSize(3, 3, 2),
|
||||
PatternSize(3, 4, 3)
|
||||
}};
|
||||
std::array<std::vector<std::vector<uInt32>>, int(ScanlineMask::NumMasks)> Pattern = {{
|
||||
{ // standard
|
||||
{ 0x00000000 },
|
||||
{ 0xff000000 },
|
||||
}, { // thin lines
|
||||
{ 0x00000000 },
|
||||
{ 0x00000000 },
|
||||
{ 0xff000000 },
|
||||
}, { // pixelated
|
||||
// orignal data from https://forum.arcadeotaku.com/posting.php?mode=quote&f=10&p=134359
|
||||
//{ 0x08ffffff, 0x02ffffff, 0x80e7e7e7 },
|
||||
//{ 0x08ffffff, 0x80e7e7e7, 0x40ffffff },
|
||||
//{ 0xff282828, 0xff282828, 0xff282828 },
|
||||
//{ 0x80e7e7e7, 0x04ffffff, 0x04ffffff },
|
||||
//{ 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 },
|
||||
}, { // mame
|
||||
// original tile data from https://wiki.arcadeotaku.com/w/MAME_CRT_Simulation
|
||||
//{ 0xffb4b4b4, 0xffa5a5a5, 0xffc3c3c3 },
|
||||
//{ 0xffffffff, 0xfff0f0f0, 0xfff0f0f0 },
|
||||
//{ 0xfff0f0f0, 0xffffffff, 0xffe1e1e1 },
|
||||
//{ 0xff000000, 0xff000000, 0xff000000 },
|
||||
//{ 0xffa5a5a5, 0xffc3c3c3, 0xffb4b4b4 },
|
||||
//{ 0xfff0f0f0, 0xfff0f0f0, 0xffffffff },
|
||||
//{ 0xffffffff, 0xffe1e1e1, 0xfff0f0f0 },
|
||||
//{ 0xff000000, 0xff000000, 0xff000000 },
|
||||
//{ 0xffc3c3c3, 0xffb4b4b4, 0xffa5a5a5 },
|
||||
//{ 0xfff0f0f0, 0xffffffff, 0xfff0f0f0 },
|
||||
//{ 0xffe1e1e1, 0xfff0f0f0, 0xffffffff },
|
||||
//{ 0xff000000, 0xff000000, 0xff000000 },
|
||||
// MAME tile RGB values inverted into alpha channel
|
||||
{ 0x4b000000, 0x5a000000, 0x3c000000 },
|
||||
{ 0x00000000, 0x0f000000, 0x0f000000 },
|
||||
{ 0x0f000000, 0x00000000, 0x1e000000 },
|
||||
{ 0xff000000, 0xff000000, 0xff000000 },
|
||||
{ 0x5a000000, 0x3c000000, 0x4b000000 },
|
||||
{ 0x0f000000, 0x0f000000, 0x00000000 },
|
||||
{ 0x00000000, 0x1e000000, 0x0f000000 },
|
||||
{ 0xff000000, 0xff000000, 0xff000000 },
|
||||
{ 0x3c000000, 0x4b000000, 0x5a000000 },
|
||||
{ 0x0f000000, 0x00000000, 0x0f000000 },
|
||||
{ 0x1e000000, 0x0f000000, 0x00000000 },
|
||||
{ 0xff000000, 0xff000000, 0xff000000 },
|
||||
}
|
||||
}};
|
||||
|
||||
const int mask = int(scanlineMaskType());
|
||||
const PatternSize size(Sizes[mask]);
|
||||
uInt32 width{1}, height{1};
|
||||
|
||||
// Single width pattern need no x-repeats
|
||||
if(size.width > 1)
|
||||
width = TIAConstants::frameBufferWidth * size.width;
|
||||
else
|
||||
width = 1;
|
||||
// TODO: use alternative mask pattern if destination is scaled smaller than mask height
|
||||
height = myTIA->height() * size.height; // hRepeats are not used here
|
||||
|
||||
// Copy repeated pattern into surface data
|
||||
std::vector<uInt32>data(width * height);
|
||||
|
||||
for(uInt32 i = 0; i < width * height; ++i)
|
||||
data[i] = Pattern[mask][(i / width) % (size.height * size.hRepeats)][i % size.width];
|
||||
|
||||
myFB.deallocateSurface(mySLineSurface);
|
||||
mySLineSurface = myFB.allocateSurface(width, height,
|
||||
interpolationModeFromSettings(myOSystem.settings()), data.data());
|
||||
|
||||
mySLineSurface->setSrcSize(mySLineSurface->width(), height);
|
||||
mySLineSurface->setDstRect(myTiaSurface->dstRect());
|
||||
|
||||
enableNTSC(ntscEnabled());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TIASurface::enableNTSC(bool enable)
|
||||
{
|
||||
|
@ -311,11 +445,11 @@ void TIASurface::enableNTSC(bool enable)
|
|||
myTiaSurface->invalidate();
|
||||
}
|
||||
|
||||
mySLineSurface->setSrcSize(1, 2 * myTIA->height());
|
||||
|
||||
// Generate a scanline surface from current scanline pattern
|
||||
// Apply current blend to scan line surface
|
||||
myScanlinesEnabled = myOSystem.settings().getInt("tv.scanlines") > 0;
|
||||
FBSurface::Attributes& sl_attr = mySLineSurface->attributes();
|
||||
sl_attr.blending = myScanlinesEnabled;
|
||||
sl_attr.blending = myScanlinesEnabled;
|
||||
sl_attr.blendalpha = myOSystem.settings().getInt("tv.scanlines");
|
||||
mySLineSurface->applyAttributes();
|
||||
|
||||
|
|
|
@ -45,6 +45,12 @@ class PaletteHandler;
|
|||
class TIASurface
|
||||
{
|
||||
public:
|
||||
// Setting names of palette types
|
||||
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_MAME = "mame";
|
||||
|
||||
/**
|
||||
Creates a new TIASurface object
|
||||
*/
|
||||
|
@ -138,15 +144,14 @@ class TIASurface
|
|||
|
||||
@param direction +1 indicates increase, -1 indicates decrease.
|
||||
*/
|
||||
void setScanlineIntensity(int direction = +1);
|
||||
void changeScanlineIntensity(int direction = +1);
|
||||
|
||||
/**
|
||||
Change scanline intensity and interpolation.
|
||||
Cycle through available scanline masks.
|
||||
|
||||
@param change change current intensity by 'change'
|
||||
@return New current intensity
|
||||
@param direction +1 next mask, -1 mask.
|
||||
*/
|
||||
uInt32 enableScanlines(int change);
|
||||
void cycleScanlineMask(int direction = +1);
|
||||
|
||||
/**
|
||||
Enable/disable/query phosphor effect.
|
||||
|
@ -154,6 +159,11 @@ class TIASurface
|
|||
void enablePhosphor(bool enable, int blend = -1);
|
||||
bool phosphorEnabled() const { return myPhosphorHandler.phosphorEnabled(); }
|
||||
|
||||
/**
|
||||
Creates a scanline surface for the current TIA resolution
|
||||
*/
|
||||
void createScanlineSurface();
|
||||
|
||||
/**
|
||||
Enable/disable/query NTSC filtering effects.
|
||||
*/
|
||||
|
@ -184,15 +194,14 @@ class TIASurface
|
|||
void updateSurfaceSettings();
|
||||
|
||||
private:
|
||||
/**
|
||||
Average current calculated buffer's pixel with previous calculated buffer's pixel (50:50).
|
||||
*/
|
||||
uInt32 averageBuffers(uInt32 bufOfs);
|
||||
enum class ScanlineMask {
|
||||
Standard,
|
||||
Thin,
|
||||
Pixels,
|
||||
Mame,
|
||||
NumMasks
|
||||
};
|
||||
|
||||
// Is plain video mode enabled?
|
||||
bool correctAspect() const;
|
||||
|
||||
private:
|
||||
// Enumeration created such that phosphor off/on is in LSB,
|
||||
// and Blargg off/on is in MSB
|
||||
enum class Filter: uInt8 {
|
||||
|
@ -201,6 +210,19 @@ class TIASurface
|
|||
BlarggNormal = 0x10,
|
||||
BlarggPhosphor = 0x11
|
||||
};
|
||||
|
||||
private:
|
||||
/**
|
||||
Average current calculated buffer's pixel with previous calculated buffer's pixel (50:50).
|
||||
*/
|
||||
uInt32 averageBuffers(uInt32 bufOfs);
|
||||
|
||||
// Is plain video mode enabled?
|
||||
bool correctAspect() const;
|
||||
|
||||
// Convert scanline mask setting name into type
|
||||
ScanlineMask scanlineMaskType(int direction = 0);
|
||||
|
||||
Filter myFilter{Filter::Normal};
|
||||
|
||||
private:
|
||||
|
|
|
@ -29,7 +29,6 @@ class RadioButtonWidget;
|
|||
class SliderWidget;
|
||||
class StaticTextWidget;
|
||||
class ColorWidget;
|
||||
class DevSettingsHandler;
|
||||
|
||||
namespace GUI {
|
||||
class Font;
|
||||
|
|
|
@ -331,7 +331,7 @@ void VideoAudioDialog::addTVEffectsTab()
|
|||
int xpos = HBORDER,
|
||||
ypos = VBORDER;
|
||||
const int lwidth = _font.getStringWidth("Saturation ");
|
||||
const int pwidth = _font.getStringWidth("Bad adjust ");
|
||||
int pwidth = _font.getStringWidth("Bad adjust ");
|
||||
WidgetArray wid;
|
||||
VariantList items;
|
||||
const int tabID = myTab->addTab(" TV Effects ", TabWidget::AUTO_WIDTH);
|
||||
|
@ -380,6 +380,17 @@ void VideoAudioDialog::addTVEffectsTab()
|
|||
xpos += INDENT;
|
||||
CREATE_CUSTOM_SLIDERS(ScanIntense, "Intensity", kScanlinesChanged)
|
||||
|
||||
items.clear();
|
||||
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, "MAME", TIASurface::SETTING_MAME);
|
||||
|
||||
pwidth = _font.getStringWidth("Thin lines");
|
||||
myTVScanMask = new PopUpWidget(myTab, _font, myTVScanIntense->getRight() + fontWidth * 2,
|
||||
myTVScanIntense->getTop() + 1, pwidth, lineHeight, items, "Mask ");
|
||||
wid.push_back(myTVScanMask);
|
||||
|
||||
// Create buttons in 2nd column
|
||||
xpos = _w - HBORDER - 2 * 2 - buttonWidth;
|
||||
ypos = VBORDER - VGAP / 2;
|
||||
|
@ -633,15 +644,14 @@ void VideoAudioDialog::loadConfig()
|
|||
// TV Custom adjustables
|
||||
loadTVAdjustables(NTSCFilter::Preset::CUSTOM);
|
||||
|
||||
// TV phosphor mode
|
||||
// TV phosphor mode & blend
|
||||
myTVPhosphor->setState(settings.getString("tv.phosphor") == "always");
|
||||
|
||||
// TV phosphor blend
|
||||
myTVPhosLevel->setValue(settings.getInt("tv.phosblend"));
|
||||
handlePhosphorChange();
|
||||
|
||||
// TV scanline intensity and interpolation
|
||||
// TV scanline intensity & mask
|
||||
myTVScanIntense->setValue(settings.getInt("tv.scanlines"));
|
||||
myTVScanMask->setSelected(settings.getString("tv.scanmask"), TIASurface::SETTING_STANDARD);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Audio tab
|
||||
|
@ -754,15 +764,15 @@ void VideoAudioDialog::saveConfig()
|
|||
instance().frameBuffer().tiaSurface().ntsc().saveConfig(settings);
|
||||
|
||||
|
||||
// TV phosphor mode
|
||||
// TV phosphor mode & blend
|
||||
settings.setValue("tv.phosphor",
|
||||
myTVPhosphor->getState() ? "always" : "byrom");
|
||||
// TV phosphor blend
|
||||
settings.setValue("tv.phosblend", myTVPhosLevel->getValueLabel() == "Off"
|
||||
? "0" : myTVPhosLevel->getValueLabel());
|
||||
|
||||
// TV scanline intensity
|
||||
// TV scanline intensity & mask
|
||||
settings.setValue("tv.scanlines", myTVScanIntense->getValueLabel());
|
||||
settings.setValue("tv.scanmask", myTVScanMask->getSelectedTag());
|
||||
|
||||
if(instance().hasConsole())
|
||||
{
|
||||
|
@ -879,14 +889,13 @@ void VideoAudioDialog::setDefaults()
|
|||
{
|
||||
myTVMode->setSelected("0", "0");
|
||||
|
||||
// TV phosphor mode
|
||||
// TV phosphor mode & blend
|
||||
myTVPhosphor->setState(false);
|
||||
|
||||
// TV phosphor blend
|
||||
myTVPhosLevel->setValue(50);
|
||||
|
||||
// TV scanline intensity and interpolation
|
||||
// TV scanline intensity & mask
|
||||
myTVScanIntense->setValue(25);
|
||||
myTVScanMask->setSelected(TIASurface::SETTING_STANDARD);
|
||||
|
||||
// Make sure that mutually-exclusive items are not enabled at the same time
|
||||
handleTVModeChange(NTSCFilter::Preset::OFF);
|
||||
|
|
|
@ -95,6 +95,7 @@ class VideoAudioDialog : public Dialog
|
|||
// TV scanline intensity and interpolation
|
||||
StaticTextWidget* myTVScanLabel{nullptr};
|
||||
SliderWidget* myTVScanIntense{nullptr};
|
||||
PopUpWidget* myTVScanMask{nullptr};
|
||||
|
||||
// TV effects adjustables presets (custom mode)
|
||||
ButtonWidget* myCloneComposite{nullptr};
|
||||
|
|
Loading…
Reference in New Issue