openMSX
RenderSettings.cc
Go to the documentation of this file.
1#include "RenderSettings.hh"
2
4#include "CommandException.hh"
5#include "Version.hh"
6
7#include "stl.hh"
8#include "unreachable.hh"
9
10#include "build-info.hh"
11
12#include <algorithm>
13#include <iostream>
14#include <cmath>
15
16using namespace gl;
17
18namespace openmsx {
19
20EnumSetting<RenderSettings::ScaleAlgorithm>::Map RenderSettings::getScalerMap()
21{
22 using enum ScaleAlgorithm;
23 EnumSetting<ScaleAlgorithm>::Map scalerMap = {
24 {"simple", SIMPLE},
25 {"ScaleNx", SCALE},
26 {"hq", HQ},
27 {"RGBtriplet", RGBTRIPLET},
28 {"TV", TV}
29 };
30 return scalerMap;
31}
32
33EnumSetting<RenderSettings::RendererID>::Map RenderSettings::getRendererMap()
34{
35 using enum RendererID;
36 EnumSetting<RendererID>::Map rendererMap = {
37 {"uninitialized", UNINITIALIZED},
38 {"none", DUMMY},
39 {"SDLGL-PP", SDLGL_PP}
40 };
41 return rendererMap;
42}
43
45 : accuracySetting(commandController,
46 "accuracy", "rendering accuracy", Accuracy::PIXEL,
48 {"screen", Accuracy::SCREEN},
49 {"line", Accuracy::LINE},
50 {"pixel", Accuracy::PIXEL}})
51
52 , deinterlaceSetting(commandController,
53 "deinterlace", "deinterlacing on/off", true)
54
55 , deflickerSetting(commandController,
56 "deflicker", "deflicker on/off", false)
57
58 , maxFrameSkipSetting(commandController,
59 "maxframeskip", "set the max amount of frameskip", 3, 0, 100)
60
61 , minFrameSkipSetting(commandController,
62 "minframeskip", "set the min amount of frameskip", 0, 0, 100)
63
64 , fullScreenSetting(commandController,
65 "fullscreen", "full screen display on/off", false)
66
67 , gammaSetting(commandController, "gamma",
68 "amount of gamma correction: low is dark, high is bright",
69 1.1, 0.1, 5.0)
70
71 , brightnessSetting(commandController, "brightness",
72 "brightness video setting: "
73 "0 is normal, lower is darker, higher is brighter",
74 0.0, -100.0, 100.0)
75 , contrastSetting(commandController, "contrast",
76 "contrast video setting: "
77 "0 is normal, lower is less contrast, higher is more contrast",
78 0.0, -100.0, 100.0)
79
80 , colorMatrixSetting(commandController,
81 "color_matrix",
82 "3x3 matrix to transform MSX RGB to host RGB, see manual for details",
83 "{ 1 0 0 } { 0 1 0 } { 0 0 1 }")
84
85 , glowSetting(commandController,
86 "glow", "amount of afterglow effect: 0 = none, 100 = lots",
87 0, 0, 100)
88
89 , noiseSetting(commandController,
90 "noise", "amount of noise to add to the frame",
91 0.0, 0.0, 100.0)
92
93 , rendererSetting(commandController,
94 "renderer", "rendering back-end used to display the MSX screen",
95 RendererID::SDLGL_PP, getRendererMap(), Setting::Save::NO)
96
97 , horizontalBlurSetting(commandController,
98 "blur", "amount of horizontal blur effect: 0 = none, 100 = full",
99 50, 0, 100)
100
101 , scaleAlgorithmSetting(
102 commandController, "scale_algorithm", "scale algorithm",
103 ScaleAlgorithm::SIMPLE, getScalerMap())
104
105 , scaleFactorSetting(commandController,
106 "scale_factor", "scale factor",
108
109 , scanlineAlphaSetting(commandController,
110 "scanline", "amount of scanline effect: 0 = none, 100 = full",
111 20, 0, 100)
112
113 , limitSpritesSetting(commandController,
114 "limitsprites", "limit number of sprites per line "
115 "(on for realism, off to reduce sprite flashing)", true)
116
117 , disableSpritesSetting(commandController,
118 "disablesprites", "disable sprite rendering",
119 false, Setting::Save::NO)
120
121 , cmdTimingSetting(commandController,
122 "cmdtiming", "VDP command timing", false,
123 EnumSetting<bool>::Map{{"real", false}, {"broken", true}},
124 Setting::Save::NO)
125
126 , tooFastAccessSetting(commandController,
127 "too_fast_vram_access",
128 "Should too fast VDP VRAM access be correctly emulated.\n"
129 "Possible values are:\n"
130 " real -> too fast accesses are dropped\n"
131 " ignore -> access speed is ignored, all accesses are executed",
132 false,
133 EnumSetting<bool>::Map{{"real", false }, {"ignore", true}},
134 Setting::Save::NO)
135
136 , displayDeformSetting(
137 commandController,
138 "display_deform", "Display deform", DisplayDeform::NORMAL,
139 EnumSetting<DisplayDeform>::Map{
140 {"normal", DisplayDeform::NORMAL},
141 {"3d", DisplayDeform::_3D}})
142
143 , vSyncSetting(commandController,
144 "vsync", "Synchronize page flip with the host screen vertical sync:\n"
145 " on -> flip on host vsync: avoids tearing\n"
146 " off -> immediate flip: might be more fluent when host framerate"
147 " (typically 60Hz) differs from MSX framerate (50 or 60Hz).\n",
148 true)
149
150 // Many android devices are relatively low powered. Therefore use
151 // no stretch (value 320) as default for Android because it gives
152 // better performance
153 , horizontalStretchSetting(commandController,
154 "horizontal_stretch",
155 "Amount of horizontal stretch: this many MSX pixels will be "
156 "stretched over the complete width of the output screen.\n"
157 " 320 = no stretch (large borders)\n"
158 " 288 = a bit more than all border pixels\n"
159 " 284 = all border pixels\n"
160 " 280 = a bit less than all border pixels\n"
161 " 272 = realistic\n"
162 " 256 = max stretch (no border visible at all)\n"
163 " good values are 272 or 280\n",
164 PLATFORM_ANDROID ? 320.0 : 280.0, 256.0, 320.0)
165
166 , pointerHideDelaySetting(commandController,
167 "pointer_hide_delay",
168 "number of seconds after which the mouse pointer is hidden in the openMSX "
169 "window; negative = no hiding, 0 = immediately",
170 2.0, -1.0, 60.0)
171
172 , interleaveBlackFrameSetting(commandController,
173 "interleave_black_frame",
174 "Insert a black frame in between each normal MSX frame. "
175 "Useful on (100Hz+) lightboost enabled monitors to reduce "
176 "motion blur and double frame artifacts.",
177 false)
178{
179 brightnessSetting.attach(*this);
180 contrastSetting .attach(*this);
181 updateBrightnessAndContrast();
182
183 auto& interp = commandController.getInterpreter();
184 colorMatrixSetting.setChecker([this, &interp](const TclObject& newValue) {
185 try {
186 parseColorMatrix(interp, newValue);
187 } catch (CommandException& e) {
188 throw CommandException(
189 "Invalid color matrix: ", e.getMessage());
190 }
191 });
192 try {
193 parseColorMatrix(interp, colorMatrixSetting.getValue());
194 } catch (MSXException& e) {
195 std::cerr << e.getMessage() << '\n';
196 cmIdentity = true;
197 }
198
199 rendererSetting.setEnum(RendererID::UNINITIALIZED); // always start hidden
200 rendererSetting.setChecker([this](const TclObject& newValue) {
201 if (newValue.getString() == "uninitialized") {
202 throw CommandException("can't set special value 'uninitialized'");
203 }
204 // the default enum check
205 (void)rendererSetting.fromStringBase(newValue.getString());
206 });
207}
208
209RenderSettings::~RenderSettings()
210{
211 brightnessSetting.detach(*this);
212 contrastSetting .detach(*this);
213}
214
215void RenderSettings::update(const Setting& setting) noexcept
216{
217 if (&setting == &brightnessSetting) {
218 updateBrightnessAndContrast();
219 } else if (&setting == &contrastSetting) {
220 updateBrightnessAndContrast();
221 } else {
223 }
224}
225
226void RenderSettings::updateBrightnessAndContrast()
227{
228 float contrastValue = getContrast();
229 contrast = (contrastValue >= 0.0f) ? (1.0f + contrastValue * (1.0f / 25.0f))
230 : (1.0f + contrastValue * (1.0f / 125.0f));
231 brightness = (getBrightness() * (1.0f / 100.0f) - 0.5f) * contrast + 0.5f;
232}
233
234static float conv2(float x, float gamma)
235{
236 return ::powf(std::clamp(x, 0.0f, 1.0f), gamma);
237}
238
239float RenderSettings::transformComponent(float c) const
240{
241 float c2 = c * contrast + brightness;
242 return conv2(c2, 1.0f / getGamma());
243}
244
245vec3 RenderSettings::transformRGB(vec3 rgb) const
246{
247 auto [r, g, b] = colorMatrix * (rgb * contrast + vec3(brightness));
248 float gamma = 1.0f / getGamma();
249 return {conv2(r, gamma),
250 conv2(g, gamma),
251 conv2(b, gamma)};
252}
253
254void RenderSettings::parseColorMatrix(Interpreter& interp, const TclObject& value)
255{
256 if (value.getListLength(interp) != 3) {
257 throw CommandException("must have 3 rows");
258 }
259 bool identity = true;
260 for (auto i : xrange(3)) {
261 TclObject row = value.getListIndex(interp, i);
262 if (row.getListLength(interp) != 3) {
263 throw CommandException("each row must have 3 elements");
264 }
265 for (auto j : xrange(3)) {
266 TclObject element = row.getListIndex(interp, j);
267 float val = element.getFloat(interp);
268 colorMatrix[j][i] = val;
269 identity &= (val == (i == j ? 1.0f : 0.0f));
270 }
271 }
272 cmIdentity = identity;
273}
274
275} // namespace openmsx
BaseSetting * setting
int g
#define MIN_SCALE_FACTOR
Definition build-info.hh:18
#define PLATFORM_ANDROID
Definition build-info.hh:17
#define MAX_SCALE_FACTOR
Definition build-info.hh:19
EnumSettingBase::Map Map
Accuracy
Render accuracy: granularity of the rendered area.
RenderSettings(CommandController &commandController)
ScaleAlgorithm
Scaler algorithm.
RendererID
Enumeration of Renderers known to openMSX.
unsigned getListLength(Interpreter &interp) const
Definition TclObject.cc:155
TclObject getListIndex(Interpreter &interp, unsigned index) const
Definition TclObject.cc:173
constexpr double e
Definition Math.hh:21
Definition gl_mat.hh:23
vecN< 3, float > vec3
Definition gl_vec.hh:383
This file implemented 3 utility functions:
Definition Autofire.cc:11
#define UNREACHABLE
constexpr auto xrange(T e)
Definition xrange.hh:132