Tiny library for PPM output
#include <stdio.h> | |
#include <stdlib.h> | |
#include "problem.h" | |
int | |
main(void) | |
{ | |
int width = 50; | |
int height = 20; | |
int i, j; | |
size_t psz; | |
struct problem *p; | |
if ((psz = problem_size(width, height)) == 0) { | |
fprintf(stderr, "Invalid image dimensions\n"); | |
exit(1); | |
} else if ((p = calloc(1, psz)) == NULL) { | |
fprintf(stderr, "Out of memory\n"); | |
exit(1); | |
} | |
problem_init(p, width, height); | |
for (i = 4; i < 14; ++i) { | |
for (j = 0; j < 20; ++j) | |
problem_set(p, j, i, 0xFF00FF); | |
for (j = 20; j < 35; ++j) | |
problem_set(p, j, i, 0x00FFFF); | |
for (j = 35; j < 50; ++j) | |
problem_set(p, j, i, 0xFFFF00); | |
} | |
fwrite(p->raw, p->len, 1, stdout); | |
return 0; | |
} |
.PHONY: test test-video | |
test: nz.png | |
sxiv $^ | |
test-video: fire | |
./fire | mpv --no-correct-pts --fps=30 --scale=oversample - | |
%.png: %.ppm | |
convert $< $@ | |
%.ppm: % | |
./$< > $@ | |
example: example.c problem.o | |
$(CC) $(CFLAGS) -o $@ $^ | |
video: video.c problem.o | |
$(CC) $(CFLAGS) -o $@ $^ | |
fire: fire.c problem.o | |
$(CC) $(CFLAGS) -o $@ $^ | |
nz: nz.c problem.o | |
$(CC) $(CFLAGS) -o $@ $^ | |
problem.o: problem.c problem.h | |
$(CC) -c $(CFLAGS) -o $@ $< | |
.PHONY: clean | |
clean: | |
rm output.* example problem.o |
#include <stdio.h> | |
#include <stdlib.h> | |
#include "problem.h" | |
#define P186C 0xC8102E | |
#define P280C 0x012169 | |
#define PSAFE 0xFFFFFF | |
#define SQRT5 (2.236067977499790) | |
#define min(X, Y) ((X) < (Y) ? (X) : (Y)) | |
#define max(X, Y) ((X) < (Y) ? (Y) : (X)) | |
int | |
main(void) | |
{ | |
int scale = 10; | |
int height = 60 * scale; | |
int width = 120 * scale; | |
int i, j; | |
size_t psz; | |
struct problem *p; | |
if ((psz = problem_size(width, height)) == 0) { | |
fprintf(stderr, "Invalid image dimensions\n"); | |
exit(1); | |
} else if ((p = calloc(1, psz)) == NULL) { | |
fprintf(stderr, "Out of memory\n"); | |
exit(1); | |
} | |
problem_init(p, width, height); | |
/* Background */ | |
for (i = 0; i < height; ++i) | |
for (j = 0; j < width; ++j) | |
problem_set(p, j, i, P280C); | |
/* St Andrew's Cross */ | |
for (i = 10 * scale; i < 20 * scale; ++i) | |
for (j = 0; j < 60 * scale; ++j) | |
problem_set(p, j, i, PSAFE); | |
for (i = 0; i < 30 * scale; ++i) | |
for (j = 25 * scale; j < 35 * scale; ++j) | |
problem_set(p, j, i, PSAFE); | |
/* Diagonals */ | |
for (i = 0; i < 30 * scale; ++i) { | |
for (j = max(2*i - 3*SQRT5 * scale, 0); | |
j < min(2*i + 3*SQRT5 * scale, 60 * scale); ++j) { | |
problem_set(p, j, i, PSAFE); | |
problem_set(p, 60*scale - j, i, PSAFE); | |
} | |
} | |
/* St Patrick's Cross */ | |
for (i = 0; i < 10 * scale; ++i) { | |
for (j = max(2*i - 2*SQRT5 * scale, 0); j < 2*i; ++j) { | |
problem_set(p, j, i, P186C); | |
problem_set(p, 60 * scale - j, 30 * scale - i, P186C); | |
} | |
for (j = 2*i; j < min(2*i + 2*SQRT5 * scale, 60 * scale); ++j) { | |
problem_set(p, j, 30 * scale - i, P186C); | |
problem_set(p, 60 * scale - j, i, P186C); | |
} | |
} | |
/* St George's Cross */ | |
for (i = 12 * scale; i < 18 * scale; ++i) | |
for (j = 0; j < 60 * scale; ++j) | |
problem_set(p, j, i, P186C); | |
for (i = 0; i < 30 * scale; ++i) | |
for (j = 27 * scale; j < 33 * scale; ++j) | |
problem_set(p, j, i, P186C); | |
fwrite(p->raw, p->len, 1, stdout); | |
return 0; | |
} |
#include <stdint.h> | |
#include <stdio.h> | |
#include "problem.h" | |
#define PPM_HDR_FMT_NONL "P6\n%d %d 255" | |
#define PPM_HDR_FMT (PPM_HDR_FMT_NONL "\n") | |
size_t | |
problem_size(long width, long height) | |
{ | |
size_t header_len = sizeof(struct problem); | |
header_len += snprintf(NULL, 0, PPM_HDR_FMT, width, height); | |
if (width == SIZE_MAX) | |
return 0; | |
else if (height > (SIZE_MAX - header_len) / width / 3) | |
return 0; | |
return header_len + width * height * 3; | |
} | |
void | |
problem_init(struct problem *p, long width, long height) | |
{ | |
long i; | |
p->width = width; | |
p->height = height; | |
/* Don't write out the null after the header in case the memory was | |
* already set (though this could be treated as misuse, I suppose). */ | |
p->len = sprintf(p->raw, PPM_HDR_FMT_NONL, width, height); | |
p->raw[p->len++] = '\n'; | |
p->image = p->raw + p->len; | |
p->len += 3 * width * height; | |
} | |
void | |
problem_set(struct problem *p, long x, long y, unsigned long colour) | |
{ | |
p->image[3 * (p->width * y + x) + 0] = (colour >> 16) & 0xFF; | |
p->image[3 * (p->width * y + x) + 1] = (colour >> 8) & 0xFF; | |
p->image[3 * (p->width * y + x) + 2] = colour & 0xFF; | |
} | |
unsigned long | |
problem_get(struct problem *p, long x, long y) | |
{ | |
unsigned long c = 0; | |
c += p->image[3 * (p->width * y + x) + 0] << 16; | |
c += p->image[3 * (p->width * y + x) + 1] << 8; | |
c += p->image[3 * (p->width * y + x) + 0]; | |
return c; | |
} |
#include <stddef.h> | |
struct problem { | |
long width; | |
long height; | |
char *image; | |
size_t len; | |
char raw[]; | |
}; | |
size_t problem_size(long width, long height); | |
void problem_init(struct problem *p, long width, long height); | |
void problem_set(struct problem *p, long x, long y, unsigned long colour); | |
unsigned long problem_get(struct problem *p, long x, long y); |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include "problem.h" | |
void render(struct problem *p); | |
void render_ball(struct problem *p, float x, float y, float r, unsigned long c); | |
void | |
render(struct problem *p) | |
{ | |
static int b = 0; | |
int i, j; | |
memset(p->image, 0x11, p->width * p->height * 3); | |
for (i = p->height / 4; i < p->height / 4 * 3; ++i) { | |
for (j = 0; j < p->width / 3; ++j) | |
problem_set(p, (j + b) % p->width, i, 0xFF00FF); | |
for (j = p->width / 3; j < p->width / 3 * 2; ++j) | |
problem_set(p, (j + b) % p->width, i, 0x00FFFF); | |
for (j = p->width / 3 * 2; j < p->width; ++j) | |
problem_set(p, (j + b) % p->width, i, 0xFFFF00); | |
} | |
render_ball(p, (320 + b) % p->width, (240 + b) % p->height, 25, 0xFF8822); | |
b += 10; | |
} | |
void | |
render_ball(struct problem *p, float x, float y, float r, unsigned long c) | |
{ | |
int i, j; | |
int min_i = y - r < 0 ? 0 : y - r; | |
int min_j = x - r < 0 ? 0 : x - r; | |
int max_i = y + r + 1 <= p->height ? y + r + 1 : p->height; | |
int max_j = x + r + 1 <= p->width ? x + r + 1 : p->width; | |
for (i = min_i; i < max_i; ++i) | |
for (j = min_j; j < max_j; ++j) | |
if ((x - (float) j) * (x - (float) j) + (y - (float) i) * (y - (float) i) < r * r) | |
problem_set(p, j, i, c); | |
} | |
int | |
main(void) | |
{ | |
int width = 640; | |
int height = 480; | |
size_t psz; | |
struct problem *p; | |
if ((psz = problem_size(width, height)) == 0) { | |
fprintf(stderr, "Invalid image dimensions\n"); | |
exit(1); | |
} else if ((p = calloc(1, psz)) == NULL) { | |
fprintf(stderr, "Out of memory\n"); | |
exit(1); | |
} | |
problem_init(p, width, height); | |
do { | |
render(p); | |
} while (fwrite(p->raw, p->len, 1, stdout)); | |
return 0; | |
} |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <math.h> | |
#include "problem.h" | |
void render(struct problem *p); | |
void plot(struct problem *p, float x, float y, float r, unsigned long c); | |
void advance_colour(unsigned long *c); | |
void | |
render(struct problem *p) | |
{ | |
static int j = 0; | |
static unsigned long c = 0; | |
int i, k; | |
double x, y; | |
float g = 0.01; | |
for (k = 0; k < 1.0 / g; ++k) { | |
x = 2 * M_PI * (g * k + j) / p->width * 4; | |
y = sin(x); | |
i = (1 - y) * p->height / 2; | |
i = i < 0 ? 0 : i; | |
i = i >= p->height ? p->height : i; | |
plot(p, j, i, 2, c); | |
advance_colour(&c); | |
if (c > 0xFFFFFF) | |
c = 0; | |
fprintf(stderr, "Colour: %d\t%d\t%d\n", c >> 32, (c >> 16) & 0xFF, (c >> 32) & 0xFF); | |
} | |
j = (j + 1) % p->width; | |
if (!j) { | |
memset(p->image, 0xFF, p->width * p->height * 3); | |
} | |
} | |
void | |
advance_colour(unsigned long *c) | |
{ | |
if ((*c >> 32) % 2 == (*c >> 16) % 2) { | |
if (*c & 0xFF == 0xFF) { | |
if ((*c >> 16) & 0xFF == 0xFF) | |
*c += 0x10000; | |
else | |
*c += 0x100; | |
} else { | |
*c += 0x1; | |
} | |
} else { | |
if (*c & 0xFF == 0) { | |
if ((*c >> 16) & 0xFF == 0) | |
*c += 0x10000; | |
else | |
*c -= 0x100; | |
} else { | |
*c -= 0x1; | |
} | |
} | |
} | |
void | |
plot(struct problem *p, float x, float y, float r, unsigned long c) | |
{ | |
int i, j; | |
int min_i = y - r < 0 ? 0 : y - r; | |
int min_j = x - r < 0 ? 0 : x - r; | |
int max_i = y + r + 1 <= p->height ? y + r + 1 : p->height; | |
int max_j = x + r + 1 <= p->width ? x + r + 1 : p->width; | |
for (i = min_i; i < max_i; ++i) | |
for (j = min_j; j < max_j; ++j) | |
if ((x - (float) j) * (x - (float) j) + (y - (float) i) * (y - (float) i) < r * r) | |
problem_set(p, j, i, c); | |
} | |
int | |
main(void) | |
{ | |
int width = 640; | |
int height = 480; | |
int k; | |
size_t psz; | |
struct problem *p; | |
if ((psz = problem_size(width, height)) == 0) { | |
fprintf(stderr, "Invalid image dimensions\n"); | |
exit(1); | |
} else if ((p = calloc(1, psz)) == NULL) { | |
fprintf(stderr, "Out of memory\n"); | |
exit(1); | |
} | |
problem_init(p, width, height); | |
memset(p->image, 0xFF, p->width * p->height * 3); | |
do { | |
for (k = 0; k < 10; ++k) | |
render(p); | |
} while (fwrite(p->raw, p->len, 1, stdout)); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment