openMSX
GLPostProcessor.cc
Go to the documentation of this file.
1 #include "GLPostProcessor.hh"
2 #include "GLContext.hh"
3 #include "GLScaler.hh"
4 #include "GLScalerFactory.hh"
5 #include "FloatSetting.hh"
6 #include "OutputSurface.hh"
7 #include "RawFrame.hh"
8 #include "Math.hh"
9 #include "InitException.hh"
10 #include "gl_transform.hh"
11 #include "random.hh"
12 #include "ranges.hh"
13 #include "stl.hh"
14 #include "vla.hh"
15 #include <cassert>
16 #include <cstdint>
17 
18 using namespace gl;
19 
20 namespace openmsx {
21 
22 GLPostProcessor::GLPostProcessor(
23  MSXMotherBoard& motherBoard_, Display& display_,
24  OutputSurface& screen_, const std::string& videoSource,
25  unsigned maxWidth_, unsigned height_, bool canDoInterlace_)
26  : PostProcessor(motherBoard_, display_, screen_,
27  videoSource, maxWidth_, height_, canDoInterlace_)
28  , noiseTextureA(true, true) // interpolate + wrap
29  , noiseTextureB(true, true)
30  , height(height_)
31 {
32  scaleAlgorithm = static_cast<RenderSettings::ScaleAlgorithm>(-1); // not a valid scaler
33 
34  frameCounter = 0;
35  noiseX = noiseY = 0.0f;
36  preCalcNoise(renderSettings.getNoise());
37  initBuffers();
38 
39  storedFrame = false;
40  for (int i = 0; i < 2; ++i) {
41  colorTex[i].bind();
42  colorTex[i].setInterpolation(true);
43  auto [w, h] = screen.getLogicalSize();
44  glTexImage2D(GL_TEXTURE_2D, // target
45  0, // level
46  GL_RGB8, // internal format
47  w, // width
48  h, // height
49  0, // border
50  GL_RGB, // format
51  GL_UNSIGNED_BYTE, // type
52  nullptr); // data
53  fbo[i] = FrameBufferObject(colorTex[i]);
54  }
55 
56  VertexShader vertexShader ("monitor3D.vert");
57  FragmentShader fragmentShader("monitor3D.frag");
58  monitor3DProg.attach(vertexShader);
59  monitor3DProg.attach(fragmentShader);
60  monitor3DProg.bindAttribLocation(0, "a_position");
61  monitor3DProg.bindAttribLocation(1, "a_normal");
62  monitor3DProg.bindAttribLocation(2, "a_texCoord");
63  monitor3DProg.link();
64  preCalcMonitor3D(renderSettings.getHorizontalStretch());
65 
68 }
69 
71 {
74 }
75 
76 void GLPostProcessor::initBuffers()
77 {
78  const vec2 pos[4] = {
79  vec2(-1, 1), vec2(-1,-1), vec2( 1,-1), vec2( 1, 1)
80  };
81  const vec2 tex[4] = {
82  vec2( 0, 1), vec2( 0, 0), vec2( 1, 0), vec2( 1, 1)
83  };
84  glBindBuffer(GL_ARRAY_BUFFER, vbo[0].get());
85  glBufferData(GL_ARRAY_BUFFER, sizeof(pos), pos, GL_STATIC_DRAW);
86  glBindBuffer(GL_ARRAY_BUFFER, vbo[1].get());
87  glBufferData(GL_ARRAY_BUFFER, sizeof(tex), tex, GL_STATIC_DRAW);
88 
89  vao.bind();
90  glBindBuffer(GL_ARRAY_BUFFER, vbo[0].get());
91  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
92  glEnableVertexAttribArray(0);
93  glBindBuffer(GL_ARRAY_BUFFER, vbo[1].get());
94  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
95  glEnableVertexAttribArray(1);
96  vao.unbind();
97 
98  glowVAO.bind();
99  glBindBuffer(GL_ARRAY_BUFFER, vbo[0].get());
100  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
101  glEnableVertexAttribArray(0);
102  glBindBuffer(GL_ARRAY_BUFFER, vbo[1].get());
103  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
104  glEnableVertexAttribArray(1);
105  glowVAO.unbind();
106 }
107 
108 void GLPostProcessor::createRegions()
109 {
110  regions.clear();
111 
112  const unsigned srcHeight = paintFrame->getHeight();
113  const unsigned dstHeight = screen.getLogicalHeight();
114 
115  unsigned g = Math::gcd(srcHeight, dstHeight);
116  unsigned srcStep = srcHeight / g;
117  unsigned dstStep = dstHeight / g;
118 
119  // TODO: Store all MSX lines in RawFrame and only scale the ones that fit
120  // on the PC screen, as a preparation for resizable output window.
121  unsigned srcStartY = 0;
122  unsigned dstStartY = 0;
123  while (dstStartY < dstHeight) {
124  // Currently this is true because the source frame height
125  // is always >= dstHeight/(dstStep/srcStep).
126  assert(srcStartY < srcHeight);
127 
128  // get region with equal lineWidth
129  unsigned lineWidth = getLineWidth(paintFrame, srcStartY, srcStep);
130  unsigned srcEndY = srcStartY + srcStep;
131  unsigned dstEndY = dstStartY + dstStep;
132  while ((srcEndY < srcHeight) && (dstEndY < dstHeight) &&
133  (getLineWidth(paintFrame, srcEndY, srcStep) == lineWidth)) {
134  srcEndY += srcStep;
135  dstEndY += dstStep;
136  }
137 
138  regions.emplace_back(srcStartY, srcEndY,
139  dstStartY, dstEndY,
140  lineWidth);
141 
142  // next region
143  srcStartY = srcEndY;
144  dstStartY = dstEndY;
145  }
146 }
147 
149 {
151  interleaveCount ^= 1;
152  if (interleaveCount) {
153  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
154  glClear(GL_COLOR_BUFFER_BIT);
155  return;
156  }
157  }
158 
159  auto deform = renderSettings.getDisplayDeform();
160  float horStretch = renderSettings.getHorizontalStretch();
161  int glow = renderSettings.getGlow();
162  bool renderToTexture = (deform != RenderSettings::DEFORM_NORMAL) ||
163  (horStretch != 320.0f) ||
164  (glow != 0) ||
166 
167  if ((screen.getViewOffset() != ivec2()) || // any part of the screen not covered by the viewport?
168  (deform == RenderSettings::DEFORM_3D) || !paintFrame) {
169  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
170  glClear(GL_COLOR_BUFFER_BIT);
171  if (!paintFrame) {
172  return;
173  }
174  }
175 
176  // New scaler algorithm selected?
177  auto algo = renderSettings.getScaleAlgorithm();
178  if (scaleAlgorithm != algo) {
179  scaleAlgorithm = algo;
181 
182  // Re-upload frame data, this is both
183  // - Chunks of RawFrame with a specific linewidth, possibly
184  // with some extra lines above and below each chunk that are
185  // also converted to this linewidth.
186  // - Extra data that is specific for the scaler (ATM only the
187  // hq and hqlite scalers require this).
188  // Re-uploading the first is not strictly needed. But switching
189  // scalers doesn't happen that often, so it also doesn't hurt
190  // and it keeps the code simpler.
191  uploadFrame();
192  }
193 
194  auto [scrnWidth, scrnHeight] = screen.getLogicalSize();
195  if (renderToTexture) {
196  glViewport(0, 0, scrnWidth, scrnHeight);
197  glBindTexture(GL_TEXTURE_2D, 0);
198  fbo[frameCounter & 1].push();
199  }
200 
201  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
202 
203  for (auto& r : regions) {
204  //fprintf(stderr, "post processing lines %d-%d: %d\n",
205  // r.srcStartY, r.srcEndY, r.lineWidth);
206  auto it = find_if_unguarded(textures,
207  EqualTupleValue<0>(r.lineWidth));
208  auto superImpose = superImposeVideoFrame
209  ? &superImposeTex : nullptr;
210  currScaler->scaleImage(
211  it->second.tex, superImpose,
212  r.srcStartY, r.srcEndY, r.lineWidth, // src
213  r.dstStartY, r.dstEndY, scrnWidth, // dst
214  paintFrame->getHeight()); // dst
215  //GLUtil::checkGLError("GLPostProcessor::paint");
216  }
217 
218  drawNoise();
219  drawGlow(glow);
220 
221  if (renderToTexture) {
222  fbo[frameCounter & 1].pop();
223  colorTex[frameCounter & 1].bind();
224  auto [x, y] = screen.getViewOffset();
225  auto [w, h] = screen.getViewSize();
226  glViewport(x, y, w, h);
227 
228  if (deform == RenderSettings::DEFORM_3D) {
229  drawMonitor3D();
230  } else {
231  gl::context->progTex.activate();
232  glUniform4f(gl::context->unifTexColor,
233  1.0f, 1.0f, 1.0f, 1.0f);
234  mat4 I;
235  glUniformMatrix4fv(gl::context->unifTexMvp,
236  1, GL_FALSE, &I[0][0]);
237 
238  vao.bind();
239  if (horStretch != 320.0f) {
240  float x1 = (320.0f - float(horStretch)) / (2.0f * 320.0f);
241  float x2 = 1.0f - x1;
242  vec2 tex[4] = {
243  vec2(x1, 1), vec2(x1, 0), vec2(x2, 0), vec2(x2, 1)
244  };
245  glBindBuffer(GL_ARRAY_BUFFER, stretchVBO.get());
246  glBufferData(GL_ARRAY_BUFFER, sizeof(tex), tex, GL_STATIC_DRAW);
247  } else {
248  glBindBuffer(GL_ARRAY_BUFFER, vbo[1].get());
249  }
250  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
251  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
252  vao.unbind();
253  }
254  storedFrame = true;
255  } else {
256  storedFrame = false;
257  }
258 }
259 
260 std::unique_ptr<RawFrame> GLPostProcessor::rotateFrames(
261  std::unique_ptr<RawFrame> finishedFrame, EmuTime::param time)
262 {
263  std::unique_ptr<RawFrame> reuseFrame =
264  PostProcessor::rotateFrames(std::move(finishedFrame), time);
265  uploadFrame();
266  ++frameCounter;
267  noiseX = random_float(0.0f, 1.0f);
268  noiseY = random_float(0.0f, 1.0f);
269  return reuseFrame;
270 }
271 
272 void GLPostProcessor::update(const Setting& setting)
273 {
274  VideoLayer::update(setting);
275  auto& noiseSetting = renderSettings.getNoiseSetting();
276  auto& horizontalStretch = renderSettings.getHorizontalStretchSetting();
277  if (&setting == &noiseSetting) {
278  preCalcNoise(noiseSetting.getDouble());
279  } else if (&setting == &horizontalStretch) {
280  preCalcMonitor3D(horizontalStretch.getDouble());
281  }
282 }
283 
284 void GLPostProcessor::uploadFrame()
285 {
286  createRegions();
287 
288  const unsigned srcHeight = paintFrame->getHeight();
289  for (auto& r : regions) {
290  // upload data
291  // TODO get before/after data from scaler
292  unsigned before = 1;
293  unsigned after = 1;
294  uploadBlock(std::max<int>(0, r.srcStartY - before),
295  std::min<int>(srcHeight, r.srcEndY + after),
296  r.lineWidth);
297  }
298 
299  if (superImposeVideoFrame) {
300  int w = superImposeVideoFrame->getWidth();
301  int h = superImposeVideoFrame->getHeight();
302  if (superImposeTex.getWidth() != w ||
303  superImposeTex.getHeight() != h) {
304  superImposeTex.resize(w, h);
305  superImposeTex.setInterpolation(true);
306  }
307  superImposeTex.bind();
308  glTexSubImage2D(
309  GL_TEXTURE_2D, // target
310  0, // level
311  0, // offset x
312  0, // offset y
313  w, // width
314  h, // height
315  GL_BGRA, // format
316  GL_UNSIGNED_BYTE, // type
317  const_cast<RawFrame*>(superImposeVideoFrame)->getLinePtrDirect<unsigned>(0)); // data
318  }
319 }
320 
321 void GLPostProcessor::uploadBlock(
322  unsigned srcStartY, unsigned srcEndY, unsigned lineWidth)
323 {
324  // create texture/pbo if needed
325  auto it = ranges::find_if(textures, EqualTupleValue<0>(lineWidth));
326  if (it == end(textures)) {
327  TextureData textureData;
328 
329  textureData.tex.resize(lineWidth, height * 2); // *2 for interlace
330  textureData.pbo.setImage(lineWidth, height * 2);
331  textures.emplace_back(lineWidth, std::move(textureData));
332  it = end(textures) - 1;
333  }
334  auto& tex = it->second.tex;
335  auto& pbo = it->second.pbo;
336 
337  // bind texture
338  tex.bind();
339 
340  // upload data
341  uint32_t* mapped;
342  pbo.bind();
343  mapped = pbo.mapWrite();
344  for (unsigned y = srcStartY; y < srcEndY; ++y) {
345  auto* dest = mapped + y * lineWidth;
346  auto* data = paintFrame->getLinePtr(y, lineWidth, dest);
347  if (data != dest) {
348  memcpy(dest, data, lineWidth * sizeof(uint32_t));
349  }
350  }
351  pbo.unmap();
352 #if defined(__APPLE__)
353  // The nVidia GL driver for the GeForce 8000/9000 series seems to hang
354  // on texture data replacements that are 1 pixel wide and start on a
355  // line number that is a non-zero multiple of 16.
356  if (lineWidth == 1 && srcStartY != 0 && srcStartY % 16 == 0) {
357  srcStartY--;
358  }
359 #endif
360  glTexSubImage2D(
361  GL_TEXTURE_2D, // target
362  0, // level
363  0, // offset x
364  srcStartY, // offset y
365  lineWidth, // width
366  srcEndY - srcStartY, // height
367  GL_BGRA, // format
368  GL_UNSIGNED_BYTE, // type
369  pbo.getOffset(0, srcStartY)); // data
370  pbo.unbind();
371 
372  // possibly upload scaler specific data
373  if (currScaler) {
374  currScaler->uploadBlock(srcStartY, srcEndY, lineWidth, *paintFrame);
375  }
376 }
377 
378 void GLPostProcessor::drawGlow(int glow)
379 {
380  if ((glow == 0) || !storedFrame) return;
381 
382  gl::context->progTex.activate();
383  glEnable(GL_BLEND);
384  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
385  colorTex[(frameCounter & 1) ^ 1].bind();
386  glUniform4f(gl::context->unifTexColor,
387  1.0f, 1.0f, 1.0f, glow * 31 / 3200.0f);
388  mat4 I;
389  glUniformMatrix4fv(gl::context->unifTexMvp, 1, GL_FALSE, &I[0][0]);
390  glowVAO.bind();
391  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
392  glowVAO.unbind();
393  glDisable(GL_BLEND);
394 }
395 
396 void GLPostProcessor::preCalcNoise(float factor)
397 {
398  GLbyte buf1[256 * 256];
399  GLbyte buf2[256 * 256];
400  auto& generator = global_urng(); // fast (non-cryptographic) random numbers
401  std::normal_distribution<float> distribution(0.0f, 1.0f);
402  for (int i = 0; i < 256 * 256; ++i) {
403  float r = distribution(generator);
404  int s = Math::clip<-255, 255>(roundf(r * factor));
405  buf1[i] = (s > 0) ? s : 0;
406  buf2[i] = (s < 0) ? -s : 0;
407  }
408 
409  noiseTextureA.bind();
410  glTexImage2D(
411  GL_TEXTURE_2D, // target
412  0, // level
413  GL_RED, // internal format
414  256, // width
415  256, // height
416  0, // border
417  GL_RED, // format
418  GL_UNSIGNED_BYTE, // type
419  buf1); // data
420  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
421  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
422 
423  noiseTextureB.bind();
424  glTexImage2D(
425  GL_TEXTURE_2D, // target
426  0, // level
427  GL_RED, // internal format
428  256, // width
429  256, // height
430  0, // border
431  GL_RED, // format
432  GL_UNSIGNED_BYTE, // type
433  buf2); // data
434  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
435  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
436 
437  const vec2 pos[8][4] = {
438  { { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } },
439  { { -1, 1 }, { 1, 1 }, { 1, -1 }, { -1, -1 } },
440  { { -1, 1 }, { -1, -1 }, { 1, -1 }, { 1, 1 } },
441  { { 1, 1 }, { 1, -1 }, { -1, -1 }, { -1, 1 } },
442  { { 1, 1 }, { -1, 1 }, { -1, -1 }, { 1, -1 } },
443  { { 1, -1 }, { -1, -1 }, { -1, 1 }, { 1, 1 } },
444  { { 1, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 } },
445  { { -1, -1 }, { -1, 1 }, { 1, 1 }, { 1, -1 } }
446  };
447  glBindBuffer(GL_ARRAY_BUFFER, noiseVBO[0].get());
448  glBufferData(GL_ARRAY_BUFFER, sizeof(pos), pos, GL_STATIC_DRAW);
449 }
450 
451 void GLPostProcessor::drawNoise()
452 {
453  if (renderSettings.getNoise() == 0.0f) return;
454 
455  // Rotate and mirror noise texture in consecutive frames to avoid
456  // seeing 'patterns' in the noise.
457  vec2 noise(noiseX, noiseY);
458  const vec2 tex[4] = {
459  noise + vec2(0.0f, 1.875f),
460  noise + vec2(2.0f, 1.875f),
461  noise + vec2(2.0f, 0.0f ),
462  noise + vec2(0.0f, 0.0f )
463  };
464  unsigned seq = frameCounter & 7;
465 
466  gl::context->progTex.activate();
467  glEnable(GL_BLEND);
468  glBlendFunc(GL_ONE, GL_ONE);
469  glUniform4f(gl::context->unifTexColor, 1.0f, 1.0f, 1.0f, 1.0f);
470  mat4 I;
471  glUniformMatrix4fv(gl::context->unifTexMvp, 1, GL_FALSE, &I[0][0]);
472 
473  noiseVAO.bind();
474  glBindBuffer(GL_ARRAY_BUFFER, noiseVBO[0].get());
475  vec2* base = nullptr;
476  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, base + seq * 4);
477  glEnableVertexAttribArray(0);
478  glBindBuffer(GL_ARRAY_BUFFER, noiseVBO[1].get());
479  glBufferData(GL_ARRAY_BUFFER, sizeof(tex), tex, GL_STATIC_DRAW);
480  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
481  glEnableVertexAttribArray(1);
482 
483  noiseTextureA.bind();
484  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
485  glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
486  noiseTextureB.bind();
487  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
488  noiseVAO.unbind();
489 
490  glBlendEquation(GL_FUNC_ADD); // restore default
491  glDisable(GL_BLEND);
492 }
493 
494 constexpr int GRID_SIZE = 16;
495 constexpr int GRID_SIZE1 = GRID_SIZE + 1;
496 constexpr int NUM_INDICES = (GRID_SIZE1 * 2 + 2) * GRID_SIZE - 2;
497 struct Vertex {
501 };
502 
503 void GLPostProcessor::preCalcMonitor3D(float width)
504 {
505  // precalculate vertex-positions, -normals and -texture-coordinates
506  Vertex vertices[GRID_SIZE1][GRID_SIZE1];
507 
508  constexpr float GRID_SIZE2 = float(GRID_SIZE) / 2.0f;
509  float s = width / 320.0f;
510  float b = (320.0f - width) / (2.0f * 320.0f);
511 
512  for (int sx = 0; sx < GRID_SIZE1; ++sx) {
513  for (int sy = 0; sy < GRID_SIZE1; ++sy) {
514  Vertex& v = vertices[sx][sy];
515  float x = (sx - GRID_SIZE2) / GRID_SIZE2;
516  float y = (sy - GRID_SIZE2) / GRID_SIZE2;
517 
518  v.position = vec3(x, y, (x * x + y * y) / -12.0f);
519  v.normal = normalize(vec3(x / 6.0f, y / 6.0f, 1.0f)) * 1.2f;
520  v.tex = vec2((float(sx) / GRID_SIZE) * s + b,
521  float(sy) / GRID_SIZE);
522  }
523  }
524 
525  // calculate indices
526  uint16_t indices[NUM_INDICES];
527 
528  uint16_t* ind = indices;
529  for (int y = 0; y < GRID_SIZE; ++y) {
530  for (int x = 0; x < GRID_SIZE1; ++x) {
531  *ind++ = (y + 0) * GRID_SIZE1 + x;
532  *ind++ = (y + 1) * GRID_SIZE1 + x;
533  }
534  // skip 2, filled in later
535  ind += 2;
536  }
537  assert((ind - indices) == NUM_INDICES + 2);
538  ind = indices;
539  for (int y = 0; y < (GRID_SIZE - 1); ++y) {
540  ind += 2 * GRID_SIZE1;
541  // repeat prev and next index to restart strip
542  ind[0] = ind[-1];
543  ind[1] = ind[ 2];
544  ind += 2;
545  }
546 
547  // upload calculated values to buffers
548  monitor3DVAO.bind();
549  glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer.get());
550  glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,
551  GL_STATIC_DRAW);
552  char* base = nullptr;
553  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
554  base);
555  glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
556  base + sizeof(vec3));
557  glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
558  base + sizeof(vec3) + sizeof(vec3));
559  glEnableVertexAttribArray(0);
560  glEnableVertexAttribArray(1);
561  glEnableVertexAttribArray(2);
562  glBindBuffer(GL_ARRAY_BUFFER, 0);
563  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer.get());
564  glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,
565  GL_STATIC_DRAW);
566  monitor3DVAO.unbind();
567 
568  // calculate transformation matrices
569  mat4 proj = frustum(-1, 1, -1, 1, 1, 10);
570  mat4 tran = translate(vec3(0.0f, 0.4f, -2.0f));
571  mat4 rotx = rotateX(radians(-10.0f));
572  mat4 scal = scale(vec3(2.2f, 2.2f, 2.2f));
573 
574  mat3 normal = mat3(rotx);
575  mat4 mvp = proj * tran * rotx * scal;
576 
577  // set uniforms
578  monitor3DProg.activate();
579  glUniform1i(monitor3DProg.getUniformLocation("u_tex"), 0);
580  glUniformMatrix4fv(monitor3DProg.getUniformLocation("u_mvpMatrix"),
581  1, GL_FALSE, &mvp[0][0]);
582  glUniformMatrix3fv(monitor3DProg.getUniformLocation("u_normalMatrix"),
583  1, GL_FALSE, &normal[0][0]);
584 }
585 
586 void GLPostProcessor::drawMonitor3D()
587 {
588  monitor3DProg.activate();
589  monitor3DVAO.bind();
590  glDrawElements(GL_TRIANGLE_STRIP, NUM_INDICES, GL_UNSIGNED_SHORT, nullptr);
591  monitor3DVAO.unbind();
592 }
593 
594 } // namespace openmsx
gl::ColorTexture::resize
void resize(GLsizei width, GLsizei height)
Definition: GLUtil.cc:73
gl::FrameBufferObject::pop
void pop()
Definition: GLUtil.cc:122
gl::BufferObject::get
GLuint get() const
Definition: GLUtil.hh:446
openmsx::PostProcessor::paintFrame
FrameSource * paintFrame
Represents a frame as it should be displayed.
Definition: PostProcessor.hh:130
openmsx::RenderSettings::getGlow
int getGlow() const
The amount of glow [0..100].
Definition: RenderSettings.hh:88
openmsx::GLPostProcessor::paint
void paint(OutputSurface &output) override
Paint this layer.
Definition: GLPostProcessor.cc:148
openmsx::Subject::detach
void detach(Observer< T > &observer)
Definition: Subject.hh:56
gl::VertexShader
Wrapper around an OpenGL vertex shader: a program executed on the GPU that computes per-vertex stuff.
Definition: GLUtil.hh:343
gl::frustum
mat4 frustum(float left, float right, float bottom, float top, float nearVal, float farVal)
Definition: gl_transform.hh:184
gl::matMxN< 4, 4, float >
openmsx::GLPostProcessor::rotateFrames
std::unique_ptr< RawFrame > rotateFrames(std::unique_ptr< RawFrame > finishedFrame, EmuTime::param time) override
Sets up the "abcdFrame" variables for a new frame.
Definition: GLPostProcessor.cc:260
gl::ColorTexture::getWidth
GLsizei getWidth() const
Definition: GLUtil.hh:106
random.hh
openmsx::RenderSettings::getHorizontalStretch
float getHorizontalStretch() const
Definition: RenderSettings.hh:157
openmsx::RenderSettings::getHorizontalStretchSetting
FloatSetting & getHorizontalStretchSetting()
Amount of horizontal stretch.
Definition: RenderSettings.hh:154
gl::FrameBufferObject::push
void push()
Definition: GLUtil.cc:116
gl::ShaderProgram::bindAttribLocation
void bindAttribLocation(unsigned index, const char *name)
Bind the given name for a vertex shader attribute to the given location.
Definition: GLUtil.cc:277
openmsx::GLScalerFactory::createScaler
unique_ptr< GLScaler > createScaler(RenderSettings &renderSettings)
Instantiates a Scaler.
Definition: GLScalerFactory.cc:18
openmsx::FrameSource::getLinePtr
const Pixel * getLinePtr(int line, unsigned width, Pixel *buf) const
Gets a pointer to the pixels of the given line number.
Definition: FrameSource.hh:90
gl_transform.hh
gl::rotateX
mat4 rotateX(float angle)
Definition: gl_transform.hh:93
openmsx::OutputSurface::isViewScaled
bool isViewScaled() const
Definition: OutputSurface.hh:35
gl::ShaderProgram::activate
void activate() const
Makes this program the active shader program.
Definition: GLUtil.cc:290
RawFrame.hh
gl::Texture::bind
void bind()
Makes this texture the active GL texture.
Definition: GLUtil.hh:77
openmsx::PostProcessor::superImposeVideoFrame
const RawFrame * superImposeVideoFrame
Video frame on which to superimpose the (VDP) output.
Definition: PostProcessor.hh:137
ranges.hh
openmsx::RenderSettings::getNoiseSetting
FloatSetting & getNoiseSetting()
The amount of noise to add to the frame.
Definition: RenderSettings.hh:91
gl::ColorTexture::getHeight
GLsizei getHeight() const
Definition: GLUtil.hh:107
GLScaler.hh
openmsx::OutputSurface::getLogicalHeight
int getLogicalHeight() const
Definition: OutputSurface.hh:28
openmsx::OutputSurface::getViewOffset
gl::ivec2 getViewOffset() const
Definition: OutputSurface.hh:32
openmsx::Subject::attach
void attach(Observer< T > &observer)
Definition: Subject.hh:50
openmsx::GLPostProcessor::~GLPostProcessor
~GLPostProcessor() override
Definition: GLPostProcessor.cc:70
openmsx::Setting
Definition: Setting.hh:119
gl
Definition: gl_mat.hh:24
gl::vecN
Definition: gl_vec.hh:35
gl::ShaderProgram::getUniformLocation
GLint getUniformLocation(const char *name) const
Gets a reference to a uniform variable declared in the shader source.
Definition: GLUtil.cc:282
vla.hh
openmsx::RenderSettings::DEFORM_3D
@ DEFORM_3D
Definition: RenderSettings.hh:43
gl::FrameBufferObject
Definition: GLUtil.hh:114
openmsx::RenderSettings::getDisplayDeform
DisplayDeform getDisplayDeform()
Display deformation (normal, 3d) ATM this only works when using the SDLGL-PP renderer.
Definition: RenderSettings.hh:145
gl::VertexArray::bind
void bind() const
Bind this VertexArray.
Definition: GLUtil.hh:470
openmsx::RenderSettings::DEFORM_NORMAL
@ DEFORM_NORMAL
Definition: RenderSettings.hh:43
openmsx::Vertex::normal
vec3 normal
Definition: GLPostProcessor.cc:499
random_float
float random_float(float from, float upto)
Return a random float in the range [from, upto) (note: half-open interval).
Definition: random.hh:50
openmsx::MSXMotherBoard
Definition: MSXMotherBoard.hh:59
openmsx::Vertex
Definition: GLPostProcessor.cc:497
openmsx::PostProcessor::interleaveCount
int interleaveCount
Definition: PostProcessor.hh:140
openmsx::PostProcessor
Abstract base class for post processors.
Definition: PostProcessor.hh:29
openmsx::Vertex::position
vec3 position
Definition: GLPostProcessor.cc:498
gl::ivec2
vecN< 2, int > ivec2
Definition: gl_vec.hh:147
g
int g
Definition: ScopedAssign_test.cc:20
gl::vec3
vecN< 3, float > vec3
Definition: gl_vec.hh:145
openmsx::x
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:1419
openmsx::PostProcessor::rotateFrames
virtual std::unique_ptr< RawFrame > rotateFrames(std::unique_ptr< RawFrame > finishedFrame, EmuTime::param time)
Sets up the "abcdFrame" variables for a new frame.
Definition: PostProcessor.cc:93
OutputSurface.hh
openmsx::FrameSource::getHeight
unsigned getHeight() const
Gets the number of lines in this frame.
Definition: FrameSource.hh:43
gl::context
std::unique_ptr< Context > context
Definition: GLContext.cc:9
gl::ShaderProgram::attach
void attach(const Shader &shader)
Adds a given shader to this program.
Definition: GLUtil.cc:245
InitException.hh
gl::scale
mat4 scale(const vec3 &xyz)
Definition: gl_transform.hh:19
openmsx::Display
Represents the output window/screen of openMSX.
Definition: Display.hh:31
Math::gcd
unsigned gcd(unsigned a, unsigned b)
Calculate greatest common divider of two strictly positive integers.
Definition: Math.hh:135
Math::clip
int clip(int x)
Clips x to the range [LO,HI].
Definition: Math.hh:102
openmsx::OutputSurface
A frame buffer where pixels can be written to.
Definition: OutputSurface.hh:19
openmsx::Vertex::tex
vec2 tex
Definition: GLPostProcessor.cc:500
openmsx::PostProcessor::getLineWidth
static unsigned getLineWidth(FrameSource *frame, unsigned y, unsigned step)
Returns the maximum width for lines [y..y+step).
Definition: PostProcessor.cc:83
openmsx::GRID_SIZE1
constexpr int GRID_SIZE1
Definition: GLPostProcessor.cc:495
gl::normalize
vecN< N, T > normalize(const vecN< N, T > &x)
Definition: gl_vec.hh:355
gl::vec2
vecN< 2, float > vec2
Definition: gl_vec.hh:144
stl.hh
gl::VertexArray::unbind
void unbind() const
Unbind this VertexArray.
Definition: GLUtil.hh:474
find_if_unguarded
ITER find_if_unguarded(ITER first, ITER last, PRED pred)
Faster alternative to 'find_if' when it's guaranteed that the predicate will be true for at least one...
Definition: stl.hh:131
ranges::find_if
auto find_if(InputRange &&range, UnaryPredicate pred)
Definition: ranges.hh:113
openmsx::NUM_INDICES
constexpr int NUM_INDICES
Definition: GLPostProcessor.cc:496
openmsx::GLPostProcessor::update
void update(const Setting &setting) override
Definition: GLPostProcessor.cc:272
GLScalerFactory.hh
openmsx::FrameSource::getWidth
unsigned getWidth() const
Get the width of (all) lines in this frame.
Definition: FrameSource.hh:58
Math.hh
gl::ShaderProgram::link
void link()
Links all attached shaders together into one program.
Definition: GLUtil.cc:257
global_urng
auto & global_urng()
Return reference to a (shared) global random number generator.
Definition: random.hh:8
gl::mat3
matMxN< 3, 3, float > mat3
Definition: gl_mat.hh:158
openmsx::RenderSettings::getInterleaveBlackFrame
bool getInterleaveBlackFrame() const
Is black frame interleaving enabled?
Definition: RenderSettings.hh:171
gl::translate
mat4 translate(const vec3 &xyz)
Definition: gl_transform.hh:36
gl::FragmentShader
Wrapper around an OpenGL fragment shader: a program executed on the GPU that computes the colors of p...
Definition: GLUtil.hh:356
openmsx::PostProcessor::renderSettings
RenderSettings & renderSettings
Render settings.
Definition: PostProcessor.hh:106
openmsx::RenderSettings::getScaleAlgorithm
ScaleAlgorithm getScaleAlgorithm() const
The current scaling algorithm.
Definition: RenderSettings.hh:114
openmsx::RenderSettings::getNoise
float getNoise() const
Definition: RenderSettings.hh:92
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
GLContext.hh
gl::Texture::setInterpolation
void setInterpolation(bool interpolation)
Enable/disable bilinear interpolation for this texture.
Definition: GLUtil.cc:49
FloatSetting.hh
openmsx::RenderSettings::ScaleAlgorithm
ScaleAlgorithm
Scaler algorithm.
Definition: RenderSettings.hh:36
openmsx::GRID_SIZE
constexpr int GRID_SIZE
Definition: GLPostProcessor.cc:494
openmsx::VideoLayer::update
void update(const Setting &setting) override
Definition: VideoLayer.cc:50
gl::radians
T radians(T d)
Definition: gl_vec.hh:165
openmsx::OutputSurface::getLogicalSize
gl::ivec2 getLogicalSize() const
Definition: OutputSurface.hh:29
openmsx::OutputSurface::getViewSize
gl::ivec2 getViewSize() const
Definition: OutputSurface.hh:33
openmsx::PostProcessor::screen
OutputSurface & screen
The surface which is visible to the user.
Definition: PostProcessor.hh:109
GLPostProcessor.hh