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 | |