8#include "TinyGPU/Font/IFont.h"
9#include "TinyGPU/Surface/ISurface.h"
10#include "TinyGPU/Font/LinePrinter.h"
15
16
17
18
19
20
21
22
23
24template <
typename PixelT>
39 return resize(width_, height_);
51 void setPixel(size_t x, size_t y, PixelT color)
override = 0;
54 PixelT
getPixel(size_t x, size_t y)
const override = 0;
69 bool resize(size_t newWidth, size_t newHeight)
override {
72 return resizeBuffer(newWidth, newHeight);
85 void clear(PixelT color = PixelT())
override {
86 for (size_t y = 0; y < height_; ++y) {
87 for (size_t x = 0; x < width_; ++x) {
88 setPixel(x, y, color);
95 if (dx == 0 && dy == 0)
return;
96 Vector<PixelT> newBuffer(width_ * height_);
97 for (size_t y = 0; y < height_; ++y) {
98 for (size_t x = 0; x < width_; ++x) {
99 int srcX = (
int)x + dx;
100 int srcY = (
int)y + dy;
101 PixelT color = (srcX >= 0 && srcX < (
int)width_ && srcY >= 0 &&
103 ? getPixel(srcX, srcY)
105 newBuffer[y * width_ + x] = color;
109 for (size_t i = 0; i < newBuffer.size(); ++i) {
110 setPixel(i % width_, i / width_, newBuffer[i]);
115 void drawLine(size_t x0, size_t y0, size_t x1, size_t y1,
116 PixelT color)
override {
117 int dx = std::abs((
int)x1 - (
int)x0), sx = x0 < x1 ? 1 : -1;
118 int dy = -std::abs((
int)y1 - (
int)y0), sy = y0 < y1 ? 1 : -1;
119 int err = dx + dy, e2;
121 setPixelClipped(x0, y0, color);
122 if (x0 == x1 && y0 == y1)
break;
136 void drawRect(size_t x, size_t y, size_t w, size_t h, PixelT color)
override {
137 if (w == 0 || h == 0)
return;
138 size_t x1 = x + w - 1, y1 = y + h - 1;
139 drawLine(x, y, x1, y, color);
140 drawLine(x, y1, x1, y1, color);
141 drawLine(x, y, x, y1, color);
142 drawLine(x1, y, x1, y1, color);
151 void fillRect(size_t x, size_t y, size_t w, size_t h, PixelT color)
override {
152 if (w == 0 || h == 0)
return;
153 size_t endX = std::min(x + w, width_);
154 size_t endY = std::min(y + h, height_);
155 if (!clipStack_.empty()) {
156 const ClipRect& clip = clipStack_.back();
157 x = std::max(x, clip.x);
158 y = std::max(y, clip.y);
159 endX = std::min(endX, clip.x + clip.w);
160 endY = std::min(endY, clip.y + clip.h);
162 for (size_t yy = y; yy < endY; ++yy) {
163 for (size_t xx = x; xx < endX; ++xx) {
164 setPixel(xx, yy, color);
170 void drawCircle(size_t x, size_t y, size_t r, PixelT color)
override {
171 int offsetX = r, offsetY = 0, decision = 1 - (
int)offsetX;
172 while (offsetX >= offsetY) {
173 setPixelClipped(x + offsetX, y + offsetY, color);
174 setPixelClipped(x + offsetY, y + offsetX, color);
175 setPixelClipped(x - offsetY, y + offsetX, color);
176 setPixelClipped(x - offsetX, y + offsetY, color);
177 setPixelClipped(x - offsetX, y - offsetY, color);
178 setPixelClipped(x - offsetY, y - offsetX, color);
179 setPixelClipped(x + offsetY, y - offsetX, color);
180 setPixelClipped(x + offsetX, y - offsetY, color);
183 decision += 2 * offsetY + 1;
186 decision += 2 * (offsetY - offsetX) + 1;
192 void fillCircle(size_t x, size_t y, size_t r, PixelT color)
override {
193 int offsetX = r, offsetY = 0, decision = 1 - (
int)offsetX;
194 while (offsetX >= offsetY) {
195 drawHorizontalLineClipped(x - offsetX, x + offsetX, y + offsetY, color);
196 drawHorizontalLineClipped(x - offsetX, x + offsetX, y - offsetY, color);
197 drawHorizontalLineClipped(x - offsetY, x + offsetY, y + offsetX, color);
198 drawHorizontalLineClipped(x - offsetY, x + offsetY, y - offsetX, color);
201 decision += 2 * offsetY + 1;
204 decision += 2 * (offsetY - offsetX) + 1;
210 void drawSprite(size_t x, size_t y,
const ISurface<PixelT>& sprite,
211 PixelT invisibleColor = PixelT())
override {
212 for (size_t spriteY = 0; spriteY < sprite.height(); ++spriteY) {
213 for (size_t spriteX = 0; spriteX < sprite.width(); ++spriteX) {
214 PixelT color = sprite.getPixel(spriteX, spriteY);
215 if (color != invisibleColor) {
216 setPixelClipped(x + spriteX, y + spriteY, color);
224 PixelT clearColor = PixelT())
override {
225 for (size_t spriteY = 0; spriteY < sprite.height(); ++spriteY) {
226 for (size_t spriteX = 0; spriteX < sprite.width(); ++spriteX) {
227 setPixelClipped(x + spriteX, y + spriteY, clearColor);
233 void copySprite(size_t x, size_t y,
const ISurface<PixelT>& sprite)
override {
234 for (size_t spriteY = 0; spriteY < sprite.height(); ++spriteY) {
235 for (size_t spriteX = 0; spriteX < sprite.width(); ++spriteX) {
236 size_t framebufferX = x + spriteX;
237 size_t framebufferY = y + spriteY;
238 PixelT color = (framebufferX < width_ && framebufferY < height_)
239 ? getPixel(framebufferX, framebufferY)
241 const_cast<ISurface<PixelT>&>(sprite).setPixel(spriteX, spriteY, color);
248 void drawText(int16_t x, int16_t y,
const char* text, PixelT foreground,
249 PixelT background = PixelT(),
bool opaque =
false,
250 uint8_t scale = 1, uint8_t spacing = 1,
251 uint8_t lineSpacing = 1)
override {
252 font_->drawText(*
this, x, y, text, foreground, background, opaque, scale,
253 spacing, lineSpacing);
265 return x < width_ && y < height_;
270 if (isInBounds(x, y) && isClipVisible(x, y)) setPixel(x, y, color);
275 if (y < 0 || (size_t)y >= height_)
return;
276 int startX = std::max(0, std::min(x0, x1));
277 int endX = std::min((
int)width_ - 1, std::max(x0, x1));
278 if (!clipStack_.empty()) {
279 const ClipRect& clip = clipStack_.back();
280 if ((size_t)y < clip.y || (size_t)y >= clip.y + clip.h)
return;
281 startX = std::max(startX,
static_cast<
int>(clip.x));
282 endX = std::min(endX,
static_cast<
int>(clip.x + clip.w) - 1);
284 if (startX > endX)
return;
285 for (
int x = startX; x <= endX; ++x) setPixel(x, y, color);
289 return isInBounds(x, y) && isClipVisible(x, y);
296 ClipRect rect{x, y, w, h};
297 if (!clipStack_.empty()) rect = intersect(rect, clipStack_.back());
298 clipStack_.push_back(rect);
303 if (!clipStack_.empty()) clipStack_.pop_back();
308 if (clipStack_.empty())
return true;
309 const ClipRect& clip = clipStack_.back();
310 return x >= clip.x && y >= clip.y && x < clip.x + clip.w && y < clip.y + clip.h;
328 static ClipRect intersect(
const ClipRect& a,
const ClipRect& b) {
329 const size_t x0 = std::max(a.x, b.x);
330 const size_t y0 = std::max(a.y, b.y);
331 const size_t x1 = std::min(a.x + a.w, b.x + b.w);
332 const size_t y1 = std::min(a.y + a.h, b.y + b.h);
333 if (x1 <= x0 || y1 <= y0)
return ClipRect{x0, y0, 0, 0};
334 return ClipRect{x0, y0, x1 - x0, y1 - y0};
337 std::vector<ClipRect> clipStack_;
Font rendering interface for TinyGPU-compatible framebuffers.
Definition: IFont.h:19
Helper for printing wrapped lines of text onto a TinyGPU target.
Definition: LinePrinter.h:17
Base class for 2D surfaces with drawing and text rendering support.
Definition: SurfaceBase.h:25
void pushClipRect(size_t x, size_t y, size_t w, size_t h) override
Definition: SurfaceBase.h:295
void drawLine(size_t x0, size_t y0, size_t x1, size_t y1, PixelT color) override
Draw a line from (x0, y0) to (x1, y1) with the given color.
Definition: SurfaceBase.h:115
void fillRect(size_t x, size_t y, size_t w, size_t h, PixelT color) override
Definition: SurfaceBase.h:151
void setPixelClipped(size_t x, size_t y, PixelT color)
Definition: SurfaceBase.h:269
void clearSprite(size_t x, size_t y, ISurface< PixelT > &sprite, PixelT clearColor=PixelT()) override
Clear the region covered by a sprite at (x, y) to clearColor.
Definition: SurfaceBase.h:223
PixelT getPixel(size_t x, size_t y) const override=0
Abstract method: get the pixel color at (x, y).
IFont< PixelT > * font_
Definition: SurfaceBase.h:316
void drawSprite(size_t x, size_t y, const ISurface< PixelT > &sprite, PixelT invisibleColor=PixelT()) override
Draw a sprite at (x, y), skipping pixels matching invisibleColor.
Definition: SurfaceBase.h:210
void drawCircle(size_t x, size_t y, size_t r, PixelT color) override
Draw a circle outline centered at (x, y) with radius r and color.
Definition: SurfaceBase.h:170
void setFont(IFont< PixelT > &font)
Set the font for text rendering.
Definition: SurfaceBase.h:57
bool contains(size_t x, size_t y) override
Checks if the given coordinates are within the surface bounds.
Definition: SurfaceBase.h:288
size_t width_
Definition: SurfaceBase.h:314
IFont< PixelT > & font() override
Get the current font (mutable).
Definition: SurfaceBase.h:63
bool begin()
Initializes the surface by resizing it to the current dimensions.
Definition: SurfaceBase.h:38
size_t height_
Definition: SurfaceBase.h:315
const IFont< PixelT > & font() const
Get the current font (const).
Definition: SurfaceBase.h:66
void popClipRect() override
See ISurface::popClipRect().
Definition: SurfaceBase.h:302
void drawRect(size_t x, size_t y, size_t w, size_t h, PixelT color) override
Draw a rectangle outline at (x, y) with width w, height h, and color.
Definition: SurfaceBase.h:136
size_t height() const override
Get the height of the surface.
Definition: SurfaceBase.h:79
SurfaceBase(size_t width, size_t height, IFont< PixelT > &font)
Construct with width, height, and font.
Definition: SurfaceBase.h:31
bool isClipVisible(size_t x, size_t y) const override
See ISurface::isClipVisible().
Definition: SurfaceBase.h:307
LinePrinter< PixelT > & linePrinter()
Get the line printer for this surface.
Definition: SurfaceBase.h:257
void clear(PixelT color=PixelT()) override
Clears the framebuffer with a single color.
Definition: SurfaceBase.h:85
void drawText(int16_t x, int16_t y, const char *text, PixelT foreground, PixelT background=PixelT(), bool opaque=false, uint8_t scale=1, uint8_t spacing=1, uint8_t lineSpacing=1) override
Definition: SurfaceBase.h:248
void setPixel(size_t x, size_t y, PixelT color) override=0
Abstract method: set a pixel at (x, y) to the specified color.
void fillCircle(size_t x, size_t y, size_t r, PixelT color) override
Fill a circle centered at (x, y) with radius r and color.
Definition: SurfaceBase.h:192
void scroll(int dx, int dy)
Scroll the surface content by (dx, dy) pixels.
Definition: SurfaceBase.h:94
void end()
Clears the surface and releases any allocated resources.
Definition: SurfaceBase.h:43
virtual bool resizeBuffer(size_t, size_t)=0
SurfaceBase()=default
Default constructor.
size_t width() const override
Get the width of the surface.
Definition: SurfaceBase.h:76
LinePrinter< PixelT > linePrinter_
Definition: SurfaceBase.h:317
~SurfaceBase() override=default
Virtual destructor.
bool resize(size_t newWidth, size_t newHeight) override
Resize the surface to new dimensions.
Definition: SurfaceBase.h:69
void copySprite(size_t x, size_t y, const ISurface< PixelT > &sprite) override
Copy the framebuffer region at (x, y) into the sprite.
Definition: SurfaceBase.h:233
void drawHorizontalLineClipped(int x0, int x1, int y, PixelT color)
Definition: SurfaceBase.h:274
bool isInBounds(size_t x, size_t y) const
Returns true if (x, y) is within the surface bounds.
Definition: SurfaceBase.h:264
Definition: DSIBusESP32.h:19