-
Notifications
You must be signed in to change notification settings - Fork 2
/
basegraphics.h
146 lines (125 loc) · 4.29 KB
/
basegraphics.h
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
#pragma once
using namespace std;
// BaseGraphics
//
// A class that can do all the basic drawing functions (pixel, line, circle, etc) of the ILEDGraphics
// interface to its own internal buffer of pixels. It manipulates the buffer only through SetPixel
#include <vector>
#include "pixeltypes.h" // Assuming this defines the CRGB structure
#include "interfaces.h"
class BaseGraphics : public ILEDGraphics
{
protected:
uint32_t _width;
uint32_t _height;
vector<CRGB> _pixels;
virtual inline __attribute__((always_inline)) uint32_t _index(uint32_t x, uint32_t y) const
{
return y * _width + x;
}
public:
explicit BaseGraphics(uint32_t width, uint32_t height)
: _width(width), _height(height), _pixels(width * height)
{
}
// ICanvas methods
uint32_t Width() const override { return _width; }
uint32_t Height() const override { return _height; }
const vector<CRGB>& GetPixels() const override
{
return _pixels;
}
void SetPixel(uint32_t x, uint32_t y, const CRGB& color) override
{
if (x < _width && y < _height)
_pixels[_index(x, y)] = color;
}
CRGB GetPixel(uint32_t x, uint32_t y) const override
{
if (x < _width && y < _height)
return _pixels[_index(x, y)];
return CRGB(0, 0, 0); // Default to black for out-of-bounds
}
void Clear(const CRGB& color = CRGB::Black) override
{
FillRectangle(0, 0, _width, _height, color);
}
void FillRectangle(uint32_t x, uint32_t y, uint32_t width, uint32_t height, const CRGB& color) override
{
for (int j = y; j < y + height; ++j)
for (int i = x; i < x + width; ++i)
SetPixel(i, j, color);
}
void DrawLine(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, const CRGB& color) override
{
int32_t dx = abs((int32_t)x2 - (int32_t)x1), dy = abs((int32_t)y2 - (int32_t)y1);
int32_t sx = (x1 < x2) ? 1 : -1, sy = (y1 < y2) ? 1 : -1;
int32_t err = dx - dy;
while (true)
{
SetPixel(x1, y1, color);
if (x1 == x2 && y1 == y2) break;
int e2 = 2 * err;
if (e2 > -dy)
{
err -= dy;
x1 += sx;
}
if (e2 < dx)
{
err += dx;
y1 += sy;
}
}
}
void DrawCircle(uint32_t x, uint32_t y, uint32_t radius, const CRGB& color) override
{
uint32_t cx = 0, cy = radius;
int32_t d = 1 - radius;
while (cy >= cx)
{
SetPixel(x + cx, y + cy, color);
SetPixel(x - cx, y + cy, color);
SetPixel(x + cx, y - cy, color);
SetPixel(x - cx, y - cy, color);
SetPixel(x + cy, y + cx, color);
SetPixel(x - cy, y + cx, color);
SetPixel(x + cy, y - cx, color);
SetPixel(x - cy, y - cx, color);
++cx;
if (d < 0)
{
d += 2 * cx + 1;
}
else
{
--cy;
d += 2 * (cx - cy) + 1;
}
}
}
void FillCircle(uint32_t x, uint32_t y, uint32_t radius, const CRGB& color) override
{
// Fill within the bounding box, but only those pixels within radius of the center
for (int32_t cy = -radius; cy <= radius; ++cy)
for (int32_t cx = -radius; cx <= radius; ++cx)
if (cx * cx + cy * cy <= radius * radius)
SetPixel(x + cx, y + cy, color);
}
void DrawRectangle(uint32_t x, uint32_t y, uint32_t width, uint32_t height, const CRGB& color) override
{
DrawLine(x, y, x + width - 1, y, color); // Top
DrawLine(x, y, x, y + height - 1, color); // Left
DrawLine(x + width - 1, y, x + width - 1, y + height - 1, color); // Right
DrawLine(x, y + height - 1, x + width - 1, y + height - 1, color); // Bottom
}
void FadeFrameBy(uint8_t dimAmount) override
{
for (auto& pixel : _pixels)
{
pixel.r = scale8(pixel.r, 255-dimAmount);
pixel.g = scale8(pixel.g, 255-dimAmount);
pixel.b = scale8(pixel.b, 255-dimAmount);
}
}
};