Software Rendering Utilities (Lines & Polygons)
A small, self‑contained C99 library that provides a framebuffer abstraction and basic software rendering primitives
c (c99)
2025-12-27
AI Generated
c99
software-rendering
lines
polygons
graphics
Code
#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;}*/
Comments
No comments yet. Be the first to comment!
Please login to leave a comment.