-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAbstractFramePainter.h
More file actions
182 lines (160 loc) · 5.31 KB
/
AbstractFramePainter.h
File metadata and controls
182 lines (160 loc) · 5.31 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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#ifndef _EGFX_ABSTRACT_FRAME_PAINTER_h
#define _EGFX_ABSTRACT_FRAME_PAINTER_h
#include "../Model/ColorConverter.h"
#include "../Model/IFrameBuffer.h"
#include <IntegerSignal.h>
namespace Egfx
{
/// <summary>
/// Abstract base class for rendering graphics primitives to a frame buffer with configurable color conversion, dimensions, and rotation.
/// </summary>
/// <typeparam name="ColorConverter">The color converter type that defines color representation, bit depth, and conversion from RGB.</typeparam>
/// <typeparam name="frameWidth">The physical width of the frame buffer in pixels.</typeparam>
/// <typeparam name="frameHeight">The physical height of the frame buffer in pixels.</typeparam>
/// <typeparam name="rotated">If true, the logical frame dimensions are rotated 90 degrees relative to physical dimensions.</typeparam>
template<typename ColorConverter, uint16_t frameWidth, uint16_t frameHeight, bool rotated>
class AbstractFramePainter : public IFrameBuffer
{
private:
enum class OutcodeEnum : uint8_t
{
OUT_LEFT = 1,
OUT_RIGHT = 2,
OUT_BOTTOM = 4,
OUT_TOP = 8
};
public:
// Physical screen dimensions
static constexpr uint16_t PhysicalWidth = frameWidth;
static constexpr uint16_t PhysicalHeight = frameHeight;
static constexpr size_t BufferSize = ColorConverter::BufferSize(frameWidth, frameHeight);
// Logical dimensions (taking rotation into account)
static constexpr uint16_t FrameWidth = rotated ? frameHeight : frameWidth;
static constexpr uint16_t FrameHeight = rotated ? frameWidth : frameHeight;
public:
static constexpr uint8_t ColorDepth = ColorConverter::ColorDepth;
static constexpr bool Monochrome = ColorConverter::Monochrome;
using color_t = typename ColorConverter::color_t;
protected:
uint8_t* Buffer;
public:
AbstractFramePainter(uint8_t* buffer = nullptr)
: IFrameBuffer()
, Buffer(buffer)
{
}
static constexpr color_t GetRawColor(const rgb_color_t color)
{
return ColorConverter::GetRawColor(color);
}
protected:
/// <summary>
/// Fixed-point scale used by line and triangle rendering.
/// </summary>
static constexpr uint8_t BRESENHAM_SCALE = 8;
// Fixed-point rounding helper: add half-unit for the current Bresenham scale, then arithmetic right-shift.
static constexpr int16_t FP_ROUND_HALF = SignedLeftShift<int16_t>(1, BRESENHAM_SCALE - 1);
/// <summary>
/// Rounds a 32-bit fixed-point value to the nearest integer using a signed right shift.
/// </summary>
inline constexpr pixel_t FixedRoundToInt(const int32_t fx)
{
return SignedRightShift(fx + FP_ROUND_HALF, BRESENHAM_SCALE);
}
/// <summary>
/// Converts an integer pixel coordinate to fixed-point representation.
/// </summary>
inline constexpr int32_t IntToFixed(const pixel_t x)
{
return SignedLeftShift<int32_t>(x, BRESENHAM_SCALE);
}
protected:
bool ClipRectangle(pixel_point_t& topLeft, pixel_point_t& bottomRight) const
{
if ((topLeft.x < 0 && bottomRight.x < 0)
|| (topLeft.y < 0 && bottomRight.y < 0)
|| (topLeft.x >= FrameWidth && bottomRight.x >= FrameWidth)
|| (topLeft.y >= FrameHeight && bottomRight.y >= FrameHeight)
|| (topLeft.x > bottomRight.x || topLeft.y > bottomRight.y))
{
return false; // Invalid rectangle
}
topLeft.x = LimitValue<pixel_t>(topLeft.x, 0, FrameWidth - 1);
topLeft.y = LimitValue<pixel_t>(topLeft.y, 0, FrameHeight - 1);
bottomRight.x = LimitValue<pixel_t>(bottomRight.x, 0, FrameWidth - 1);
bottomRight.y = LimitValue<pixel_t>(bottomRight.y, 0, FrameHeight - 1);
return true;
}
bool ClipLine(pixel_point_t& p0, pixel_point_t& p1) const
{
pixel_t x0 = p0.x, y0 = p0.y, x1 = p1.x, y1 = p1.y;
uint8_t outcode0 = ComputeOutCode(x0, y0);
uint8_t outcode1 = ComputeOutCode(x1, y1);
pixel_t x = 0;
pixel_t y = 0;
while (true)
{
if (!(outcode0 | outcode1))
{
p0 = { x0 , y0 };
p1 = { x1 , y1 };
return true;
}
else if (outcode0 & outcode1)
{
return false;
}
else
{
uint8_t outcodeOut = outcode0 ? outcode0 : outcode1;
x = 0;
y = 0;
if (outcodeOut & (uint8_t)OutcodeEnum::OUT_TOP)
{
if (y1 == y0) return false;
x = x0 + int32_t(x1 - x0) * (0 - y0) / (y1 - y0);
y = 0;
}
else if (outcodeOut & (uint8_t)OutcodeEnum::OUT_BOTTOM)
{
if (y1 == y0) return false;
x = x0 + int32_t(x1 - x0) * (FrameHeight - 1 - y0) / (y1 - y0);
y = FrameHeight - 1;
}
else if (outcodeOut & (uint8_t)OutcodeEnum::OUT_RIGHT)
{
if (x1 == x0) return false;
y = y0 + int32_t(y1 - y0) * (FrameWidth - 1 - x0) / (x1 - x0);
x = FrameWidth - 1;
}
else
{
if (x1 == x0) return false;
y = y0 + int32_t(y1 - y0) * (0 - x0) / (x1 - x0);
x = 0;
}
if (outcodeOut == outcode0)
{
x0 = x; y0 = y;
outcode0 = ComputeOutCode(x0, y0);
}
else
{
x1 = x; y1 = y;
outcode1 = ComputeOutCode(x1, y1);
}
}
}
}
uint8_t ComputeOutCode(const pixel_t x, const pixel_t y) const
{
uint8_t code = 0;
if (x < 0) code |= (uint8_t)OutcodeEnum::OUT_LEFT;
else if (x >= FrameWidth) code |= (uint8_t)OutcodeEnum::OUT_RIGHT;
if (y < 0) code |= (uint8_t)OutcodeEnum::OUT_TOP;
else if (y >= FrameHeight) code |= (uint8_t)OutcodeEnum::OUT_BOTTOM;
return code;
}
};
}
#endif