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