The default phosphor blend level can now be set globally (fixes #144).

Added new 'tv.phosphor' commandline argument to accomplish the above,
and associated UI item in Video Settings.

Updated docs for 'tv.phosphor' and 'tia.debugcolors'.  More work is
needed on this, since I need to add screenshots for this new functionality.
This commit is contained in:
Stephen Anthony 2017-07-09 22:36:50 -02:30
parent aa5be284cb
commit d613173cd7
9 changed files with 129 additions and 48 deletions

View File

@ -24,11 +24,13 @@
choice of 'red', 'orange', 'yellow', 'green', 'blue' and 'purple'. choice of 'red', 'orange', 'yellow', 'green', 'blue' and 'purple'.
This is accessible through the new 'tia.dbgcolors' commandline This is accessible through the new 'tia.dbgcolors' commandline
argument. argument.
- ... - The defaul
* Implemented new phosphor emulation mode, which is much closer to real * Implemented new phosphor emulation mode, which is much closer to real
TV output. Special thanks to Thomas Jentzsch for the idea and TV output. Related to this, added ability to change the default
implementation. phosphor blend level in the UI and through the new 'tv.phosphor'
commandline argument. Special thanks to Thomas Jentzsch for the idea
and implementation.
* Much improved RIOT timer emulation never before seen in any emulator. * Much improved RIOT timer emulation never before seen in any emulator.
Special thanks to DirtyHairy for the implementation, and alex_79 for Special thanks to DirtyHairy for the implementation, and alex_79 for

View File

@ -1865,6 +1865,23 @@
(vs. an integral stretch which won't necessarily completely fill the screen).</td> (vs. an integral stretch which won't necessarily completely fill the screen).</td>
</tr> </tr>
<tr>
<td><pre>-tia.debugcolors &lt;ROYGBP&gt;</pre></td>
<td>Assigns the colours (R)ed, (O)range, (Y)ellow, (G)reen, (B)lue and (P)urple
to each graphical register P0/M0/P1/M1/PF/BL, respectively. Currently,
these change be changed around to apply different colours to the
respective register.
</td>
</tr>
<tr>
<td><pre>-tv.phosphor &lt;0 - 100&gt;</pre></td>
<td>Enable default phosphor blending level; 0 implies no mixing, and 100
is full mixing (not recommended). Note that this doesn't actually
enable phosphor mode; that is done for each ROM in the ROM properties.
</td>
</tr>
<tr> <tr>
<td><pre>-tv.jitter &lt;1|0&gt;</pre></td> <td><pre>-tv.jitter &lt;1|0&gt;</pre></td>
<td>Enable TV jitter/roll effect, when there are too many or too few scanlines <td>Enable TV jitter/roll effect, when there are too many or too few scanlines

View File

@ -103,6 +103,10 @@ void EventHandler::initialize()
// Integer to string conversions (for HEX) use upper or lower-case // Integer to string conversions (for HEX) use upper or lower-case
Common::Base::setHexUppercase(myOSystem.settings().getBool("dbg.uhex")); Common::Base::setHexUppercase(myOSystem.settings().getBool("dbg.uhex"));
// Default phosphor blend
Properties::setDefault(Display_PPBlend,
myOSystem.settings().getString("tv.phosphor"));
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -63,13 +63,11 @@ void Properties::set(PropertyType key, const string& value)
break; break;
} }
case Display_PPBlend: // FIXME - handle global default case Display_PPBlend:
{ {
int blend = atoi(myProperties[key].c_str()); int blend = atoi(myProperties[key].c_str());
if(blend < 1 || blend > 100) blend = 50; if(blend < 1 || blend > 100)
ostringstream buf; myProperties[key] = ourDefaultProperties[key];
buf << blend;
myProperties[key] = buf.str();
break; break;
} }
@ -222,6 +220,12 @@ Properties& Properties::operator=(const Properties& properties)
return *this; return *this;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Properties::setDefault(PropertyType key, const string& value)
{
ourDefaultProperties[key] = value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Properties::copy(const Properties& properties) void Properties::copy(const Properties& properties)
{ {
@ -261,14 +265,7 @@ void Properties::print() const
void Properties::setDefaults() void Properties::setDefaults()
{ {
for(int i = 0; i < LastPropType; ++i) for(int i = 0; i < LastPropType; ++i)
{
if(i == Display_PPBlend) // special case, handle global default
{
myProperties[i] = "50"; // FIXME - for now, just use 50
}
else
myProperties[i] = ourDefaultProperties[i]; myProperties[i] = ourDefaultProperties[i];
}
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -310,7 +307,7 @@ void Properties::printHeader()
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* const Properties::ourDefaultProperties[LastPropType] = { string Properties::ourDefaultProperties[LastPropType] = {
"", // Cartridge.MD5 "", // Cartridge.MD5
"", // Cartridge.Manufacturer "", // Cartridge.Manufacturer
"", // Cartridge.ModelNo "", // Cartridge.ModelNo

View File

@ -136,6 +136,14 @@ class Properties
*/ */
Properties& operator = (const Properties& properties); Properties& operator = (const Properties& properties);
/**
Set the default value associated with key to the given value.
@param key The key of the property to set
@param value The value to assign to the property
*/
static void setDefault(PropertyType key, const string& value);
private: private:
/** /**
Helper function to perform a deep copy of the specified Helper function to perform a deep copy of the specified
@ -183,7 +191,7 @@ class Properties
string myProperties[LastPropType]; string myProperties[LastPropType];
// List of default properties to use when none have been provided // List of default properties to use when none have been provided
static const char* const ourDefaultProperties[LastPropType]; static string ourDefaultProperties[LastPropType];
// The text strings associated with each property type // The text strings associated with each property type
static const char* const ourPropertyNames[LastPropType]; static const char* const ourPropertyNames[LastPropType];

View File

@ -55,10 +55,11 @@ Settings::Settings(OSystem& osystem)
// TV filtering options // TV filtering options
setInternal("tv.filter", "0"); setInternal("tv.filter", "0");
setInternal("tv.scanlines", "25"); setInternal("tv.phosphor", "50");
setInternal("tv.scaninter", "true");
setInternal("tv.jitter", "false"); setInternal("tv.jitter", "false");
setInternal("tv.jitter_recovery", "10"); setInternal("tv.jitter_recovery", "10");
setInternal("tv.scanlines", "25");
setInternal("tv.scaninter", "true");
// TV options when using 'custom' mode // TV options when using 'custom' mode
setInternal("tv.contrast", "0.0"); setInternal("tv.contrast", "0.0");
setInternal("tv.brightness", "0.0"); setInternal("tv.brightness", "0.0");
@ -278,6 +279,9 @@ void Settings::validate()
sort(s.begin(), s.end()); sort(s.begin(), s.end());
if(s != "bgopry") setInternal("tia.dbgcolors", "roygpb"); if(s != "bgopry") setInternal("tia.dbgcolors", "roygpb");
i = getInt("tv.phosphor");
if(i < 0 || i > 100) setInternal("tv.phosphor", "50");
i = getInt("tv.filter"); i = getInt("tv.filter");
if(i < 0 || i > 5) setInternal("tv.filter", "0"); if(i < 0 || i > 5) setInternal("tv.filter", "0");
@ -373,12 +377,14 @@ void Settings::usage() const
<< " -tia.aspectn <number> Scale TIA width by the given percentage in NTSC mode\n" << " -tia.aspectn <number> Scale TIA width by the given percentage in NTSC mode\n"
<< " -tia.aspectp <number> Scale TIA width by the given percentage in PAL mode\n" << " -tia.aspectp <number> Scale TIA width by the given percentage in PAL mode\n"
<< " -tia.fsfill <1|0> Stretch TIA image to fill fullscreen mode\n" << " -tia.fsfill <1|0> Stretch TIA image to fill fullscreen mode\n"
<< " -tia.dbgcolors <string> Debug colors to use for each object (see manual for description)\n"
<< endl << endl
<< " -tv.filter <0-5> Set TV effects off (0) or to specified mode (1-5)\n" << " -tv.filter <0-5> Set TV effects off (0) or to specified mode (1-5)\n"
<< " -tv.scanlines <0-100> Set scanline intensity to percentage (0 disables completely)\n" << " -tv.phosphor <0-100> Set default blend level in phosphor mode\n"
<< " -tv.scaninter <1|0> Enable interpolated (smooth) scanlines\n"
<< " -tv.jitter <1|0> Enable TV jitter effect\n" << " -tv.jitter <1|0> Enable TV jitter effect\n"
<< " -tv.jitter_recovery <1-20> Set recovery time for TV jitter effect\n" << " -tv.jitter_recovery <1-20> Set recovery time for TV jitter effect\n"
<< " -tv.scanlines <0-100> Set scanline intensity to percentage (0 disables completely)\n"
<< " -tv.scaninter <1|0> Enable interpolated (smooth) scanlines\n"
<< " -tv.contrast <value> Set TV effects custom contrast to value 1.0 - 1.0\n" << " -tv.contrast <value> Set TV effects custom contrast to value 1.0 - 1.0\n"
<< " -tv.brightness <value> Set TV effects custom brightness to value 1.0 - 1.0\n" << " -tv.brightness <value> Set TV effects custom brightness to value 1.0 - 1.0\n"
<< " -tv.hue <value> Set TV effects custom hue to value 1.0 - 1.0\n" << " -tv.hue <value> Set TV effects custom hue to value 1.0 - 1.0\n"

View File

@ -361,7 +361,7 @@ GameInfoDialog::GameInfoDialog(
myPPBlendLabel = new StaticTextWidget(myTab, font, myPPBlendLabel = new StaticTextWidget(myTab, font,
xpos + lwidth + myPhosphor->getWidth() + 10 + xpos + lwidth + myPhosphor->getWidth() + 10 +
myPPBlend->getWidth() + 4, ypos+1, myPPBlend->getWidth() + 4, ypos+1,
3*fontWidth, fontHeight, "", kTextAlignLeft); 5*fontWidth, fontHeight, "", kTextAlignLeft);
myPPBlendLabel->setFlags(WIDGET_CLEARBG); myPPBlendLabel->setFlags(WIDGET_CLEARBG);
// Add items for tab 3 // Add items for tab 3
@ -490,7 +490,7 @@ void GameInfoDialog::loadView()
const string& blend = myGameProperties.get(Display_PPBlend); const string& blend = myGameProperties.get(Display_PPBlend);
myPPBlend->setValue(atoi(blend.c_str())); myPPBlend->setValue(atoi(blend.c_str()));
myPPBlendLabel->setLabel(blend); myPPBlendLabel->setLabel(blend == "0" ? "Auto" : blend);
myTab->loadConfig(); myTab->loadConfig();
} }
@ -539,7 +539,8 @@ void GameInfoDialog::saveConfig()
myGameProperties.set(Display_Height, myHeightLabel->getLabel() == "Auto" ? "0" : myGameProperties.set(Display_Height, myHeightLabel->getLabel() == "Auto" ? "0" :
myHeightLabel->getLabel()); myHeightLabel->getLabel());
myGameProperties.set(Display_Phosphor, myPhosphor->getSelectedTag().toString()); myGameProperties.set(Display_Phosphor, myPhosphor->getSelectedTag().toString());
myGameProperties.set(Display_PPBlend, myPPBlendLabel->getLabel()); myGameProperties.set(Display_PPBlend, myPPBlendLabel->getLabel() == "Auto" ? "0" :
myPPBlendLabel->getLabel());
// Determine whether to add or remove an entry from the properties set // Determine whether to add or remove an entry from the properties set
if(myDefaultsSelected) if(myDefaultsSelected)
@ -612,6 +613,9 @@ void GameInfoDialog::handleCommand(CommandSender* sender, int cmd,
break; break;
case kPPBlendChanged: case kPPBlendChanged:
if(myPPBlend->getValue() == 0)
myPPBlendLabel->setLabel("Auto");
else
myPPBlendLabel->setValue(myPPBlend->getValue()); myPPBlendLabel->setValue(myPPBlend->getValue());
break; break;

View File

@ -52,7 +52,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent,
// Set real dimensions // Set real dimensions
_w = std::min(52 * fontWidth + 10, max_w); _w = std::min(52 * fontWidth + 10, max_w);
_h = std::min(14 * (lineHeight + 4) + 10, max_h); _h = std::min(16 * (lineHeight + 4) + 10, max_h);
// The tab widget // The tab widget
xpos = ypos = 5; xpos = ypos = 5;
@ -244,18 +244,33 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent,
xpos += myTVContrast->getWidth() + myTVContrastLabel->getWidth() + 20; xpos += myTVContrast->getWidth() + myTVContrastLabel->getWidth() + 20;
ypos = 8; ypos = 8;
// TV jitter effect
myTVJitter = new CheckboxWidget(myTab, font, xpos, ypos,
"Jitter/Roll effect", kTVJitterChanged);
wid.push_back(myTVJitter);
ypos += lineHeight;
lwidth = font.getStringWidth("Intensity "); lwidth = font.getStringWidth("Intensity ");
pwidth = font.getMaxCharWidth() * 6; pwidth = font.getMaxCharWidth() * 6;
// TV Phosphor effect
myTVPhosLabel = new StaticTextWidget(myTab, font, xpos, ypos,
font.getStringWidth("Phosphor Effect"), fontHeight,
"Phosphor Effect", kTextAlignLeft);
ypos += lineHeight;
// TV Phosphor default level
xpos += 20;
CREATE_CUSTOM_SLIDERS(PhosLevel, "Default ");
ypos += 4;
// TV jitter effect
xpos -= 20;
myTVJitter = new CheckboxWidget(myTab, font, xpos, ypos,
"Jitter/Roll Effect", kTVJitterChanged);
wid.push_back(myTVJitter);
xpos += 20;
ypos += lineHeight;
CREATE_CUSTOM_SLIDERS(JitterRec, "Recovery "); CREATE_CUSTOM_SLIDERS(JitterRec, "Recovery ");
myTVJitterRec->setMinValue(1); myTVJitterRec->setMaxValue(20); myTVJitterRec->setMinValue(1); myTVJitterRec->setMaxValue(20);
ypos += 4; ypos += 4;
// Scanline intensity and interpolation // Scanline intensity and interpolation
xpos -= 20;
myTVScanLabel = myTVScanLabel =
new StaticTextWidget(myTab, font, xpos, ypos, font.getStringWidth("Scanline settings"), new StaticTextWidget(myTab, font, xpos, ypos, font.getStringWidth("Scanline settings"),
fontHeight, "Scanline settings", kTextAlignLeft); fontHeight, "Scanline settings", kTextAlignLeft);
@ -289,6 +304,13 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent,
// Add items for tab 2 // Add items for tab 2
addToFocusList(wid, myTab, tabID); addToFocusList(wid, myTab, tabID);
//////////////////////////////////////////////////////////
// 3) TIA debug colours
wid.clear();
tabID = myTab->addTab(" Debug Colors ");
xpos = ypos = 8;
// Activate the first tab // Activate the first tab
myTab->setActiveTab(0); myTab->setActiveTab(0);
@ -376,6 +398,10 @@ void VideoDialog::loadConfig()
// TV Custom adjustables // TV Custom adjustables
loadTVAdjustables(NTSCFilter::PRESET_CUSTOM); loadTVAdjustables(NTSCFilter::PRESET_CUSTOM);
// TV phosphor blend
myTVPhosLevel->setValue(instance().settings().getInt("tv.phosphor"));
myTVPhosLevelLabel->setLabel(instance().settings().getString("tv.phosphor"));
// TV jitter // TV jitter
myTVJitterRec->setValue(instance().settings().getInt("tv.jitter_recovery")); myTVJitterRec->setValue(instance().settings().getInt("tv.jitter_recovery"));
myTVJitterRecLabel->setLabel(instance().settings().getString("tv.jitter_recovery")); myTVJitterRecLabel->setLabel(instance().settings().getString("tv.jitter_recovery"));
@ -467,6 +493,10 @@ void VideoDialog::saveConfig()
adj.bleed = myTVBleed->getValue(); adj.bleed = myTVBleed->getValue();
instance().frameBuffer().tiaSurface().ntsc().setCustomAdjustables(adj); instance().frameBuffer().tiaSurface().ntsc().setCustomAdjustables(adj);
// TV phosphor blend
instance().settings().setValue("tv.phosphor", myTVPhosLevelLabel->getLabel());
Properties::setDefault(Display_PPBlend, myTVPhosLevelLabel->getLabel());
// TV jitter // TV jitter
instance().settings().setValue("tv.jitter", myTVJitter->getState()); instance().settings().setValue("tv.jitter", myTVJitter->getState());
instance().settings().setValue("tv.jitter_recovery", myTVJitterRecLabel->getLabel()); instance().settings().setValue("tv.jitter_recovery", myTVJitterRecLabel->getLabel());
@ -517,6 +547,15 @@ void VideoDialog::setDefaults()
{ {
myTVMode->setSelected("0", "0"); myTVMode->setSelected("0", "0");
// TV phosphor blend
myTVPhosLevel->setValue(50);
myTVPhosLevelLabel->setLabel("50");
// TV jitter
myTVJitterRec->setValue(10);
myTVJitterRecLabel->setLabel("10");
handleTVJitterChange(false);
// TV scanline intensity and interpolation // TV scanline intensity and interpolation
myTVScanIntense->setValue(25); myTVScanIntense->setValue(25);
myTVScanIntenseLabel->setLabel("25"); myTVScanIntenseLabel->setLabel("25");
@ -525,11 +564,6 @@ void VideoDialog::setDefaults()
// Make sure that mutually-exclusive items are not enabled at the same time // Make sure that mutually-exclusive items are not enabled at the same time
handleTVModeChange(NTSCFilter::PRESET_OFF); handleTVModeChange(NTSCFilter::PRESET_OFF);
loadTVAdjustables(NTSCFilter::PRESET_CUSTOM); loadTVAdjustables(NTSCFilter::PRESET_CUSTOM);
// TV jitter
myTVJitterRec->setValue(10);
myTVJitterRecLabel->setLabel("10");
handleTVJitterChange(false);
break; break;
} }
} }
@ -666,12 +700,14 @@ void VideoDialog::handleCommand(CommandSender* sender, int cmd,
break; break;
case kTVGammaChanged: myTVGammaLabel->setValue(myTVGamma->getValue()); case kTVGammaChanged: myTVGammaLabel->setValue(myTVGamma->getValue());
break; break;
case kTVScanIntenseChanged: myTVScanIntenseLabel->setValue(myTVScanIntense->getValue()); case kTVPhosLevelChanged: myTVPhosLevelLabel->setValue(myTVPhosLevel->getValue());
break; break;
case kTVJitterChanged: handleTVJitterChange(myTVJitter->getState()); case kTVJitterChanged: handleTVJitterChange(myTVJitter->getState());
break; break;
case kTVJitterRecChanged: myTVJitterRecLabel->setValue(myTVJitterRec->getValue()); case kTVJitterRecChanged: myTVJitterRecLabel->setValue(myTVJitterRec->getValue());
break; break;
case kTVScanIntenseChanged: myTVScanIntenseLabel->setValue(myTVScanIntense->getValue());
break;
case kCloneCompositeCmd: loadTVAdjustables(NTSCFilter::PRESET_COMPOSITE); case kCloneCompositeCmd: loadTVAdjustables(NTSCFilter::PRESET_COMPOSITE);
break; break;
case kCloneSvideoCmd: loadTVAdjustables(NTSCFilter::PRESET_SVIDEO); case kCloneSvideoCmd: loadTVAdjustables(NTSCFilter::PRESET_SVIDEO);

View File

@ -95,6 +95,16 @@ class VideoDialog : public Dialog
SliderWidget* myTVGamma; SliderWidget* myTVGamma;
StaticTextWidget* myTVGammaLabel; StaticTextWidget* myTVGammaLabel;
// TV jitter effects
CheckboxWidget* myTVJitter;
SliderWidget* myTVJitterRec;
StaticTextWidget* myTVJitterRecLabel;
// TV phosphor effect
StaticTextWidget* myTVPhosLabel;
SliderWidget* myTVPhosLevel;
StaticTextWidget* myTVPhosLevelLabel;
// TV scanline intensity and interpolation // TV scanline intensity and interpolation
StaticTextWidget* myTVScanLabel; StaticTextWidget* myTVScanLabel;
SliderWidget* myTVScanIntense; SliderWidget* myTVScanIntense;
@ -108,11 +118,6 @@ class VideoDialog : public Dialog
ButtonWidget* myCloneBad; ButtonWidget* myCloneBad;
ButtonWidget* myCloneCustom; ButtonWidget* myCloneCustom;
// TV jitter effects
CheckboxWidget* myTVJitter;
SliderWidget* myTVJitterRec;
StaticTextWidget* myTVJitterRecLabel;
enum { enum {
kNAspectRatioChanged = 'VDan', kNAspectRatioChanged = 'VDan',
kPAspectRatioChanged = 'VDap', kPAspectRatioChanged = 'VDap',
@ -134,6 +139,8 @@ class VideoDialog : public Dialog
kTVJitterChanged = 'TVjt', kTVJitterChanged = 'TVjt',
kTVJitterRecChanged = 'TVjr', kTVJitterRecChanged = 'TVjr',
kTVPhosLevelChanged = 'TVpl',
kCloneCompositeCmd = 'CLcp', kCloneCompositeCmd = 'CLcp',
kCloneSvideoCmd = 'CLsv', kCloneSvideoCmd = 'CLsv',
kCloneRGBCmd = 'CLrb', kCloneRGBCmd = 'CLrb',