#include #include #include #define SIZE 256 #define SCALE ((double)SIZE / 1024.0) typedef struct { int x, y; } XY; static XY points[] = { {50, 850}, {50, 450}, {550, 250}, {850, 50}, {950, 350}, {650, 550}, {850, 850}, {550, 950}, {450, 850}, {50, 850}, {0, 0}, {100, 900}, {100, 500}, {600, 300}, {900, 100}, {1000, 400}, {700, 600}, {900, 900}, {600, 1000}, {500, 900}, {100, 900}, {0, 0}, {0, 0} }; /* Interpolate between two points. */ static double Interpolate(double a, double b, double t) { return a + (b - a) * t; } int main(int argc, char **argv) { unsigned char *image = calloc(SIZE * SIZE, 1); int *range = malloc(SIZE * 2 * sizeof(int)); int x, y, p = 0, t, shape_index = 0; double ft; if( image == NULL ) return printf("Out of memory\n"); while( points[p].x != 0 ) { /* Collect horizontal ranges for each scanline. This allows us to draw filled shapes one scanline at a time, and the shapes can be both convex and concave as long as each scanline is continuous. We can enforce the continuous requirement by tweaking our shapes, saving us the complexity of having to write a more featureful rasterizer. */ memset(range, 0, SIZE * 2 * sizeof(int)); for(; points[p + 1].x != 0; p += 3) { for(t = 0; t < SIZE * 4; t++) { ft = (double)t / (SIZE * 4.0); /* https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm */ x = (int) Interpolate( Interpolate( Interpolate(points[p].x * SCALE, points[p+1].x * SCALE, ft), Interpolate(points[p+1].x * SCALE, points[p+2].x * SCALE, ft), ft), Interpolate( Interpolate(points[p+1].x * SCALE, points[p+2].x * SCALE, ft), Interpolate(points[p+2].x * SCALE, points[p+3].x * SCALE, ft), ft), ft); y = (int) Interpolate( Interpolate( Interpolate(points[p].y * SCALE, points[p+1].y * SCALE, ft), Interpolate(points[p+1].y * SCALE, points[p+2].y * SCALE, ft), ft), Interpolate( Interpolate(points[p+1].y * SCALE, points[p+2].y * SCALE, ft), Interpolate(points[p+2].y * SCALE, points[p+3].y * SCALE, ft), ft), ft); if( x > 0 && x < SIZE && y >= 0 && y < SIZE ) { if( range[y * 2] == 0 ) { range[y * 2] = range[y * 2 + 1] = x; } else { range[y * 2] = range[y * 2] < x ? range[y * 2] : x; range[y * 2 + 1] = range[y * 2 + 1] > x ? range[y * 2 + 1] : x; } } } } /* Draw scanlines. */ for(y = 0; y < SIZE; y++) { if( range[y * 2] != 0 ) { for(x = range[y * 2]; x <= range[y * 2 + 1]; x++) image[y * SIZE + x] = shape_index < 1 ? (x + y) & 1 : 1; } } p += 2; shape_index++; } /* Output image as PBM. */ printf("P1\n%d %d\n", SIZE, SIZE); for(y = 0; y < SIZE; y++) { for(x = 0; x < SIZE; x++) fputs(image[y * SIZE + x] ? "0 " : "1 ", stdout); putchar('\n'); } return 0; }