openMSX
PixelOperations.hh
Go to the documentation of this file.
1 #ifndef PIXELOPERATIONS_HH
2 #define PIXELOPERATIONS_HH
3 
4 #include "unreachable.hh"
5 #include "build-info.hh"
6 #include "Math.hh"
7 #include <SDL.h>
8 
9 namespace openmsx {
10 
11 template<typename Pixel> class PixelOpBase
12 {
13 public:
14  explicit PixelOpBase(const SDL_PixelFormat& format_)
15  : format(format_)
16  , blendMask(calcBlendMask())
17  {
18  }
19 
20  const SDL_PixelFormat& getSDLPixelFormat() const { return format; }
21 
22  inline int getRmask() const { return format.Rmask; }
23  inline int getGmask() const { return format.Gmask; }
24  inline int getBmask() const { return format.Bmask; }
25  inline int getAmask() const { return format.Amask; }
26  inline int getRshift() const { return format.Rshift; }
27  inline int getGshift() const { return format.Gshift; }
28  inline int getBshift() const { return format.Bshift; }
29  inline int getAshift() const { return format.Ashift; }
30  inline int getRloss() const { return format.Rloss; }
31  inline int getGloss() const { return format.Gloss; }
32  inline int getBloss() const { return format.Bloss; }
33  inline int getAloss() const { return format.Aloss; }
34 
42  inline Pixel getBlendMask() const { return blendMask; }
43 
48  static constexpr bool IS_RGB565 = false;
49 
50 private:
51  inline Pixel calcBlendMask() const
52  {
53  int rBit = ~(getRmask() << 1) & getRmask();
54  int gBit = ~(getGmask() << 1) & getGmask();
55  int bBit = ~(getBmask() << 1) & getBmask();
56  return ~(rBit | gBit | bBit);
57  }
58 
59  const SDL_PixelFormat& format;
60 
67  const Pixel blendMask;
68 };
69 
70 // Specialization for 32bpp
71 // No need to store 'blendMask' in a member variable.
72 template<> class PixelOpBase<unsigned>
73 {
74 public:
75  explicit PixelOpBase(const SDL_PixelFormat& format_)
76  : format(format_) {}
77 
78  const SDL_PixelFormat& getSDLPixelFormat() const { return format; }
79 
80  inline int getRmask() const { return format.Rmask; }
81  inline int getGmask() const { return format.Gmask; }
82  inline int getBmask() const { return format.Bmask; }
83  inline int getAmask() const { return format.Amask; }
84  inline int getRshift() const { return format.Rshift; }
85  inline int getGshift() const { return format.Gshift; }
86  inline int getBshift() const { return format.Bshift; }
87  inline int getAshift() const { return format.Ashift; }
88  inline int getRloss() const { return 0; }
89  inline int getGloss() const { return 0; }
90  inline int getBloss() const { return 0; }
91  inline int getAloss() const { return 0; }
92 
93  inline unsigned getBlendMask() const { return 0xFEFEFEFE; }
94 
95  static constexpr bool IS_RGB565 = false;
96 
97 private:
98  const SDL_PixelFormat& format;
99 };
100 
101 
102 #if PLATFORM_DINGUX
103 // Specialization for dingoo (16bpp)
104 // We know the exact pixel format for this platform. No need for any
105 // members in this class. All values can also be compile-time constant.
106 template<> class PixelOpBase<uint16_t>
107 {
108 public:
109  explicit PixelOpBase(const SDL_PixelFormat& /*format*/) {}
110 
111  const SDL_PixelFormat& getSDLPixelFormat() const
112  {
113  static SDL_PixelFormat format;
114  format.palette = nullptr;
115  format.BitsPerPixel = 16;
116  format.BytesPerPixel = 2;
117  format.Rloss = 3;
118  format.Gloss = 2;
119  format.Bloss = 3;
120  format.Aloss = 8;
121  format.Rshift = 0;
122  format.Gshift = 5;
123  format.Bshift = 11;
124  format.Ashift = 0;
125  format.Rmask = 0x001F;
126  format.Gmask = 0x07E0;
127  format.Bmask = 0xF800;
128  format.Amask = 0x0000;
129  return format;
130  }
131 
132  inline int getRmask() const { return 0x001F; }
133  inline int getGmask() const { return 0x07E0; }
134  inline int getBmask() const { return 0xF800; }
135  inline int getAmask() const { return 0x0000; }
136  inline int getRshift() const { return 0; }
137  inline int getGshift() const { return 5; }
138  inline int getBshift() const { return 11; }
139  inline int getAshift() const { return 0; }
140  inline int getRloss() const { return 3; }
141  inline int getGloss() const { return 2; }
142  inline int getBloss() const { return 3; }
143  inline int getAloss() const { return 8; }
144 
145  inline uint16_t getBlendMask() const { return 0xF7DE; }
146 
147  static constexpr bool IS_RGB565 = true;
148 };
149 #endif
150 
151 
152 
153 template<typename Pixel> class PixelOperations : public PixelOpBase<Pixel>
154 {
155 public:
171 
172  explicit PixelOperations(const SDL_PixelFormat& format);
173 
176  inline unsigned red(Pixel p) const;
177  inline unsigned green(Pixel p) const;
178  inline unsigned blue(Pixel p) const;
179  inline unsigned alpha(Pixel p) const;
180 
181  // alpha is maximum
182  inline bool isFullyOpaque(Pixel p) const;
183  // alpha is minimum
184  inline bool isFullyTransparent(Pixel p) const;
185 
188  inline unsigned red256(Pixel p) const;
189  inline unsigned green256(Pixel p) const;
190  inline unsigned blue256(Pixel p) const;
191 
194  inline Pixel combine(unsigned r, unsigned g, unsigned b) const;
195  inline Pixel combine256(unsigned r, unsigned g, unsigned b) const;
196 
199  inline unsigned getMaxRed() const;
200  inline unsigned getMaxGreen() const;
201  inline unsigned getMaxBlue() const;
202 
207  template <unsigned w1, unsigned w2>
208  inline Pixel blend(Pixel p1, Pixel p2) const;
209  template <unsigned w1, unsigned w2, unsigned w3>
210  inline Pixel blend(Pixel p1, Pixel p2, Pixel p3) const;
211  template <unsigned w1, unsigned w2, unsigned w3, unsigned w4>
212  inline Pixel blend(Pixel p1, Pixel p2, Pixel p3, Pixel p4) const;
213  template <unsigned w1, unsigned w2, unsigned w3,
214  unsigned w4, unsigned w5, unsigned w6>
215  inline Pixel blend(Pixel p1, Pixel p2, Pixel p3,
216  Pixel p4, Pixel p5, Pixel p6) const;
217 
218  template <unsigned w1, unsigned w2>
219  inline Pixel blend2(const Pixel* p) const;
220  template <unsigned w1, unsigned w2, unsigned w3>
221  inline Pixel blend3(const Pixel* p) const;
222  template <unsigned w1, unsigned w2, unsigned w3, unsigned w4>
223  inline Pixel blend4(const Pixel* p) const;
224  template <unsigned w1, unsigned w2, unsigned w3,
225  unsigned w4, unsigned w5, unsigned w6>
226  inline Pixel blend6(const Pixel* p) const;
227 
236  static inline Pixel multiply(Pixel p, unsigned x);
237 
246  inline Pixel lerp(Pixel p1, Pixel p2, unsigned x) const;
247 
252  inline Pixel alphaBlend(Pixel p1, Pixel p2) const;
253 
254 private:
255  inline Pixel avgDown(Pixel p1, Pixel p2) const;
256  inline Pixel avgUp (Pixel p1, Pixel p2) const;
257 };
258 
259 
260 template <typename Pixel>
261 PixelOperations<Pixel>::PixelOperations(const SDL_PixelFormat& format_)
262  : PixelOpBase<Pixel>(format_)
263 {
264 }
265 
266 template <typename Pixel>
267 inline unsigned PixelOperations<Pixel>::red(Pixel p) const
268 {
269  if (sizeof(Pixel) == 4) {
270  return (p >> getRshift()) & 0xFF;
271  } else {
272  return (p & getRmask()) >> getRshift();
273  }
274 }
275 template <typename Pixel>
276 inline unsigned PixelOperations<Pixel>::green(Pixel p) const
277 {
278  if (sizeof(Pixel) == 4) {
279  return (p >> getGshift()) & 0xFF;
280  } else {
281  return (p & getGmask()) >> getGshift();
282  }
283 }
284 template <typename Pixel>
285 inline unsigned PixelOperations<Pixel>::blue(Pixel p) const
286 {
287  if (sizeof(Pixel) == 4) {
288  return (p >> getBshift()) & 0xFF;
289  } else {
290  return (p & getBmask()) >> getBshift();
291  }
292 }
293 template <typename Pixel>
294 inline unsigned PixelOperations<Pixel>::alpha(Pixel p) const
295 {
296  if (sizeof(Pixel) == 4) {
297  return (p >> getAshift()) & 0xFF;
298  } else {
299  UNREACHABLE; return 0;
300  //return (p & getAmask()) >> getAshift();
301  }
302 }
303 
304 template <typename Pixel>
306 {
307  if (sizeof(Pixel) == 4) {
308  return alpha(p) == 255;
309  } else {
310  return p != 0x0001;
311  }
312 }
313 template <typename Pixel>
315 {
316  if (sizeof(Pixel) == 4) {
317  return alpha(p) == 0;
318  } else {
319  return p == 0x0001;
320  }
321 }
322 
323 template <typename Pixel>
324 inline unsigned PixelOperations<Pixel>::red256(Pixel p) const
325 {
326  if (sizeof(Pixel) == 4) {
327  return (p >> getRshift()) & 0xFF;
328  } else {
329  return ((p >> getRshift()) << getRloss()) & 0xFF;
330  }
331 }
332 template <typename Pixel>
333 inline unsigned PixelOperations<Pixel>::green256(Pixel p) const
334 {
335  if (sizeof(Pixel) == 4) {
336  return (p >> getGshift()) & 0xFF;
337  } else {
338  return ((p >> getGshift()) << getGloss()) & 0xFF;
339  }
340 }
341 template <typename Pixel>
342 inline unsigned PixelOperations<Pixel>::blue256(Pixel p) const
343 {
344  if (sizeof(Pixel) == 4) {
345  return (p >> getBshift()) & 0xFF;
346  } else {
347  return ((p >> getBshift()) << getBloss()) & 0xFF;
348  }
349 }
350 
351 template <typename Pixel>
353  unsigned r, unsigned g, unsigned b) const
354 {
355  return Pixel((r << getRshift()) |
356  (g << getGshift()) |
357  (b << getBshift()));
358 }
359 
360 template <typename Pixel>
362  unsigned r, unsigned g, unsigned b) const
363 {
364  if (sizeof(Pixel) == 4) {
365  return Pixel((r << getRshift()) |
366  (g << getGshift()) |
367  (b << getBshift()));
368  } else {
369  return Pixel(((r >> getRloss()) << getRshift()) |
370  ((g >> getGloss()) << getGshift()) |
371  ((b >> getBloss()) << getBshift()));
372  }
373 }
374 
375 template <typename Pixel>
376 inline unsigned PixelOperations<Pixel>::getMaxRed() const
377 {
378  if (sizeof(Pixel) == 4) {
379  return 255;
380  } else {
381  return 255 >> getRloss();
382  }
383 }
384 template <typename Pixel>
385 inline unsigned PixelOperations<Pixel>::getMaxGreen() const
386 {
387  if (sizeof(Pixel) == 4) {
388  return 255;
389  } else {
390  return 255 >> getGloss();
391  }
392 }
393 template <typename Pixel>
394 inline unsigned PixelOperations<Pixel>::getMaxBlue() const
395 {
396  if (sizeof(Pixel) == 4) {
397  return 255;
398  } else {
399  return 255 >> getBloss();
400  }
401 }
402 
403 template<typename Pixel>
405 {
406  // Average can be calculated as:
407  // floor((x + y) / 2.0) = (x & y) + (x ^ y) / 2
408  // see "Average of Integers" on http://aggregate.org/MAGIC/
409  return (p1 & p2) + (((p1 ^ p2) & getBlendMask()) >> 1);
410 }
411 template<typename Pixel>
412 inline Pixel PixelOperations<Pixel>::avgUp(Pixel p1, Pixel p2) const
413 {
414  // Similar to above, but rounds up
415  // ceil((x + y) / 2.0) = (x | y) - (x ^ y) / 2
416  return (p1 | p2) - (((p1 ^ p2) & getBlendMask()) >> 1);
417 }
418 
419 template<typename Pixel>
420 template<unsigned w1, unsigned w2>
422 {
423  static const unsigned total = w1 + w2;
424  if (w1 == 0) {
425  return p2;
426  } else if (w1 > w2) {
427  return blend<w2, w1>(p2, p1);
428 
429  } else if (w1 == w2) {
430  // <1,1>
431  return avgDown(p1, p2);
432  } else if ((3 * w1) == w2) {
433  // <1,3>
434  Pixel p11 = avgDown(p1, p2);
435  return avgUp(p11, p2);
436  } else if ((7 * w1) == w2) {
437  // <1,7>
438  Pixel p11 = avgDown(p1, p2);
439  Pixel p13 = avgDown(p11, p2);
440  return avgUp(p13, p2);
441  } else if ((5 * w1) == (3 * w2)) {
442  // <3,5> mix rounding up/down to get a more accurate result
443  Pixel p11 = avgUp (p1, p2);
444  Pixel p13 = avgDown(p11, p2);
445  return avgDown(p11, p13);
446 
447  } else if (!Math::ispow2(total)) {
448  // approximate with weights that sum to 256 (or 64)
449  // e.g. approximate <1,2> as <85,171> (or <21,43>)
450  // ww1 = round(256 * w1 / total) ww2 = 256 - ww1
451  constexpr unsigned newTotal = IS_RGB565 ? 64 : 256;
452  constexpr unsigned ww1 = (2 * w1 * newTotal + total) / (2 * total);
453  constexpr unsigned ww2 = 256 - ww1;
454  return blend<ww1, ww2>(p1, p2);
455 
456  } else if (sizeof(Pixel) == 4) {
457  unsigned l2 = Math::log2p1(total) - 1;
458  unsigned c1 = (((p1 & 0x00FF00FF) * w1 +
459  (p2 & 0x00FF00FF) * w2
460  ) >> l2) & 0x00FF00FF;
461  unsigned c2 = (((p1 & 0xFF00FF00) >> l2) * w1 +
462  ((p2 & 0xFF00FF00) >> l2) * w2
463  ) & 0xFF00FF00;
464  return c1 | c2;
465 
466  } else if (IS_RGB565) {
467  if (total > 64) {
468  // reduce to maximum 6-bit
469  // note: DIV64 only exists to work around a
470  // division by zero in dead code
471  constexpr unsigned DIV64 = (total > 64) ? 64 : 1;
472  constexpr unsigned factor = total / DIV64;
473  constexpr unsigned round = factor / 2;
474  constexpr unsigned ww1 = (w1 + round) / factor;
475  constexpr unsigned ww2 = 64 - ww1;
476  return blend<ww1, ww2>(p1, p2);
477  } else {
478  unsigned l2 = Math::log2p1(total) - 1;
479  unsigned c1 = (((unsigned(p1) & 0xF81F) * w1) +
480  ((unsigned(p2) & 0xF81F) * w2)) & (0xF81F << l2);
481  unsigned c2 = (((unsigned(p1) & 0x07E0) * w1) +
482  ((unsigned(p2) & 0x07E0) * w2)) & (0x07E0 << l2);
483  return (c1 | c2) >> l2;
484  }
485 
486  } else {
487  // generic version
488  unsigned r = (red (p1) * w1 + red (p2) * w2) / total;
489  unsigned g = (green(p1) * w1 + green(p2) * w2) / total;
490  unsigned b = (blue (p1) * w1 + blue (p2) * w2) / total;
491  return combine(r, g, b);
492  }
493 }
494 
495 template <typename Pixel>
496 template <unsigned w1, unsigned w2, unsigned w3>
498 {
499  constexpr unsigned total = w1 + w2 + w3;
500  if ((sizeof(Pixel) == 4) && Math::ispow2(total)) {
501  unsigned l2 = Math::log2p1(total) - 1;
502  unsigned c1 = (((p1 & 0x00FF00FF) * w1 +
503  (p2 & 0x00FF00FF) * w2 +
504  (p3 & 0x00FF00FF) * w3) >> l2) & 0x00FF00FF;
505  unsigned c2 = (((p1 & 0xFF00FF00) >> l2) * w1 +
506  ((p2 & 0xFF00FF00) >> l2) * w2 +
507  ((p3 & 0xFF00FF00) >> l2) * w3) & 0xFF00FF00;
508  return c1 | c2;
509  } else {
510  unsigned r = (red (p1) * w1 + red (p2) * w2 + red (p3) * w3) / total;
511  unsigned g = (green(p1) * w1 + green(p2) * w2 + green(p3) * w3) / total;
512  unsigned b = (blue (p1) * w1 + blue (p2) * w2 + blue (p3) * w3) / total;
513  return combine(r, g, b);
514  }
515 }
516 
517 template <typename Pixel>
518 template <unsigned w1, unsigned w2, unsigned w3, unsigned w4>
520  Pixel p1, Pixel p2, Pixel p3, Pixel p4) const
521 {
522  constexpr unsigned total = w1 + w2 + w3 + w4;
523  if ((sizeof(Pixel) == 4) && Math::ispow2(total)) {
524  unsigned l2 = Math::log2p1(total) - 1;
525  unsigned c1 = (((p1 & 0x00FF00FF) * w1 +
526  (p2 & 0x00FF00FF) * w2 +
527  (p3 & 0x00FF00FF) * w3 +
528  (p4 & 0x00FF00FF) * w4) >> l2) & 0x00FF00FF;
529  unsigned c2 = (((p1 & 0xFF00FF00) >> l2) * w1 +
530  ((p2 & 0xFF00FF00) >> l2) * w2 +
531  ((p3 & 0xFF00FF00) >> l2) * w3 +
532  ((p4 & 0xFF00FF00) >> l2) * w4) & 0xFF00FF00;
533  return c1 | c2;
534  } else {
535  unsigned r = (red (p1) * w1 + red (p2) * w2 +
536  red (p3) * w3 + red (p4) * w4) / total;
537  unsigned g = (green(p1) * w1 + green(p2) * w2 +
538  green(p3) * w3 + green(p4) * w4) / total;
539  unsigned b = (blue (p1) * w1 + blue (p2) * w2 +
540  blue (p3) * w3 + blue (p4) * w4) / total;
541  return combine(r, g, b);
542  }
543 }
544 
545 template <typename Pixel>
546 template <unsigned w1, unsigned w2, unsigned w3,
547  unsigned w4, unsigned w5, unsigned w6>
549  Pixel p1, Pixel p2, Pixel p3, Pixel p4, Pixel p5, Pixel p6) const
550 {
551  constexpr unsigned total = w1 + w2 + w3 + w4 + w5 + w6;
552  if ((sizeof(Pixel) == 4) && Math::ispow2(total)) {
553  unsigned l2 = Math::log2p1(total) - 1;
554  unsigned c1 = (((p1 & 0x00FF00FF) * w1 +
555  (p2 & 0x00FF00FF) * w2 +
556  (p3 & 0x00FF00FF) * w3 +
557  (p4 & 0x00FF00FF) * w4 +
558  (p5 & 0x00FF00FF) * w5 +
559  (p6 & 0x00FF00FF) * w6) >> l2) & 0x00FF00FF;
560  unsigned c2 = (((p1 & 0xFF00FF00) >> l2) * w1 +
561  ((p2 & 0xFF00FF00) >> l2) * w2 +
562  ((p3 & 0xFF00FF00) >> l2) * w3 +
563  ((p4 & 0xFF00FF00) >> l2) * w4 +
564  ((p5 & 0xFF00FF00) >> l2) * w5 +
565  ((p6 & 0xFF00FF00) >> l2) * w6) & 0xFF00FF00;
566  return c1 | c2;
567  } else {
568  unsigned r = (red (p1) * w1 + red (p2) * w2 +
569  red (p3) * w3 + red (p4) * w4 +
570  red (p5) * w5 + red (p6) * w6) / total;
571  unsigned g = (green(p1) * w1 + green(p2) * w2 +
572  green(p3) * w3 + green(p4) * w4 +
573  green(p5) * w5 + green(p6) * w6) / total;
574  unsigned b = (blue (p1) * w1 + blue (p2) * w2 +
575  blue (p3) * w3 + blue (p4) * w4 +
576  blue (p5) * w5 + blue (p6) * w6) / total;
577  return combine(r, g, b);
578  }
579 }
580 
581 
582 template <typename Pixel>
583 template <unsigned w1, unsigned w2>
585 {
586  return blend<w1, w2>(p[0], p[1]);
587 }
588 
589 template <typename Pixel>
590 template <unsigned w1, unsigned w2, unsigned w3>
592 {
593  return blend<w1, w2, w3>(p[0], p[1], p[2]);
594 }
595 
596 template <typename Pixel>
597 template <unsigned w1, unsigned w2, unsigned w3, unsigned w4>
599 {
600  return blend<w1, w2, w3, w4>(p[0], p[1], p[2], p[3]);
601 }
602 
603 template <typename Pixel>
604 template <unsigned w1, unsigned w2, unsigned w3,
605  unsigned w4, unsigned w5, unsigned w6>
607 {
608  return blend<w1, w2, w3, w4, w5, w6>(p[0], p[1], p[2], p[3], p[4], p[5]);
609 }
610 
611 template <typename Pixel>
613 {
614  if (sizeof(Pixel) == 4) {
615  return ((((p & 0x00FF00FF) * x) & 0xFF00FF00) >> 8)
616  | ((((p >> 8) & 0x00FF00FF) * x) & 0xFF00FF00);
617  } else {
618  UNREACHABLE; return 0;
619  }
620 }
621 
622 template <typename Pixel>
623 inline Pixel PixelOperations<Pixel>::lerp(Pixel p1, Pixel p2, unsigned x) const
624 {
625  if (sizeof(Pixel) == 4) { // 32 bpp
626  unsigned rb1 = (p1 >> 0) & 0x00FF00FF;
627  unsigned ag1 = (p1 >> 8) & 0x00FF00FF;
628  unsigned rb2 = (p2 >> 0) & 0x00FF00FF;
629  unsigned ag2 = (p2 >> 8) & 0x00FF00FF;
630 
631  // Note: the subtraction for the lower component can 'borrow' from
632  // the higher component. Though in the full calculation this error
633  // magically cancels out.
634  unsigned trb = ((rb2 - rb1) * x) >> 8;
635  unsigned tag = ((ag2 - ag1) * x) >> 0;
636 
637  unsigned rb = ((trb + rb1) << 0) & 0x00FF00FF;
638  unsigned ag = (tag + (ag1 << 8)) & 0xFF00FF00;
639 
640  return rb | ag;
641 
642  } else if (IS_RGB565) {
643  unsigned rb1 = p1 & 0xF81F;
644  unsigned rb2 = p2 & 0xF81F;
645  unsigned g1 = p1 & 0x07E0;
646  unsigned g2 = p2 & 0x07E0;
647 
648  x >>= 2;
649  unsigned trb = ((rb2 - rb1) * x) >> 6;
650  unsigned tg = ((g2 - g1 ) * x) >> 6;
651 
652  unsigned rb = (trb + rb1) & 0xF81F;
653  unsigned g = (tg + g1 ) & 0x07E0;
654 
655  return rb | g;
656 
657  } else {
658  int r1 = red(p1), r2 = red(p2);
659  int g1 = green(p1), g2 = green(p2);
660  int b1 = blue(p1), b2 = blue(p2);
661 
662  // note: '/ 256' is not the same as '>> 8' for signed numbers
663  int r = ((r2 - r1) * x) / 256 + r1;
664  int g = ((g2 - g1) * x) / 256 + g1;
665  int b = ((b2 - b1) * x) / 256 + b1;
666 
667  return combine(r, g, b);
668  }
669 }
670 
671 template <typename Pixel>
673 {
674  if (sizeof(Pixel) == 2) {
675  // TODO keep magic value in sync with OutputSurface::getKeyColor()
676  return (p1 == 0x0001) ? p2 : p1;
677  } else {
678  unsigned a = alpha(p1);
679  // Note: 'a' is [0..255], while lerp() expects [0..256].
680  // We ignore this small error.
681  return lerp(p2, p1, a);
682  }
683 }
684 
685 } // namespace openmsx
686 
687 #endif
KeyCode combine(KeyCode key, KeyCode modifier)
Convenience method to create key combinations (hides ugly casts).
Definition: Keys.hh:231
Pixel getBlendMask() const
Returns a constant that is useful to calculate the average of two pixel values.
mat3 p3(vec3(1, 2, 3), vec3(4, 5, 6), vec3(7, 0, 9))
uint32_t Pixel
PixelOpBase(const SDL_PixelFormat &format_)
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
mat4 p4(vec4(1, 2, 3, 4), vec4(3, 4, 5, 6), vec4(5, 0, 7, 8), vec4(7, 8, 9, 0))
const SDL_PixelFormat & getSDLPixelFormat() const
constexpr T log2p1(T x) noexcept
Returns the number of bits needed to store the value &#39;x&#39;, that is: for x==0 : 0 for x!=0 : 1 + floor(...
Definition: Math.hh:38
PixelOperations(const SDL_PixelFormat &format)
constexpr double round(double x)
Definition: cstd.hh:318
int g
vec3 w3(-1, -2, 2)
const SDL_PixelFormat & getSDLPixelFormat() const
static constexpr bool IS_RGB565
Return true if it&#39;s statically known that the pixelformat has a 5-6-5 format (not specified wihich co...
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:1377
constexpr bool ispow2(T x) noexcept
Is the given number an integral power of two? That is, does it have exactly one 1-bit in binary repre...
Definition: Math.hh:56
void format(SectorAccessibleDisk &disk, bool dos1)
Format the given disk (= a single partition).
PixelOpBase(const SDL_PixelFormat &format_)
vec4 w4(-1, 2, 2, -6)
#define UNREACHABLE
Definition: unreachable.hh:38