1#ifndef PIXELOPERATIONS_HH
2#define PIXELOPERATIONS_HH
19 , blendMask(calcBlendMask())
54 [[nodiscard]]
inline Pixel calcBlendMask()
const
59 return Pixel(~(rBit | gBit | bBit));
71 const Pixel blendMask;
92 [[nodiscard]]
inline unsigned getRloss()
const {
return 0; }
93 [[nodiscard]]
inline unsigned getGloss()
const {
return 0; }
94 [[nodiscard]]
inline unsigned getBloss()
const {
return 0; }
95 [[nodiscard]]
inline unsigned getAloss()
const {
return 0; }
97 [[nodiscard]]
inline unsigned getBlendMask()
const {
return 0xFEFEFEFE; }
117 static PixelFormat format(16,
125 [[nodiscard]]
inline unsigned getRmask()
const {
return 0x001F; }
126 [[nodiscard]]
inline unsigned getGmask()
const {
return 0x07E0; }
127 [[nodiscard]]
inline unsigned getBmask()
const {
return 0xF800; }
128 [[nodiscard]]
inline unsigned getAmask()
const {
return 0x0000; }
129 [[nodiscard]]
inline unsigned getRshift()
const {
return 0; }
130 [[nodiscard]]
inline unsigned getGshift()
const {
return 5; }
131 [[nodiscard]]
inline unsigned getBshift()
const {
return 11; }
132 [[nodiscard]]
inline unsigned getAshift()
const {
return 0; }
133 [[nodiscard]]
inline unsigned getRloss()
const {
return 3; }
134 [[nodiscard]]
inline unsigned getGloss()
const {
return 2; }
135 [[nodiscard]]
inline unsigned getBloss()
const {
return 3; }
136 [[nodiscard]]
inline unsigned getAloss()
const {
return 8; }
138 [[nodiscard]]
inline uint16_t
getBlendMask()
const {
return 0xF7DE; }
187 [[nodiscard]]
inline Pixel combine(
unsigned r,
unsigned g,
unsigned b)
const;
200 template<
unsigned w1,
unsigned w2>
202 template<
unsigned w1,
unsigned w2,
unsigned w3>
204 template<
unsigned w1,
unsigned w2,
unsigned w3,
unsigned w4>
206 template<
unsigned w1,
unsigned w2,
unsigned w3,
207 unsigned w4,
unsigned w5,
unsigned w6>
211 template<
unsigned w1,
unsigned w2>
212 [[nodiscard]]
inline Pixel blend(std::span<const Pixel, 2> p)
const;
213 template<
unsigned w1,
unsigned w2,
unsigned w3>
214 [[nodiscard]]
inline Pixel blend(std::span<const Pixel, 3> p)
const;
215 template<
unsigned w1,
unsigned w2,
unsigned w3,
unsigned w4>
216 [[nodiscard]]
inline Pixel blend(std::span<const Pixel, 4> p)
const;
217 template<
unsigned w1,
unsigned w2,
unsigned w3,
218 unsigned w4,
unsigned w5,
unsigned w6>
219 [[nodiscard]]
inline Pixel blend(std::span<const Pixel, 6> p)
const;
253template<std::
unsigned_
integral Pixel>
259template<std::
unsigned_
integral Pixel>
262 if constexpr (
sizeof(
Pixel) == 4) {
263 return (p >> getRshift()) & 0xFF;
265 return (p & getRmask()) >> getRshift();
268template<std::
unsigned_
integral Pixel>
271 if constexpr (
sizeof(
Pixel) == 4) {
272 return (p >> getGshift()) & 0xFF;
274 return (p & getGmask()) >> getGshift();
277template<std::
unsigned_
integral Pixel>
280 if constexpr (
sizeof(
Pixel) == 4) {
281 return (p >> getBshift()) & 0xFF;
283 return (p & getBmask()) >> getBshift();
286template<std::
unsigned_
integral Pixel>
289 if constexpr (
sizeof(
Pixel) == 4) {
290 return (p >> getAshift()) & 0xFF;
297template<std::
unsigned_
integral Pixel>
300 if constexpr (
sizeof(
Pixel) == 4) {
301 return alpha(p) == 255;
306template<std::
unsigned_
integral Pixel>
309 if constexpr (
sizeof(
Pixel) == 4) {
310 return alpha(p) == 0;
316template<std::
unsigned_
integral Pixel>
319 if constexpr (
sizeof(
Pixel) == 4) {
320 return (p >> getRshift()) & 0xFF;
322 return ((p >> getRshift()) << getRloss()) & 0xFF;
325template<std::
unsigned_
integral Pixel>
328 if constexpr (
sizeof(
Pixel) == 4) {
329 return (p >> getGshift()) & 0xFF;
331 return ((p >> getGshift()) << getGloss()) & 0xFF;
334template<std::
unsigned_
integral Pixel>
337 if constexpr (
sizeof(
Pixel) == 4) {
338 return (p >> getBshift()) & 0xFF;
340 return ((p >> getBshift()) << getBloss()) & 0xFF;
344template<std::
unsigned_
integral Pixel>
346 unsigned r,
unsigned g,
unsigned b)
const
348 return Pixel((r << getRshift()) |
353template<std::
unsigned_
integral Pixel>
355 unsigned r,
unsigned g,
unsigned b)
const
357 if constexpr (
sizeof(
Pixel) == 4) {
358 return Pixel((r << getRshift()) |
362 return Pixel(((r >> getRloss()) << getRshift()) |
363 ((
g >> getGloss()) << getGshift()) |
364 ((b >> getBloss()) << getBshift()));
368template<std::
unsigned_
integral Pixel>
371 if constexpr (
sizeof(
Pixel) == 4) {
374 return 255 >> getRloss();
377template<std::
unsigned_
integral Pixel>
380 if constexpr (
sizeof(
Pixel) == 4) {
383 return 255 >> getGloss();
386template<std::
unsigned_
integral Pixel>
389 if constexpr (
sizeof(
Pixel) == 4) {
392 return 255 >> getBloss();
396template<std::
unsigned_
integral Pixel>
402 return (p1 & p2) + (((p1 ^ p2) & getBlendMask()) >> 1);
404template<std::
unsigned_
integral Pixel>
409 return (p1 | p2) - (((p1 ^ p2) & getBlendMask()) >> 1);
412template<std::
unsigned_
integral Pixel>
413template<
unsigned w1,
unsigned w2>
416 constexpr unsigned total = w1 + w2;
417 if constexpr (w1 == 0) {
419 }
else if constexpr (w1 > w2) {
420 return blend<w2, w1>(p2, p1);
422 }
else if constexpr (w1 == w2) {
424 return avgDown(p1, p2);
425 }
else if constexpr ((3 * w1) == w2) {
427 Pixel p11 = avgDown(p1, p2);
428 return avgUp(p11, p2);
429 }
else if constexpr ((7 * w1) == w2) {
431 Pixel p11 = avgDown(p1, p2);
432 Pixel p13 = avgDown(p11, p2);
433 return avgUp(p13, p2);
434 }
else if constexpr ((5 * w1) == (3 * w2)) {
436 Pixel p11 = avgUp (p1, p2);
437 Pixel p13 = avgDown(p11, p2);
438 return avgDown(p11, p13);
440 }
else if constexpr (!std::has_single_bit(total)) {
444 constexpr unsigned newTotal = IS_RGB565 ? 64 : 256;
445 constexpr unsigned ww1 = (2 * w1 * newTotal + total) / (2 * total);
446 constexpr unsigned ww2 = 256 - ww1;
447 return blend<ww1, ww2>(p1, p2);
449 }
else if constexpr (
sizeof(
Pixel) == 4) {
450 constexpr unsigned l2 = std::bit_width(total) - 1;
451 unsigned c1 = (((p1 & 0x00FF00FF) * w1 +
452 (p2 & 0x00FF00FF) * w2
453 ) >> l2) & 0x00FF00FF;
454 unsigned c2 = (((p1 & 0xFF00FF00) >> l2) * w1 +
455 ((p2 & 0xFF00FF00) >> l2) * w2
459 }
else if constexpr (IS_RGB565) {
460 if constexpr (total > 64) {
464 constexpr unsigned DIV64 = (total > 64) ? 64 : 1;
465 constexpr unsigned factor = total / DIV64;
466 constexpr unsigned round = factor / 2;
467 constexpr unsigned ww1 = (w1 + round) / factor;
468 constexpr unsigned ww2 = 64 - ww1;
469 return blend<ww1, ww2>(p1, p2);
471 unsigned l2 = std::bit_width(total) - 1;
472 unsigned c1 = (((unsigned(p1) & 0xF81F) * w1) +
473 ((unsigned(p2) & 0xF81F) * w2)) & (0xF81F << l2);
474 unsigned c2 = (((unsigned(p1) & 0x07E0) * w1) +
475 ((unsigned(p2) & 0x07E0) * w2)) & (0x07E0 << l2);
476 return (c1 | c2) >> l2;
481 unsigned r = (red (p1) * w1 + red (p2) * w2) / total;
482 unsigned g = (green(p1) * w1 + green(p2) * w2) / total;
483 unsigned b = (blue (p1) * w1 + blue (p2) * w2) / total;
488template<std::
unsigned_
integral Pixel>
489template<
unsigned w1,
unsigned w2,
unsigned w3>
492 constexpr unsigned total = w1 + w2 +
w3;
493 if constexpr ((
sizeof(
Pixel) == 4) && std::has_single_bit(total)) {
494 constexpr unsigned l2 = std::bit_width(total) - 1;
495 unsigned c1 = (((p1 & 0x00FF00FF) * w1 +
496 (p2 & 0x00FF00FF) * w2 +
497 (
p3 & 0x00FF00FF) *
w3) >> l2) & 0x00FF00FF;
498 unsigned c2 = (((p1 & 0xFF00FF00) >> l2) * w1 +
499 ((p2 & 0xFF00FF00) >> l2) * w2 +
500 ((
p3 & 0xFF00FF00) >> l2) *
w3) & 0xFF00FF00;
503 unsigned r = (red (p1) * w1 + red (p2) * w2 + red (
p3) *
w3) / total;
504 unsigned g = (green(p1) * w1 + green(p2) * w2 + green(
p3) *
w3) / total;
505 unsigned b = (blue (p1) * w1 + blue (p2) * w2 + blue (
p3) *
w3) / total;
510template<std::
unsigned_
integral Pixel>
511template<
unsigned w1,
unsigned w2,
unsigned w3,
unsigned w4>
515 constexpr unsigned total = w1 + w2 +
w3 +
w4;
516 if constexpr ((
sizeof(
Pixel) == 4) && std::has_single_bit(total)) {
517 constexpr unsigned l2 = std::bit_width(total) - 1;
518 unsigned c1 = (((p1 & 0x00FF00FF) * w1 +
519 (p2 & 0x00FF00FF) * w2 +
520 (
p3 & 0x00FF00FF) *
w3 +
521 (
p4 & 0x00FF00FF) *
w4) >> l2) & 0x00FF00FF;
522 unsigned c2 = (((p1 & 0xFF00FF00) >> l2) * w1 +
523 ((p2 & 0xFF00FF00) >> l2) * w2 +
524 ((
p3 & 0xFF00FF00) >> l2) *
w3 +
525 ((
p4 & 0xFF00FF00) >> l2) *
w4) & 0xFF00FF00;
528 unsigned r = (red (p1) * w1 + red (p2) * w2 +
529 red (
p3) *
w3 + red (
p4) *
w4) / total;
530 unsigned g = (green(p1) * w1 + green(p2) * w2 +
531 green(
p3) *
w3 + green(
p4) *
w4) / total;
532 unsigned b = (blue (p1) * w1 + blue (p2) * w2 +
533 blue (
p3) *
w3 + blue (
p4) *
w4) / total;
538template<std::
unsigned_
integral Pixel>
539template<
unsigned w1,
unsigned w2,
unsigned w3,
540 unsigned w4,
unsigned w5,
unsigned w6>
544 constexpr unsigned total = w1 + w2 +
w3 +
w4 + w5 + w6;
545 if constexpr ((
sizeof(
Pixel) == 4) && std::has_single_bit(total)) {
546 constexpr unsigned l2 = std::bit_width(total) - 1;
547 unsigned c1 = (((p1 & 0x00FF00FF) * w1 +
548 (p2 & 0x00FF00FF) * w2 +
549 (
p3 & 0x00FF00FF) *
w3 +
550 (
p4 & 0x00FF00FF) *
w4 +
551 (p5 & 0x00FF00FF) * w5 +
552 (p6 & 0x00FF00FF) * w6) >> l2) & 0x00FF00FF;
553 unsigned c2 = (((p1 & 0xFF00FF00) >> l2) * w1 +
554 ((p2 & 0xFF00FF00) >> l2) * w2 +
555 ((
p3 & 0xFF00FF00) >> l2) *
w3 +
556 ((
p4 & 0xFF00FF00) >> l2) *
w4 +
557 ((p5 & 0xFF00FF00) >> l2) * w5 +
558 ((p6 & 0xFF00FF00) >> l2) * w6) & 0xFF00FF00;
561 unsigned r = (red (p1) * w1 + red (p2) * w2 +
563 red (p5) * w5 + red (p6) * w6) / total;
564 unsigned g = (green(p1) * w1 + green(p2) * w2 +
566 green(p5) * w5 + green(p6) * w6) / total;
567 unsigned b = (blue (p1) * w1 + blue (p2) * w2 +
569 blue (p5) * w5 + blue (p6) * w6) / total;
575template<std::
unsigned_
integral Pixel>
576template<
unsigned w1,
unsigned w2>
579 return blend<w1, w2>(p[0], p[1]);
582template<std::
unsigned_
integral Pixel>
583template<
unsigned w1,
unsigned w2,
unsigned w3>
586 return blend<w1, w2, w3>(p[0], p[1], p[2]);
589template<std::
unsigned_
integral Pixel>
590template<
unsigned w1,
unsigned w2,
unsigned w3,
unsigned w4>
593 return blend<w1, w2, w3, w4>(p[0], p[1], p[2], p[3]);
596template<std::
unsigned_
integral Pixel>
597template<
unsigned w1,
unsigned w2,
unsigned w3,
598 unsigned w4,
unsigned w5,
unsigned w6>
601 return blend<w1, w2, w3, w4, w5, w6>(p[0], p[1], p[2], p[3], p[4], p[5]);
604template<std::
unsigned_
integral Pixel>
607 if constexpr (
sizeof(
Pixel) == 4) {
608 return ((((p & 0x00FF00FF) * x) & 0xFF00FF00) >> 8)
609 | ((((p >> 8) & 0x00FF00FF) * x) & 0xFF00FF00);
615template<std::
unsigned_
integral Pixel>
618 if constexpr (
sizeof(
Pixel) == 4) {
619 unsigned rb1 = (p1 >> 0) & 0x00FF00FF;
620 unsigned ag1 = (p1 >> 8) & 0x00FF00FF;
621 unsigned rb2 = (p2 >> 0) & 0x00FF00FF;
622 unsigned ag2 = (p2 >> 8) & 0x00FF00FF;
627 unsigned trb = ((rb2 - rb1) * x) >> 8;
628 unsigned tag = ((ag2 - ag1) * x) >> 0;
630 unsigned rb = ((trb + rb1) << 0) & 0x00FF00FF;
631 unsigned ag = (tag + (ag1 << 8)) & 0xFF00FF00;
635 }
else if constexpr (IS_RGB565) {
636 unsigned rb1 = p1 & 0xF81F;
637 unsigned rb2 = p2 & 0xF81F;
638 unsigned g1 = p1 & 0x07E0;
639 unsigned g2 = p2 & 0x07E0;
642 unsigned trb = ((rb2 - rb1) * x) >> 6;
643 unsigned tg = ((g2 - g1 ) * x) >> 6;
645 unsigned rb = (trb + rb1) & 0xF81F;
646 unsigned g = (tg + g1 ) & 0x07E0;
651 int r1 = red(p1), r2 = red(p2);
652 int g1 = green(p1), g2 = green(p2);
653 int b1 = blue(p1), b2 = blue(p2);
656 auto r = narrow<unsigned>(((r2 - r1) * narrow<int>(x)) / 256 + r1);
657 auto g = narrow<unsigned>(((g2 - g1) * narrow<int>(x)) / 256 + g1);
658 auto b = narrow<unsigned>(((b2 - b1) * narrow<int>(x)) / 256 + b1);
664template<std::
unsigned_
integral Pixel>
667 if constexpr (
sizeof(
Pixel) == 2) {
669 return (p1 == 0x0001) ? p2 : p1;
671 unsigned a = alpha(p1);
674 return lerp(p2, p1, a);
unsigned getGmask() const
unsigned getGshift() const
unsigned getAshift() const
PixelOpBase(const PixelFormat &format_)
unsigned getBmask() const
unsigned getRloss() const
unsigned getBloss() const
unsigned getAloss() const
unsigned getGloss() const
unsigned getAmask() const
const PixelFormat & getPixelFormat() const
unsigned getBshift() const
unsigned getRshift() const
unsigned getRmask() const
unsigned getBlendMask() const
unsigned getAloss() const
unsigned getGloss() const
unsigned getBmask() const
unsigned getRmask() const
unsigned getRloss() const
unsigned getGshift() const
unsigned getBshift() 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...
unsigned getRshift() const
unsigned getAshift() const
unsigned getBloss() const
const PixelFormat & getPixelFormat() const
PixelOpBase(const PixelFormat &format_)
unsigned getGmask() const
Pixel getBlendMask() const
Returns a constant that is useful to calculate the average of two pixel values.
unsigned getAmask() const
Pixel blend(Pixel p1, Pixel p2, Pixel p3, Pixel p4) const
Pixel blend(std::span< const Pixel, 6 > p) const
static Pixel multiply(Pixel p, unsigned x)
Perform a component wise multiplication of a pixel with an 8-bit fractional value: result = (pixel * ...
Pixel blend(std::span< const Pixel, 2 > p) const
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 blend(Pixel p1, Pixel p2) const
Blend the given colors into a single color.
Pixel blend(std::span< const Pixel, 4 > 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
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.
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
Pixel blend(std::span< const Pixel, 3 > 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: