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