diff --git a/include/display/render/context.h b/include/display/render/context.h new file mode 100644 index 0000000..fb347cb --- /dev/null +++ b/include/display/render/context.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define RGB565(R, G, B) \ + ((uint16_t)((((uint16_t)(R) & 0xF8u) << 8) | \ + (((uint16_t)(G) & 0xFCu) << 3) | \ + (((uint16_t)(B) & 0xF8u) >> 3))) + +#define BSWAP16(X) \ + ((uint16_t)((((uint16_t)(X) & 0x00FFu) << 8) | \ + (((uint16_t)(X) & 0xFF00u) >> 8))) + +/* RGB888 -> RGB565 with swapped byte order for ctx->buf */ +#define RGB16(R, G, B) BSWAP16(RGB565((R), (G), (B))) + +typedef struct +{ + uint16_t* buf; + uint16_t width; + uint16_t height; + uint16_t clip_x0; + uint16_t clip_y0; + uint16_t clip_x1; + uint16_t clip_y1; +} render_ctx_t; + +void render_begin(render_ctx_t* ctx, uint16_t* buf, uint16_t width, uint16_t height); +void render_set_clip(render_ctx_t* ctx, uint16_t x, uint16_t y, uint16_t width, uint16_t height); +void render_reset_clip(render_ctx_t* ctx); +void render_clear(render_ctx_t* ctx, uint16_t color); +void render_pixel(render_ctx_t* ctx, int x, int y, uint16_t color); + +#ifdef __cplusplus +} +#endif diff --git a/src/render/context.c b/src/render/context.c new file mode 100644 index 0000000..129dfb9 --- /dev/null +++ b/src/render/context.c @@ -0,0 +1,89 @@ +#include "display/render/context.h" +#include + +static inline bool in_clip(const render_ctx_t* ctx, int x, int y) +{ + return x >= (int)ctx->clip_x0 && + x <= (int)ctx->clip_x1 && + y >= (int)ctx->clip_y0 && + y <= (int)ctx->clip_y1; +} + +void render_begin(render_ctx_t* ctx, uint16_t* buf, uint16_t width, uint16_t height) +{ + ctx->buf = buf; + ctx->width = width; + ctx->height = height; + render_reset_clip(ctx); +} + +void render_set_clip(render_ctx_t* ctx, uint16_t x, uint16_t y, uint16_t width, uint16_t height) +{ + if (ctx->width == 0 || ctx->height == 0 || width == 0 || height == 0) + { + ctx->clip_x0 = 0; + ctx->clip_y0 = 0; + ctx->clip_x1 = 0; + ctx->clip_y1 = 0; + return; + } + + uint32_t x1 = (uint32_t)x + (uint32_t)width - 1u; + uint32_t y1 = (uint32_t)y + (uint32_t)height - 1u; + + if (x >= ctx->width || y >= ctx->height) + { + ctx->clip_x0 = 0; + ctx->clip_y0 = 0; + ctx->clip_x1 = 0; + ctx->clip_y1 = 0; + return; + } + + if (x1 >= ctx->width) + x1 = (uint32_t)ctx->width - 1u; + if (y1 >= ctx->height) + y1 = (uint32_t)ctx->height - 1u; + + ctx->clip_x0 = x; + ctx->clip_y0 = y; + ctx->clip_x1 = (uint16_t)x1; + ctx->clip_y1 = (uint16_t)y1; +} + +void render_reset_clip(render_ctx_t* ctx) +{ + if (ctx->width == 0 || ctx->height == 0) + { + ctx->clip_x0 = 0; + ctx->clip_y0 = 0; + ctx->clip_x1 = 0; + ctx->clip_y1 = 0; + return; + } + + ctx->clip_x0 = 0; + ctx->clip_y0 = 0; + ctx->clip_x1 = (uint16_t)(ctx->width - 1u); + ctx->clip_y1 = (uint16_t)(ctx->height - 1u); +} + +void render_clear(render_ctx_t* ctx, uint16_t color) +{ + size_t total = (size_t)ctx->width * (size_t)ctx->height; + for (size_t i = 0; i < total; ++i) + { + ctx->buf[i] = color; + } +} + +void render_pixel(render_ctx_t* ctx, int x, int y, uint16_t color) +{ + if (x < 0 || y < 0 || x >= (int)ctx->width || y >= (int)ctx->height) + return; + + if (!in_clip(ctx, x, y)) + return; + + ctx->buf[(size_t)y * ctx->width + (size_t)x] = color; +}