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