-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathColor8FramePainter.h
More file actions
150 lines (127 loc) · 6.1 KB
/
Color8FramePainter.h
File metadata and controls
150 lines (127 loc) · 6.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#ifndef _EGFX_COLOR8_FRAME_PAINTER_h
#define _EGFX_COLOR8_FRAME_PAINTER_h
#include "AbstractFramePainter.h"
namespace Egfx
{
/// <summary>
/// A template class for painting 8-bit grayscale framebuffer, providing low-level pixel drawing operations.
/// </summary>
/// <typeparam name="frameWidth">The width of the frame in pixels.</typeparam>
/// <typeparam name="frameHeight">The height of the frame in pixels.</typeparam>
/// <typeparam name="rotated">Whether the frame is rotated (width and height swapped).</typeparam>
template<pixel_t frameWidth, pixel_t frameHeight, bool rotated>
class Color8FramePainter : public AbstractFramePainter<ColorConverter8, frameWidth, frameHeight, rotated>
{
private:
using Base = AbstractFramePainter<ColorConverter8, frameWidth, frameHeight, rotated>;
protected:
using Base::Buffer;
public:
using Base::BufferSize;
using typename Base::color_t;
public:
Color8FramePainter(uint8_t* buffer = nullptr) : Base(buffer) {}
protected:
void PixelRaw(const color_t rawColor, const pixel_t x, const pixel_t y)
{
const size_t offset = (sizeof(color_t) * y * frameWidth) + x;
Buffer[offset] = rawColor;
}
void PixelRawBlend(const color_t rawColor, const pixel_t x, const pixel_t y)
{
const size_t offset = (sizeof(color_t) * y * frameWidth) + x;
const color_t existingColor = Buffer[offset];
Buffer[offset] = Rgb::Color332From332(
MinValue<uint8_t>((Rgb::R3(existingColor) + Rgb::R3(rawColor)) >> 1, uint8_t(7)),
MinValue<uint8_t>((Rgb::G3(existingColor) + Rgb::G3(rawColor)) >> 1, uint8_t(7)),
MinValue<uint8_t>((Rgb::B2(existingColor) + Rgb::B2(rawColor)) >> 1, uint8_t(3)));
}
void PixelRawBlendAlpha(const color_t rawColor, const pixel_t x, const pixel_t y, const uint8_t alpha)
{
const size_t offset = (sizeof(color_t) * y * frameWidth) + x;
const color_t existingColor = Buffer[offset];
// Mix in RGB8 color space.
const uint8_t r = (((uint16_t)Rgb::R(existingColor) * (255 - alpha)) + ((uint16_t)Rgb::R(rawColor) * alpha)) >> 8;
const uint8_t g = (((uint16_t)Rgb::G(existingColor) * (255 - alpha)) + ((uint16_t)Rgb::G(rawColor) * alpha)) >> 8;
const uint8_t b = (((uint16_t)Rgb::B(existingColor) * (255 - alpha)) + ((uint16_t)Rgb::B(rawColor) * alpha)) >> 8;
// Convert back to RGB332.
Buffer[offset] = ((r & 0xE0)) | ((g & 0xE0) >> 3) | ((b & 0xC0) >> 6);
}
void PixelRawBlendAdd(const color_t rawColor, const pixel_t x, const pixel_t y)
{
const size_t offset = (sizeof(color_t) * y * frameWidth) + x;
const color_t existingColor = Buffer[offset];
Buffer[offset] = Rgb::Color332From332(MinValue<uint8_t>(Rgb::R3(existingColor) + Rgb::R3(rawColor), 7),
MinValue<uint8_t>(uint8_t(Rgb::G3(existingColor)) + Rgb::G3(rawColor), 7),
MinValue<uint8_t>(uint8_t(Rgb::B2(existingColor)) + Rgb::B2(rawColor), 3));
}
void PixelRawBlendSubtract(const color_t rawColor, const pixel_t x, const pixel_t y)
{
const size_t offset = (sizeof(color_t) * y * frameWidth) + x;
const color_t existingColor = Buffer[offset];
Buffer[offset] = Rgb::Color332From332(MaxValue<int16_t>(int16_t(Rgb::R3(existingColor)) - Rgb::R3(rawColor), 0),
MaxValue<int16_t>(int16_t(Rgb::G3(existingColor)) - Rgb::G3(rawColor), 0),
MaxValue<int16_t>(int16_t(Rgb::B2(existingColor)) - Rgb::B2(rawColor), 0));
}
void PixelRawBlendMultiply(const color_t rawColor, const pixel_t x, const pixel_t y)
{
const size_t offset = (sizeof(color_t) * y * frameWidth) + x;
const color_t existingColor = Buffer[offset];
Buffer[offset] = Rgb::Color332From332(MinValue<uint8_t>(uint8_t(Rgb::R3(existingColor)) * Rgb::R3(rawColor) / 7, 7),
MinValue<uint8_t>(uint8_t(Rgb::G3(existingColor)) * Rgb::G3(rawColor) / 7, 7),
MinValue<uint8_t>(uint8_t(Rgb::B2(existingColor)) * Rgb::B2(rawColor) / 3, 3));
}
void PixelRawBlendScreen(const color_t rawColor, const pixel_t x, const pixel_t y)
{
const size_t offset = (sizeof(color_t) * y * frameWidth) + x;
const color_t existingColor = Buffer[offset];
Buffer[offset] = Rgb::Color332From332(MinValue<int16_t>(int16_t(Rgb::R3(existingColor)) + Rgb::R3(rawColor) - ((Rgb::R3(existingColor) * Rgb::R3(rawColor)) / 7), 7),
MinValue<int16_t>(int16_t(Rgb::G3(existingColor)) + Rgb::G3(rawColor) - ((Rgb::G3(existingColor) * Rgb::G3(rawColor)) / 7), 7),
MinValue<int16_t>(int16_t(Rgb::B2(existingColor)) + Rgb::B2(rawColor) - ((Rgb::B2(existingColor) * Rgb::B2(rawColor)) / 3), 3));
}
void LineVerticalRaw(const color_t rawColor, const pixel_t x, const pixel_t y1, const pixel_t y2)
{
const int8_t sign = (y2 >= y1) ? 1 : -1;
const size_t lineSize = (sizeof(color_t) * frameWidth) * sign;
size_t offset = (sizeof(color_t) * frameWidth * y1) + (sizeof(color_t) * x);
const size_t offsetEnd = offset + (lineSize * ((pixel_t(sign) * (y2 - y1)) + 1));
for (; offset != offsetEnd; offset += lineSize)
{
Buffer[offset] = rawColor;
}
}
void LineHorizontalRaw(const color_t rawColor, const pixel_t x1, const pixel_t y, const pixel_t x2)
{
const pixel_t xStart = (x2 >= x1) ? x1 : x2;
const pixel_t xEnd = (x2 >= x1) ? x2 : x1;
const size_t offset = (sizeof(color_t) * frameWidth * y) + (sizeof(color_t) * xStart);
memset(&Buffer[offset], rawColor, xEnd - xStart + 1);
}
void RectangleFillRaw(const color_t rawColor, const pixel_t x1, const pixel_t y1, const pixel_t x2, const pixel_t y2)
{
const pixel_t width = x2 - x1 + 1;
const size_t lineSize = sizeof(color_t) * frameWidth;
size_t offset = (sizeof(color_t) * frameWidth * y1) + (sizeof(color_t) * x1);
const size_t offsetEnd = offset + (lineSize * ((y2 - y1) + 1));
for (; offset != offsetEnd; offset += lineSize)
{
memset(&Buffer[offset], rawColor, width);
}
}
void FillRaw(const color_t rawColor)
{
memset(Buffer, rawColor, BufferSize);
}
template<bool inverted, uint8_t Sections>
void ClearRaw(const uint8_t section)
{
static constexpr size_t sectionSize = BufferSize / Sections;
const size_t sectionOffset = sectionSize * section;
if (inverted)
memset(&Buffer[sectionOffset], UINT8_MAX, sectionSize);
else
memset(&Buffer[sectionOffset], 0, sectionSize);
}
};
}
#endif