1 #ifndef PIXELOPERATIONS_HH
2 #define PIXELOPERATIONS_HH
17 , blendMask(calcBlendMask())
52 [[nodiscard]]
inline Pixel calcBlendMask()
const
57 return ~(rBit | gBit | bBit);
69 const Pixel blendMask;
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; }
95 [[nodiscard]]
inline unsigned getBlendMask()
const {
return 0xFEFEFEFE; }
115 static PixelFormat format(16,
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; }
136 [[nodiscard]]
inline uint16_t
getBlendMask()
const {
return 0xF7DE; }
185 [[nodiscard]]
inline Pixel combine(
unsigned r,
unsigned g,
unsigned b)
const;
198 template<
unsigned w1,
unsigned w2>
200 template<
unsigned w1,
unsigned w2,
unsigned w3>
202 template<
unsigned w1,
unsigned w2,
unsigned w3,
unsigned w4>
204 template<
unsigned w1,
unsigned w2,
unsigned w3,
205 unsigned w4,
unsigned w5,
unsigned w6>
209 template<
unsigned w1,
unsigned w2>
211 template<
unsigned w1,
unsigned w2,
unsigned w3>
213 template<
unsigned w1,
unsigned w2,
unsigned w3,
unsigned w4>
215 template<
unsigned w1,
unsigned w2,
unsigned w3,
216 unsigned w4,
unsigned w5,
unsigned w6>
251 template<std::
unsigned_
integral Pixel>
257 template<std::
unsigned_
integral Pixel>
260 if constexpr (
sizeof(
Pixel) == 4) {
261 return (p >> getRshift()) & 0xFF;
263 return (p & getRmask()) >> getRshift();
266 template<std::
unsigned_
integral Pixel>
269 if constexpr (
sizeof(
Pixel) == 4) {
270 return (p >> getGshift()) & 0xFF;
272 return (p & getGmask()) >> getGshift();
275 template<std::
unsigned_
integral Pixel>
278 if constexpr (
sizeof(
Pixel) == 4) {
279 return (p >> getBshift()) & 0xFF;
281 return (p & getBmask()) >> getBshift();
284 template<std::
unsigned_
integral Pixel>
287 if constexpr (
sizeof(
Pixel) == 4) {
288 return (p >> getAshift()) & 0xFF;
295 template<std::
unsigned_
integral Pixel>
298 if constexpr (
sizeof(
Pixel) == 4) {
299 return alpha(p) == 255;
304 template<std::
unsigned_
integral Pixel>
307 if constexpr (
sizeof(
Pixel) == 4) {
308 return alpha(p) == 0;
314 template<std::
unsigned_
integral Pixel>
317 if constexpr (
sizeof(
Pixel) == 4) {
318 return (p >> getRshift()) & 0xFF;
320 return ((p >> getRshift()) << getRloss()) & 0xFF;
323 template<std::
unsigned_
integral Pixel>
326 if constexpr (
sizeof(
Pixel) == 4) {
327 return (p >> getGshift()) & 0xFF;
329 return ((p >> getGshift()) << getGloss()) & 0xFF;
332 template<std::
unsigned_
integral Pixel>
335 if constexpr (
sizeof(
Pixel) == 4) {
336 return (p >> getBshift()) & 0xFF;
338 return ((p >> getBshift()) << getBloss()) & 0xFF;
342 template<std::
unsigned_
integral Pixel>
344 unsigned r,
unsigned g,
unsigned b)
const
346 return Pixel((r << getRshift()) |
351 template<std::
unsigned_
integral Pixel>
353 unsigned r,
unsigned g,
unsigned b)
const
355 if constexpr (
sizeof(
Pixel) == 4) {
356 return Pixel((r << getRshift()) |
360 return Pixel(((r >> getRloss()) << getRshift()) |
361 ((
g >> getGloss()) << getGshift()) |
362 ((b >> getBloss()) << getBshift()));
366 template<std::
unsigned_
integral Pixel>
369 if constexpr (
sizeof(
Pixel) == 4) {
372 return 255 >> getRloss();
375 template<std::
unsigned_
integral Pixel>
378 if constexpr (
sizeof(
Pixel) == 4) {
381 return 255 >> getGloss();
384 template<std::
unsigned_
integral Pixel>
387 if constexpr (
sizeof(
Pixel) == 4) {
390 return 255 >> getBloss();
394 template<std::
unsigned_
integral Pixel>
400 return (p1 & p2) + (((p1 ^ p2) & getBlendMask()) >> 1);
402 template<std::
unsigned_
integral Pixel>
407 return (p1 | p2) - (((p1 ^ p2) & getBlendMask()) >> 1);
410 template<std::
unsigned_
integral Pixel>
411 template<
unsigned w1,
unsigned w2>
414 constexpr
unsigned total = w1 + w2;
415 if constexpr (w1 == 0) {
417 }
else if constexpr (w1 > w2) {
418 return blend<w2, w1>(p2, p1);
420 }
else if constexpr (w1 == w2) {
422 return avgDown(p1, p2);
423 }
else if constexpr ((3 * w1) == w2) {
425 Pixel p11 = avgDown(p1, p2);
426 return avgUp(p11, p2);
427 }
else if constexpr ((7 * w1) == w2) {
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)) {
434 Pixel p11 = avgUp (p1, p2);
435 Pixel p13 = avgDown(p11, p2);
436 return avgDown(p11, p13);
438 }
else if constexpr (!std::has_single_bit(total)) {
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);
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
457 }
else if constexpr (IS_RGB565) {
458 if constexpr (total > 64) {
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);
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;
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;
486 template<std::
unsigned_
integral Pixel>
487 template<
unsigned w1,
unsigned w2,
unsigned w3>
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;
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;
508 template<std::
unsigned_
integral Pixel>
509 template<
unsigned w1,
unsigned w2,
unsigned w3,
unsigned w4>
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;
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;
536 template<std::
unsigned_
integral Pixel>
537 template<
unsigned w1,
unsigned w2,
unsigned w3,
538 unsigned w4,
unsigned w5,
unsigned w6>
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;
559 unsigned r = (red (p1) * w1 + red (p2) * w2 +
561 red (p5) * w5 + red (p6) * w6) / total;
562 unsigned g = (green(p1) * w1 + green(p2) * w2 +
564 green(p5) * w5 + green(p6) * w6) / total;
565 unsigned b = (blue (p1) * w1 + blue (p2) * w2 +
567 blue (p5) * w5 + blue (p6) * w6) / total;
573 template<std::
unsigned_
integral Pixel>
574 template<
unsigned w1,
unsigned w2>
577 return blend<w1, w2>(p[0], p[1]);
580 template<std::
unsigned_
integral Pixel>
581 template<
unsigned w1,
unsigned w2,
unsigned w3>
584 return blend<w1, w2, w3>(p[0], p[1], p[2]);
587 template<std::
unsigned_
integral Pixel>
588 template<
unsigned w1,
unsigned w2,
unsigned w3,
unsigned w4>
591 return blend<w1, w2, w3, w4>(p[0], p[1], p[2], p[3]);
594 template<std::
unsigned_
integral Pixel>
595 template<
unsigned w1,
unsigned w2,
unsigned w3,
596 unsigned w4,
unsigned w5,
unsigned w6>
599 return blend<w1, w2, w3, w4, w5, w6>(p[0], p[1], p[2], p[3], p[4], p[5]);
602 template<std::
unsigned_
integral Pixel>
605 if constexpr (
sizeof(
Pixel) == 4) {
606 return ((((p & 0x00FF00FF) *
x) & 0xFF00FF00) >> 8)
607 | ((((p >> 8) & 0x00FF00FF) *
x) & 0xFF00FF00);
613 template<std::
unsigned_
integral Pixel>
616 if constexpr (
sizeof(
Pixel) == 4) {
617 unsigned rb1 = (p1 >> 0) & 0x00FF00FF;
618 unsigned ag1 = (p1 >> 8) & 0x00FF00FF;
619 unsigned rb2 = (p2 >> 0) & 0x00FF00FF;
620 unsigned ag2 = (p2 >> 8) & 0x00FF00FF;
625 unsigned trb = ((rb2 - rb1) *
x) >> 8;
626 unsigned tag = ((ag2 - ag1) *
x) >> 0;
628 unsigned rb = ((trb + rb1) << 0) & 0x00FF00FF;
629 unsigned ag = (tag + (ag1 << 8)) & 0xFF00FF00;
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;
640 unsigned trb = ((rb2 - rb1) *
x) >> 6;
641 unsigned tg = ((g2 - g1 ) *
x) >> 6;
643 unsigned rb = (trb + rb1) & 0xF81F;
644 unsigned g = (tg + g1 ) & 0x07E0;
649 int r1 = red(p1), r2 = red(p2);
650 int g1 = green(p1), g2 = green(p2);
651 int b1 = blue(p1), b2 = blue(p2);
654 int r = ((r2 - r1) *
x) / 256 + r1;
655 int g = ((g2 - g1) *
x) / 256 + g1;
656 int b = ((b2 - b1) *
x) / 256 + b1;
662 template<std::
unsigned_
integral Pixel>
665 if constexpr (
sizeof(
Pixel) == 2) {
667 return (p1 == 0x0001) ? p2 : p1;
669 unsigned a = alpha(p1);
672 return lerp(p2, p1, a);
PixelOpBase(const PixelFormat &format_)
const PixelFormat & getPixelFormat() const
unsigned getBlendMask() 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))
KeyCode combine(KeyCode key, KeyCode modifier)
Convenience method to create key combinations (hides ugly casts).
This file implemented 3 utility functions:
constexpr KeyMatrixPosition x
Keyboard bindings.