#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
/* ------------------------------------------------------------
* Basic Types
* ------------------------------------------------------------ */
typedef struct {
uint8_t r, g, b, a; /* 0‑255 per channel */
} Color;
typedef struct {
uint32_t width;
uint32_t height;
Color *pixels; /* Row‑major order: pixels[y * width + x] */
} Framebuffer;
typedef struct {
int x;
int y;
} Point;
/* ------------------------------------------------------------
* Framebuffer Management
* ------------------------------------------------------------ */
static inline Framebuffer *fb_create(uint32_t width, uint32_t height, Color clear_color)
{
Framebuffer *fb = (Framebuffer *)malloc(sizeof(Framebuffer));
if (!fb) return NULL;
fb->width = width;
fb->height = height;
fb->pixels = (Color *)malloc(width * height * sizeof(Color));
if (!fb->pixels) {
free(fb);
return NULL;
}
/* Initialise with clear colour */
for (uint32_t i = 0; i < width * height; ++i) {
fb->pixels[i] = clear_color;
}
return fb;
}
static inline void fb_destroy(Framebuffer *fb)
{
if (fb) {
free(fb->pixels);
free(fb);
}
}
static inline void fb_clear(Framebuffer *fb, Color color)
{
if (!fb) return;
for (uint32_t i = 0; i < fb->width * fb->height; ++i) {
fb->pixels[i] = color;
}
}
/* ------------------------------------------------------------
* Pixel Operations
* ------------------------------------------------------------ */
static inline bool fb_set_pixel(Framebuffer *fb, int x, int y, Color color)
{
if (!fb) return false;
if (x < 0 || y < 0 || (uint32_t)x >= fb->width || (uint32_t)y >= fb->height)
return false; /* Out of bounds – silently ignore */
fb->pixels[y * fb->width + x] = color;
return true;
}
/* ------------------------------------------------------------
* Line Drawing – Bresenham (integer only, no anti‑aliasing)
* ------------------------------------------------------------ */
static void draw_line(Framebuffer *fb, Point p0, Point p1, Color color)
{
int x0 = p0.x, y0 = p0.y;
int x1 = p1.x, y1 = p1.y;
int dx = abs(x1 - x0);
int dy = -abs(y1 - y0);
int sx = (x0 < x1) ? 1 : -1;
int sy = (y0 < y1) ? 1 : -1;
int err = dx + dy; /* error value e_xy */
while (true) {
fb_set_pixel(fb, x0, y0, color);
if (x0 == x1 && y0 == y1) break;
int e2 = 2 * err;
if (e2 >= dy) { err += dy; x0 += sx; }
if (e2 <= dx) { err += dx; y0 += sy; }
}
}
/* ------------------------------------------------------------
* Polygon Stroking – draws edges using draw_line
* ------------------------------------------------------------ */
static void draw_polygon(Framebuffer *fb, const Point *pts, size_t count, Color color)
{
if (count < 2) return;
for (size_t i = 0; i < count; ++i) {
Point a = pts[i];
Point b = pts[(i + 1) % count];
draw_line(fb, a, b, color);
}
}
/* ------------------------------------------------------------
* Polygon Fill – simple even‑odd scan‑line algorithm
* ------------------------------------------------------------ */
static void fill_polygon(Framebuffer *fb, const Point *pts, size_t count, Color color)
{
if (count < 3) return; /* Not a polygon */
/* Find vertical bounds */
int min_y = pts[0].y, max_y = pts[0].y;
for (size_t i = 1; i < count; ++i) {
if (pts[i].y < min_y) min_y = pts[i].y;
if (pts[i].y > max_y) max_y = pts[i].y;
}
/* Clamp to framebuffer */
if (min_y < 0) min_y = 0;
if ((uint32_t)max_y >= fb->height) max_y = fb->height - 1;
/* For each scan line, compute intersections with polygon edges */
for (int y = min_y; y <= max_y; ++y) {
/* Collect x intersections */
int intersections[64]; /* Reasonable static limit; can be expanded */
size_t n = 0;
for (size_t i = 0; i < count; ++i) {
Point v1 = pts[i];
Point v2 = pts[(i + 1) % count];
if (v1.y == v2.y) continue; /* Horizontal edge – ignore */
if ((y < v1.y && y < v2.y) || (y > v1.y && y > v2.y))
continue; /* Edge not crossing scan line */
/* Compute intersection X coordinate */
double x = v1.x + (double)(y - v1.y) * (v2.x - v1.x) / (v2.y - v1.y);
if (n < sizeof(intersections)/sizeof(intersections[0]))
intersections[n++] = (int) (x + 0.5); /* Round to nearest pixel */
}
if (n < 2) continue; /* No spans on this line */
/* Sort intersections (simple insertion sort – n is tiny) */
for (size_t i = 1; i < n; ++i) {
int key = intersections[i];
size_t j = i;
while (j > 0 && intersections[j-1] > key) {
intersections[j] = intersections[j-1];
--j;
}
intersections[j] = key;
}
/* Fill between pairs */
for (size_t i = 0; i + 1 < n; i += 2) {
int x_start = intersections[i];
int x_end = intersections[i+1];
if (x_start > x_end) continue;
if (x_start < 0) x_start = 0;
if ((uint32_t)x_end >= fb->width) x_end = fb->width - 1;
for (int x = x_start; x <= x_end; ++x) {
fb_set_pixel(fb, x, y, color);
}
}
}
}
/* ------------------------------------------------------------
* Example usage (commented out – keep library header‑only)
* ------------------------------------------------------------ */
/*
int main(void)
{
Color black = {0,0,0,255};
Color red = {255,0,0,255};
Framebuffer *fb = fb_create(640, 480, black);
if (!fb) return 1;
Point poly[] = {{100,100},{200,80},{250,200},{150,250}};
draw_polygon(fb, poly, 4, red);
fill_polygon(fb, poly, 4, red);
/* At this point you could write fb->pixels to a BMP/PNG file or
blit it to a window using your platform‑specific code. */
fb_destroy(fb);
return 0;
}
*/