| 1 | //============================================================================ |
| 2 | // |
| 3 | // SSSS tt lll lll |
| 4 | // SS SS tt ll ll |
| 5 | // SS tttttt eeee ll ll aaaa |
| 6 | // SSSS tt ee ee ll ll aa |
| 7 | // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" |
| 8 | // SS SS tt ee ll ll aa aa |
| 9 | // SSSS ttt eeeee llll llll aaaaa |
| 10 | // |
| 11 | // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony |
| 12 | // and the Stella Team |
| 13 | // |
| 14 | // See the file "License.txt" for information on usage and redistribution of |
| 15 | // this file, and for a DISCLAIMER OF ALL WARRANTIES. |
| 16 | //============================================================================ |
| 17 | |
| 18 | #include <cmath> |
| 19 | |
| 20 | #include "bspf.hxx" |
| 21 | #include "Control.hxx" |
| 22 | #include "Dialog.hxx" |
| 23 | #include "Menu.hxx" |
| 24 | #include "OSystem.hxx" |
| 25 | #include "EditTextWidget.hxx" |
| 26 | #include "PopUpWidget.hxx" |
| 27 | #include "Console.hxx" |
| 28 | #include "TIA.hxx" |
| 29 | #include "Settings.hxx" |
| 30 | #include "Widget.hxx" |
| 31 | #include "Font.hxx" |
| 32 | #include "TabWidget.hxx" |
| 33 | #include "NTSCFilter.hxx" |
| 34 | #include "TIASurface.hxx" |
| 35 | |
| 36 | #include "VideoDialog.hxx" |
| 37 | |
| 38 | namespace { |
| 39 | // Emulation speed is a positive float that multiplies the framerate. However, the UI controls |
| 40 | // adjust speed in terms of a speedup factor (1/10, 1/9 .. 1/2, 1, 2, 3, .., 10). The following |
| 41 | // mapping and formatting functions implement this conversion. The speedup factor is represented |
| 42 | // by an integer value between -900 and 900 (0 means no speedup). |
| 43 | |
| 44 | constexpr int MAX_SPEED = 900; |
| 45 | constexpr int MIN_SPEED = -900; |
| 46 | constexpr int SPEED_STEP = 10; |
| 47 | |
| 48 | int mapSpeed(float speed) |
| 49 | { |
| 50 | speed = std::abs(speed); |
| 51 | |
| 52 | return BSPF::clamp( |
| 53 | static_cast<int>(round(100 * (speed >= 1 ? speed - 1 : -1 / speed + 1))), |
| 54 | MIN_SPEED, MAX_SPEED |
| 55 | ); |
| 56 | } |
| 57 | |
| 58 | float unmapSpeed(int speed) |
| 59 | { |
| 60 | float f_speed = static_cast<float>(speed) / 100; |
| 61 | |
| 62 | return speed < 0 ? -1 / (f_speed - 1) : 1 + f_speed; |
| 63 | } |
| 64 | |
| 65 | string formatSpeed(int speed) { |
| 66 | stringstream ss; |
| 67 | |
| 68 | ss |
| 69 | << std::setw(3) << std::fixed << std::setprecision(0) |
| 70 | << (unmapSpeed(speed) * 100); |
| 71 | |
| 72 | return ss.str(); |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 77 | VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, |
| 78 | const GUI::Font& font, int max_w, int max_h) |
| 79 | : Dialog(osystem, parent, font, "Video settings" ) |
| 80 | { |
| 81 | const int VGAP = 4; |
| 82 | const int VBORDER = 8; |
| 83 | const int HBORDER = 10; |
| 84 | const int INDENT = 20; |
| 85 | const int lineHeight = font.getLineHeight(), |
| 86 | fontWidth = font.getMaxCharWidth(), |
| 87 | buttonHeight = font.getLineHeight() + 4; |
| 88 | int xpos, ypos, tabID; |
| 89 | int lwidth = font.getStringWidth("TIA Palette " ), |
| 90 | pwidth = font.getStringWidth("XXXXxXXXX" ), |
| 91 | swidth = font.getMaxCharWidth() * 10 - 2; |
| 92 | |
| 93 | WidgetArray wid; |
| 94 | VariantList items; |
| 95 | |
| 96 | // Set real dimensions |
| 97 | setSize(55 * fontWidth + HBORDER * 2, 14 * (lineHeight + VGAP) + 14 + _th, max_w, max_h); |
| 98 | |
| 99 | // The tab widget |
| 100 | xpos = 2; ypos = 4; |
| 101 | myTab = new TabWidget(this, font, xpos, ypos + _th, _w - 2*xpos, _h - _th - buttonHeight - 20); |
| 102 | addTabWidget(myTab); |
| 103 | |
| 104 | xpos = HBORDER; ypos = VBORDER; |
| 105 | ////////////////////////////////////////////////////////// |
| 106 | // 1) General options |
| 107 | tabID = myTab->addTab(" General " ); |
| 108 | |
| 109 | // Video renderer |
| 110 | myRenderer = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, |
| 111 | instance().frameBuffer().supportedRenderers(), |
| 112 | "Renderer " , lwidth); |
| 113 | wid.push_back(myRenderer); |
| 114 | ypos += lineHeight + VGAP; |
| 115 | |
| 116 | // TIA Palette |
| 117 | items.clear(); |
| 118 | VarList::push_back(items, "Standard" , "standard" ); |
| 119 | VarList::push_back(items, "Z26" , "z26" ); |
| 120 | VarList::push_back(items, "User" , "user" ); |
| 121 | myTIAPalette = new PopUpWidget(myTab, font, xpos, ypos, pwidth, |
| 122 | lineHeight, items, "TIA palette " , lwidth); |
| 123 | wid.push_back(myTIAPalette); |
| 124 | ypos += lineHeight + VGAP; |
| 125 | |
| 126 | // TIA interpolation |
| 127 | myTIAInterpolate = new CheckboxWidget(myTab, font, xpos, ypos + 1, "TIA interpolation " ); |
| 128 | wid.push_back(myTIAInterpolate); |
| 129 | ypos += lineHeight + VGAP; |
| 130 | |
| 131 | // TIA zoom levels (will be dynamically filled later) |
| 132 | myTIAZoom = new SliderWidget(myTab, font, xpos, ypos - 1, swidth, lineHeight, |
| 133 | "TIA zoom" , lwidth, 0, fontWidth * 4, "%" ); |
| 134 | myTIAZoom->setMinValue(200); myTIAZoom->setStepValue(FrameBuffer::ZOOM_STEPS * 100); |
| 135 | wid.push_back(myTIAZoom); |
| 136 | ypos += lineHeight + VGAP; |
| 137 | |
| 138 | // Aspect ratio (NTSC mode) |
| 139 | myNAspectRatio = |
| 140 | new SliderWidget(myTab, font, xpos, ypos-1, swidth, lineHeight, |
| 141 | "NTSC aspect " , lwidth, 0, |
| 142 | fontWidth * 4, "%" ); |
| 143 | myNAspectRatio->setMinValue(80); myNAspectRatio->setMaxValue(120); |
| 144 | myNAspectRatio->setTickmarkIntervals(2); |
| 145 | wid.push_back(myNAspectRatio); |
| 146 | ypos += lineHeight + VGAP; |
| 147 | |
| 148 | // Aspect ratio (PAL mode) |
| 149 | myPAspectRatio = |
| 150 | new SliderWidget(myTab, font, xpos, ypos-1, swidth, lineHeight, |
| 151 | "PAL aspect " , lwidth, 0, |
| 152 | fontWidth * 4, "%" ); |
| 153 | myPAspectRatio->setMinValue(80); myPAspectRatio->setMaxValue(120); |
| 154 | myPAspectRatio->setTickmarkIntervals(2); |
| 155 | wid.push_back(myPAspectRatio); |
| 156 | ypos += lineHeight + VGAP; |
| 157 | |
| 158 | // Speed |
| 159 | mySpeed = |
| 160 | new SliderWidget(myTab, font, xpos, ypos-1, swidth, lineHeight, |
| 161 | "Emul. speed " , lwidth, kSpeedupChanged, fontWidth * 5, "%" ); |
| 162 | mySpeed->setMinValue(MIN_SPEED); mySpeed->setMaxValue(MAX_SPEED); |
| 163 | mySpeed->setStepValue(SPEED_STEP); |
| 164 | mySpeed->setTickmarkIntervals(2); |
| 165 | wid.push_back(mySpeed); |
| 166 | ypos += lineHeight + VGAP; |
| 167 | |
| 168 | // Use sync to vblank |
| 169 | myUseVSync = new CheckboxWidget(myTab, font, xpos, ypos + 1, "VSync" ); |
| 170 | wid.push_back(myUseVSync); |
| 171 | |
| 172 | // Move over to the next column |
| 173 | xpos += mySpeed->getWidth() + 28; |
| 174 | ypos = VBORDER; |
| 175 | |
| 176 | // Fullscreen |
| 177 | myFullscreen = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Fullscreen" , kFullScreenChanged); |
| 178 | wid.push_back(myFullscreen); |
| 179 | ypos += lineHeight + VGAP; |
| 180 | |
| 181 | /*pwidth = font.getStringWidth("0: 3840x2860@120Hz"); |
| 182 | myFullScreenMode = new PopUpWidget(myTab, font, xpos + INDENT + 2, ypos, pwidth, lineHeight, |
| 183 | instance().frameBuffer().supportedScreenModes(), "Mode "); |
| 184 | wid.push_back(myFullScreenMode); |
| 185 | ypos += lineHeight + VGAP;*/ |
| 186 | |
| 187 | // FS stretch |
| 188 | myUseStretch = new CheckboxWidget(myTab, font, xpos + INDENT, ypos + 1, "Stretch" ); |
| 189 | wid.push_back(myUseStretch); |
| 190 | ypos += lineHeight + VGAP; |
| 191 | |
| 192 | // FS overscan |
| 193 | myTVOverscan = new SliderWidget(myTab, font, xpos + INDENT, ypos - 1, swidth, lineHeight, |
| 194 | "Overscan" , font.getStringWidth("Overscan " ), kOverscanChanged, fontWidth * 3, "%" ); |
| 195 | myTVOverscan->setMinValue(0); myTVOverscan->setMaxValue(10); |
| 196 | myTVOverscan->setTickmarkIntervals(2); |
| 197 | wid.push_back(myTVOverscan); |
| 198 | ypos += (lineHeight + VGAP) * 2; |
| 199 | |
| 200 | // Skip progress load bars for SuperCharger ROMs |
| 201 | // Doesn't really belong here, but I couldn't find a better place for it |
| 202 | myFastSCBios = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Fast SuperCharger load" ); |
| 203 | wid.push_back(myFastSCBios); |
| 204 | ypos += lineHeight + VGAP; |
| 205 | |
| 206 | // Show UI messages onscreen |
| 207 | myUIMessages = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Show UI messages" ); |
| 208 | wid.push_back(myUIMessages); |
| 209 | ypos += lineHeight + VGAP; |
| 210 | |
| 211 | // Center window (in windowed mode) |
| 212 | myCenter = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Center window" ); |
| 213 | wid.push_back(myCenter); |
| 214 | ypos += (lineHeight + VGAP) * 2; |
| 215 | |
| 216 | // Use multi-threading |
| 217 | myUseThreads = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Multi-threading" ); |
| 218 | wid.push_back(myUseThreads); |
| 219 | |
| 220 | // Add items for tab 0 |
| 221 | addToFocusList(wid, myTab, tabID); |
| 222 | |
| 223 | ////////////////////////////////////////////////////////// |
| 224 | // 2) TV effects options |
| 225 | wid.clear(); |
| 226 | tabID = myTab->addTab(" TV Effects " ); |
| 227 | xpos = HBORDER; |
| 228 | ypos = VBORDER; |
| 229 | swidth = font.getMaxCharWidth() * 8 - 4; |
| 230 | |
| 231 | // TV Mode |
| 232 | items.clear(); |
| 233 | VarList::push_back(items, "Disabled" , static_cast<uInt32>(NTSCFilter::Preset::OFF)); |
| 234 | VarList::push_back(items, "RGB" , static_cast<uInt32>(NTSCFilter::Preset::RGB)); |
| 235 | VarList::push_back(items, "S-Video" , static_cast<uInt32>(NTSCFilter::Preset::SVIDEO)); |
| 236 | VarList::push_back(items, "Composite" , static_cast<uInt32>(NTSCFilter::Preset::COMPOSITE)); |
| 237 | VarList::push_back(items, "Bad adjust" , static_cast<uInt32>(NTSCFilter::Preset::BAD)); |
| 238 | VarList::push_back(items, "Custom" , static_cast<uInt32>(NTSCFilter::Preset::CUSTOM)); |
| 239 | lwidth = font.getStringWidth("TV Mode " ); |
| 240 | pwidth = font.getStringWidth("Bad adjust" ); |
| 241 | myTVMode = |
| 242 | new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, |
| 243 | items, "TV mode " , lwidth, kTVModeChanged); |
| 244 | wid.push_back(myTVMode); |
| 245 | ypos += lineHeight + VGAP; |
| 246 | |
| 247 | // Custom adjustables (using macro voodoo) |
| 248 | xpos += INDENT - 2; ypos += 0; |
| 249 | lwidth = font.getStringWidth("Saturation " ); |
| 250 | |
| 251 | #define CREATE_CUSTOM_SLIDERS(obj, desc, cmd) \ |
| 252 | myTV ## obj = \ |
| 253 | new SliderWidget(myTab, font, xpos, ypos-1, swidth, lineHeight, \ |
| 254 | desc, lwidth, cmd, fontWidth*4, "%"); \ |
| 255 | myTV ## obj->setMinValue(0); myTV ## obj->setMaxValue(100); \ |
| 256 | myTV ## obj->setTickmarkIntervals(2); \ |
| 257 | wid.push_back(myTV ## obj); \ |
| 258 | ypos += lineHeight + VGAP; |
| 259 | |
| 260 | CREATE_CUSTOM_SLIDERS(Contrast, "Contrast " , 0) |
| 261 | CREATE_CUSTOM_SLIDERS(Bright, "Brightness " , 0) |
| 262 | CREATE_CUSTOM_SLIDERS(Hue, "Hue " , 0) |
| 263 | CREATE_CUSTOM_SLIDERS(Satur, "Saturation " , 0) |
| 264 | CREATE_CUSTOM_SLIDERS(Gamma, "Gamma " , 0) |
| 265 | CREATE_CUSTOM_SLIDERS(Sharp, "Sharpness " , 0) |
| 266 | CREATE_CUSTOM_SLIDERS(Res, "Resolution " , 0) |
| 267 | CREATE_CUSTOM_SLIDERS(Artifacts, "Artifacts " , 0) |
| 268 | CREATE_CUSTOM_SLIDERS(Fringe, "Fringing " , 0) |
| 269 | CREATE_CUSTOM_SLIDERS(Bleed, "Bleeding " , 0) |
| 270 | |
| 271 | xpos += myTVContrast->getWidth() + 30; |
| 272 | ypos = VBORDER; |
| 273 | |
| 274 | lwidth = font.getStringWidth("Intensity " ); |
| 275 | |
| 276 | // TV Phosphor effect |
| 277 | myTVPhosphor = new CheckboxWidget(myTab, font, xpos, ypos + 1, "Phosphor for all ROMs" , kPhosphorChanged); |
| 278 | wid.push_back(myTVPhosphor); |
| 279 | ypos += lineHeight + VGAP / 2; |
| 280 | |
| 281 | // TV Phosphor blend level |
| 282 | xpos += INDENT; |
| 283 | swidth = font.getMaxCharWidth() * 10; |
| 284 | CREATE_CUSTOM_SLIDERS(PhosLevel, "Blend " , kPhosBlendChanged) |
| 285 | ypos += 8; |
| 286 | |
| 287 | // Scanline intensity and interpolation |
| 288 | xpos -= INDENT; |
| 289 | myTVScanLabel = new StaticTextWidget(myTab, font, xpos, ypos, "Scanlines:" ); |
| 290 | ypos += lineHeight + VGAP / 2; |
| 291 | |
| 292 | xpos += INDENT; |
| 293 | CREATE_CUSTOM_SLIDERS(ScanIntense, "Intensity " , kScanlinesChanged) |
| 294 | ypos += lineHeight + 2; |
| 295 | |
| 296 | // Adjustable presets |
| 297 | xpos -= INDENT; |
| 298 | int cloneWidth = font.getStringWidth("Clone Bad Adjust" ) + 20; |
| 299 | #define CREATE_CLONE_BUTTON(obj, desc) \ |
| 300 | myClone ## obj = \ |
| 301 | new ButtonWidget(myTab, font, xpos, ypos, cloneWidth, buttonHeight,\ |
| 302 | desc, kClone ## obj ##Cmd); \ |
| 303 | wid.push_back(myClone ## obj); \ |
| 304 | ypos += lineHeight + 4 + VGAP; |
| 305 | |
| 306 | ypos += VGAP; |
| 307 | CREATE_CLONE_BUTTON(RGB, "Clone RGB" ) |
| 308 | CREATE_CLONE_BUTTON(Svideo, "Clone S-Video" ) |
| 309 | CREATE_CLONE_BUTTON(Composite, "Clone Composite" ) |
| 310 | CREATE_CLONE_BUTTON(Bad, "Clone Bad adjust" ) |
| 311 | CREATE_CLONE_BUTTON(Custom, "Revert" ) |
| 312 | |
| 313 | // Add items for tab 2 |
| 314 | addToFocusList(wid, myTab, tabID); |
| 315 | |
| 316 | // Activate the first tab |
| 317 | myTab->setActiveTab(0); |
| 318 | |
| 319 | // Add Defaults, OK and Cancel buttons |
| 320 | wid.clear(); |
| 321 | addDefaultsOKCancelBGroup(wid, font); |
| 322 | addBGroupToFocusList(wid); |
| 323 | |
| 324 | // Disable certain functions when we know they aren't present |
| 325 | #ifndef WINDOWED_SUPPORT |
| 326 | myFullscreen->clearFlags(Widget::FLAG_ENABLED); |
| 327 | myCenter->clearFlags(Widget::FLAG_ENABLED); |
| 328 | #endif |
| 329 | } |
| 330 | |
| 331 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 332 | void VideoDialog::loadConfig() |
| 333 | { |
| 334 | // Renderer settings |
| 335 | myRenderer->setSelected(instance().settings().getString("video" ), "default" ); |
| 336 | |
| 337 | // TIA zoom levels |
| 338 | // These are dynamically loaded, since they depend on the size of |
| 339 | // the desktop and which renderer we're using |
| 340 | float minZoom = instance().frameBuffer().supportedTIAMinZoom(); // or 2 if we allow lower values |
| 341 | float maxZoom = instance().frameBuffer().supportedTIAMaxZoom(); |
| 342 | |
| 343 | myTIAZoom->setMinValue(minZoom * 100); |
| 344 | myTIAZoom->setMaxValue(maxZoom * 100); |
| 345 | myTIAZoom->setTickmarkIntervals((maxZoom - minZoom) * 2); // every ~50% |
| 346 | myTIAZoom->setValue(instance().settings().getFloat("tia.zoom" ) * 100); |
| 347 | |
| 348 | // TIA Palette |
| 349 | myTIAPalette->setSelected( |
| 350 | instance().settings().getString("palette" ), "standard" ); |
| 351 | |
| 352 | // TIA interpolation |
| 353 | myTIAInterpolate->setState(instance().settings().getBool("tia.inter" )); |
| 354 | |
| 355 | // Aspect ratio setting (NTSC and PAL) |
| 356 | myNAspectRatio->setValue(instance().settings().getInt("tia.aspectn" )); |
| 357 | myPAspectRatio->setValue(instance().settings().getInt("tia.aspectp" )); |
| 358 | |
| 359 | // Emulation speed |
| 360 | int speed = mapSpeed(instance().settings().getFloat("speed" )); |
| 361 | mySpeed->setValue(speed); |
| 362 | mySpeed->setValueLabel(formatSpeed(speed)); |
| 363 | |
| 364 | // Fullscreen |
| 365 | myFullscreen->setState(instance().settings().getBool("fullscreen" )); |
| 366 | /*string mode = instance().settings().getString("fullscreenmode"); |
| 367 | myFullScreenMode->setSelected(mode);*/ |
| 368 | // Fullscreen stretch setting |
| 369 | myUseStretch->setState(instance().settings().getBool("tia.fs_stretch" )); |
| 370 | // Fullscreen overscan setting |
| 371 | myTVOverscan->setValue(instance().settings().getInt("tia.fs_overscan" )); |
| 372 | handleFullScreenChange(); |
| 373 | |
| 374 | // Use sync to vertical blank |
| 375 | myUseVSync->setState(instance().settings().getBool("vsync" )); |
| 376 | |
| 377 | // Show UI messages |
| 378 | myUIMessages->setState(instance().settings().getBool("uimessages" )); |
| 379 | |
| 380 | // Center window |
| 381 | myCenter->setState(instance().settings().getBool("center" )); |
| 382 | |
| 383 | // Fast loading of Supercharger BIOS |
| 384 | myFastSCBios->setState(instance().settings().getBool("fastscbios" )); |
| 385 | |
| 386 | // Multi-threaded rendering |
| 387 | myUseThreads->setState(instance().settings().getBool("threads" )); |
| 388 | |
| 389 | // TV Mode |
| 390 | myTVMode->setSelected( |
| 391 | instance().settings().getString("tv.filter" ), "0" ); |
| 392 | int preset = instance().settings().getInt("tv.filter" ); |
| 393 | handleTVModeChange(NTSCFilter::Preset(preset)); |
| 394 | |
| 395 | // TV Custom adjustables |
| 396 | loadTVAdjustables(NTSCFilter::Preset::CUSTOM); |
| 397 | |
| 398 | // TV phosphor mode |
| 399 | myTVPhosphor->setState(instance().settings().getString("tv.phosphor" ) == "always" ); |
| 400 | |
| 401 | // TV phosphor blend |
| 402 | myTVPhosLevel->setValue(instance().settings().getInt("tv.phosblend" )); |
| 403 | handlePhosphorChange(); |
| 404 | |
| 405 | // TV scanline intensity and interpolation |
| 406 | myTVScanIntense->setValue(instance().settings().getInt("tv.scanlines" )); |
| 407 | |
| 408 | myTab->loadConfig(); |
| 409 | } |
| 410 | |
| 411 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 412 | void VideoDialog::saveConfig() |
| 413 | { |
| 414 | // Renderer setting |
| 415 | instance().settings().setValue("video" , |
| 416 | myRenderer->getSelectedTag().toString()); |
| 417 | |
| 418 | // TIA zoom levels |
| 419 | instance().settings().setValue("tia.zoom" , myTIAZoom->getValue() / 100.0); |
| 420 | |
| 421 | // TIA Palette |
| 422 | instance().settings().setValue("palette" , |
| 423 | myTIAPalette->getSelectedTag().toString()); |
| 424 | |
| 425 | // TIA interpolation |
| 426 | instance().settings().setValue("tia.inter" , myTIAInterpolate->getState()); |
| 427 | |
| 428 | // Aspect ratio setting (NTSC and PAL) |
| 429 | instance().settings().setValue("tia.aspectn" , myNAspectRatio->getValueLabel()); |
| 430 | instance().settings().setValue("tia.aspectp" , myPAspectRatio->getValueLabel()); |
| 431 | |
| 432 | // Speed |
| 433 | int speedup = mySpeed->getValue(); |
| 434 | instance().settings().setValue("speed" , unmapSpeed(speedup)); |
| 435 | if (instance().hasConsole()) instance().console().initializeAudio(); |
| 436 | |
| 437 | // Fullscreen |
| 438 | instance().settings().setValue("fullscreen" , myFullscreen->getState()); |
| 439 | /*instance().settings().setValue("fullscreenmode", |
| 440 | myFullScreenMode->getSelectedTag().toString());*/ |
| 441 | // Fullscreen stretch setting |
| 442 | instance().settings().setValue("tia.fs_stretch" , myUseStretch->getState()); |
| 443 | // Fullscreen overscan |
| 444 | instance().settings().setValue("tia.fs_overscan" , myTVOverscan->getValueLabel()); |
| 445 | |
| 446 | // Use sync to vertical blank |
| 447 | instance().settings().setValue("vsync" , myUseVSync->getState()); |
| 448 | |
| 449 | // Show UI messages |
| 450 | instance().settings().setValue("uimessages" , myUIMessages->getState()); |
| 451 | |
| 452 | // Center window |
| 453 | instance().settings().setValue("center" , myCenter->getState()); |
| 454 | |
| 455 | // Fast loading of Supercharger BIOS |
| 456 | instance().settings().setValue("fastscbios" , myFastSCBios->getState()); |
| 457 | |
| 458 | // Multi-threaded rendering |
| 459 | instance().settings().setValue("threads" , myUseThreads->getState()); |
| 460 | if(instance().hasConsole()) |
| 461 | instance().frameBuffer().tiaSurface().ntsc().enableThreading(myUseThreads->getState()); |
| 462 | |
| 463 | // TV Mode |
| 464 | instance().settings().setValue("tv.filter" , |
| 465 | myTVMode->getSelectedTag().toString()); |
| 466 | |
| 467 | // TV Custom adjustables |
| 468 | NTSCFilter::Adjustable adj; |
| 469 | adj.hue = myTVHue->getValue(); |
| 470 | adj.saturation = myTVSatur->getValue(); |
| 471 | adj.contrast = myTVContrast->getValue(); |
| 472 | adj.brightness = myTVBright->getValue(); |
| 473 | adj.sharpness = myTVSharp->getValue(); |
| 474 | adj.gamma = myTVGamma->getValue(); |
| 475 | adj.resolution = myTVRes->getValue(); |
| 476 | adj.artifacts = myTVArtifacts->getValue(); |
| 477 | adj.fringing = myTVFringe->getValue(); |
| 478 | adj.bleed = myTVBleed->getValue(); |
| 479 | instance().frameBuffer().tiaSurface().ntsc().setCustomAdjustables(adj); |
| 480 | |
| 481 | // TV phosphor mode |
| 482 | instance().settings().setValue("tv.phosphor" , |
| 483 | myTVPhosphor->getState() ? "always" : "byrom" ); |
| 484 | // TV phosphor blend |
| 485 | instance().settings().setValue("tv.phosblend" , myTVPhosLevel->getValueLabel()); |
| 486 | |
| 487 | // TV scanline intensity |
| 488 | instance().settings().setValue("tv.scanlines" , myTVScanIntense->getValueLabel()); |
| 489 | |
| 490 | // Finally, issue a complete framebuffer re-initialization |
| 491 | instance().createFrameBuffer(); |
| 492 | } |
| 493 | |
| 494 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 495 | void VideoDialog::setDefaults() |
| 496 | { |
| 497 | switch(myTab->getActiveTab()) |
| 498 | { |
| 499 | case 0: // General |
| 500 | { |
| 501 | myRenderer->setSelectedIndex(0); |
| 502 | myTIAZoom->setValue(300); |
| 503 | myTIAPalette->setSelected("standard" , "" ); |
| 504 | myTIAInterpolate->setState(false); |
| 505 | myNAspectRatio->setValue(91); |
| 506 | myPAspectRatio->setValue(109); |
| 507 | mySpeed->setValue(0); |
| 508 | |
| 509 | myFullscreen->setState(false); |
| 510 | //myFullScreenMode->setSelectedIndex(0); |
| 511 | myUseStretch->setState(true); |
| 512 | myUseVSync->setState(true); |
| 513 | myUIMessages->setState(true); |
| 514 | myCenter->setState(false); |
| 515 | myFastSCBios->setState(true); |
| 516 | myUseThreads->setState(false); |
| 517 | break; |
| 518 | } |
| 519 | |
| 520 | case 1: // TV effects |
| 521 | { |
| 522 | myTVMode->setSelected("0" , "0" ); |
| 523 | |
| 524 | // TV phosphor mode |
| 525 | myTVPhosphor->setState(false); |
| 526 | |
| 527 | // TV phosphor blend |
| 528 | myTVPhosLevel->setValue(50); |
| 529 | |
| 530 | // TV scanline intensity and interpolation |
| 531 | myTVScanIntense->setValue(25); |
| 532 | |
| 533 | // Make sure that mutually-exclusive items are not enabled at the same time |
| 534 | handleTVModeChange(NTSCFilter::Preset::OFF); |
| 535 | handlePhosphorChange(); |
| 536 | loadTVAdjustables(NTSCFilter::Preset::CUSTOM); |
| 537 | break; |
| 538 | } |
| 539 | } |
| 540 | } |
| 541 | |
| 542 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 543 | void VideoDialog::handleTVModeChange(NTSCFilter::Preset preset) |
| 544 | { |
| 545 | bool enable = preset == NTSCFilter::Preset::CUSTOM; |
| 546 | |
| 547 | myTVSharp->setEnabled(enable); |
| 548 | myTVHue->setEnabled(enable); |
| 549 | myTVRes->setEnabled(enable); |
| 550 | myTVArtifacts->setEnabled(enable); |
| 551 | myTVFringe->setEnabled(enable); |
| 552 | myTVBleed->setEnabled(enable); |
| 553 | myTVBright->setEnabled(enable); |
| 554 | myTVContrast->setEnabled(enable); |
| 555 | myTVSatur->setEnabled(enable); |
| 556 | myTVGamma->setEnabled(enable); |
| 557 | myCloneComposite->setEnabled(enable); |
| 558 | myCloneSvideo->setEnabled(enable); |
| 559 | myCloneRGB->setEnabled(enable); |
| 560 | myCloneBad->setEnabled(enable); |
| 561 | myCloneCustom->setEnabled(enable); |
| 562 | } |
| 563 | |
| 564 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 565 | void VideoDialog::loadTVAdjustables(NTSCFilter::Preset preset) |
| 566 | { |
| 567 | NTSCFilter::Adjustable adj; |
| 568 | instance().frameBuffer().tiaSurface().ntsc().getAdjustables( |
| 569 | adj, NTSCFilter::Preset(preset)); |
| 570 | myTVSharp->setValue(adj.sharpness); |
| 571 | myTVHue->setValue(adj.hue); |
| 572 | myTVRes->setValue(adj.resolution); |
| 573 | myTVArtifacts->setValue(adj.artifacts); |
| 574 | myTVFringe->setValue(adj.fringing); |
| 575 | myTVBleed->setValue(adj.bleed); |
| 576 | myTVBright->setValue(adj.brightness); |
| 577 | myTVContrast->setValue(adj.contrast); |
| 578 | myTVSatur->setValue(adj.saturation); |
| 579 | myTVGamma->setValue(adj.gamma); |
| 580 | } |
| 581 | |
| 582 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 583 | void VideoDialog::handleFullScreenChange() |
| 584 | { |
| 585 | bool enable = myFullscreen->getState(); |
| 586 | myUseStretch->setEnabled(enable); |
| 587 | myTVOverscan->setEnabled(enable); |
| 588 | } |
| 589 | |
| 590 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 591 | void VideoDialog::handleOverscanChange() |
| 592 | { |
| 593 | if (myTVOverscan->getValue() == 0) |
| 594 | { |
| 595 | myTVOverscan->setValueLabel("Off" ); |
| 596 | myTVOverscan->setValueUnit("" ); |
| 597 | } |
| 598 | else |
| 599 | myTVOverscan->setValueUnit("%" ); |
| 600 | } |
| 601 | |
| 602 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 603 | void VideoDialog::handlePhosphorChange() |
| 604 | { |
| 605 | myTVPhosLevel->setEnabled(myTVPhosphor->getState()); |
| 606 | } |
| 607 | |
| 608 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 609 | void VideoDialog::handleCommand(CommandSender* sender, int cmd, |
| 610 | int data, int id) |
| 611 | { |
| 612 | switch (cmd) |
| 613 | { |
| 614 | case GuiObject::kOKCmd: |
| 615 | saveConfig(); |
| 616 | close(); |
| 617 | break; |
| 618 | |
| 619 | case GuiObject::kDefaultsCmd: |
| 620 | setDefaults(); |
| 621 | break; |
| 622 | |
| 623 | case kSpeedupChanged: |
| 624 | mySpeed->setValueLabel(formatSpeed(mySpeed->getValue())); |
| 625 | break; |
| 626 | |
| 627 | case kFullScreenChanged: |
| 628 | handleFullScreenChange(); |
| 629 | break; |
| 630 | |
| 631 | case kOverscanChanged: |
| 632 | handleOverscanChange(); |
| 633 | break; |
| 634 | |
| 635 | case kTVModeChanged: |
| 636 | handleTVModeChange(NTSCFilter::Preset(myTVMode->getSelectedTag().toInt())); |
| 637 | break; |
| 638 | |
| 639 | case kCloneCompositeCmd: loadTVAdjustables(NTSCFilter::Preset::COMPOSITE); |
| 640 | break; |
| 641 | case kCloneSvideoCmd: loadTVAdjustables(NTSCFilter::Preset::SVIDEO); |
| 642 | break; |
| 643 | case kCloneRGBCmd: loadTVAdjustables(NTSCFilter::Preset::RGB); |
| 644 | break; |
| 645 | case kCloneBadCmd: loadTVAdjustables(NTSCFilter::Preset::BAD); |
| 646 | break; |
| 647 | case kCloneCustomCmd: loadTVAdjustables(NTSCFilter::Preset::CUSTOM); |
| 648 | break; |
| 649 | |
| 650 | case kScanlinesChanged: |
| 651 | if (myTVScanIntense->getValue() == 0) |
| 652 | { |
| 653 | myTVScanIntense->setValueLabel("Off" ); |
| 654 | myTVScanIntense->setValueUnit("" ); |
| 655 | } |
| 656 | else |
| 657 | myTVScanIntense->setValueUnit("%" ); |
| 658 | break; |
| 659 | |
| 660 | case kPhosphorChanged: |
| 661 | handlePhosphorChange(); |
| 662 | break; |
| 663 | |
| 664 | case kPhosBlendChanged: |
| 665 | if (myTVPhosLevel->getValue() == 0) |
| 666 | { |
| 667 | myTVPhosLevel->setValueLabel("Off" ); |
| 668 | myTVPhosLevel->setValueUnit("" ); |
| 669 | } |
| 670 | else |
| 671 | myTVPhosLevel->setValueUnit("%" ); |
| 672 | break; |
| 673 | |
| 674 | default: |
| 675 | Dialog::handleCommand(sender, cmd, data, 0); |
| 676 | break; |
| 677 | } |
| 678 | } |
| 679 | |