Last active
December 30, 2022 08:10
-
-
Save louisswarren/f7729fb1630156153187c0317220f7ba to your computer and use it in GitHub Desktop.
Tiny library for PPM output
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.PHONY: default | |
default: spectrum.png | |
.PHONY: waves-video | |
waves-video: waves | |
./$< | mpv --no-correct-pts --fps=30 --scale=oversample - | |
.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 $@ $^ | |
spectrum: spectrum.c problem.o | |
$(CC) $(CFLAGS) -o $@ $^ | |
waves: waves.c problem.o | |
$(CC) $(CFLAGS) -lm -o $@ $^ | |
problem.o: problem.c problem.h | |
$(CC) -c $(CFLAGS) -o $@ $< | |
.PHONY: clean | |
clean: | |
rm output.* example problem.o |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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->ppm, p->ppm_size, 1, stdout); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include "problem.h" | |
#define PPM_HDR_FMT "P6\n%ld %ld 255\n" | |
size_t | |
problem_size(long width, long height) | |
{ | |
size_t size = sizeof(struct problem); | |
int header_len = snprintf(NULL, 0, PPM_HDR_FMT, width, height); | |
if (width <= 0 || height <= 0 || header_len <= 0) | |
return 0; | |
size += (unsigned int)header_len; | |
if ((unsigned long)height > (SIZE_MAX - size) / width / 3) | |
return 0; | |
size += width * height * 3; | |
return size; | |
} | |
void | |
problem_init(struct problem *p, long width, long height) | |
{ | |
size_t header_size = sprintf(p->ppm, PPM_HDR_FMT, width, height); | |
size_t body_size = 3 * width * height; | |
p->ppm_size = header_size + body_size; | |
p->width = width; | |
p->height = height; | |
p->_pixels = p->ppm + header_size; | |
memset(p->_pixels, 0, body_size); | |
} | |
void | |
problem_set(struct problem *p, long x, long y, uint32_t colour) | |
{ | |
char *pixel = p->_pixels + (p->width * y + x) * 3; | |
pixel[0] = (colour >> 16) & 0xff; | |
pixel[1] = (colour >> 8) & 0xff; | |
pixel[2] = (colour >> 0) & 0xff; | |
} | |
uint32_t | |
problem_get(struct problem *p, long x, long y) | |
{ | |
const char *pixel = p->_pixels + (p->width * y + x) * 3; | |
return pixel[0] << 16 | pixel[1] << 8 | pixel[2] << 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <stddef.h> | |
struct problem { | |
size_t ppm_size; | |
long width; | |
long height; | |
unsigned char *_pixels; | |
unsigned char ppm[]; | |
}; | |
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, uint32_t colour); | |
uint32_t problem_get(struct problem *p, long x, long y); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include "problem.h" | |
#define die(...) do { \ | |
fprintf(stderr, __VA_ARGS__); \ | |
fprintf(stderr, "\n"); \ | |
exit(1); \ | |
} while(0) | |
unsigned long | |
colour(unsigned int s) | |
{ | |
const long start_and_shift[][2] = { | |
{0xff0000, 0x000100}, | |
{0xffff00, -0x010000}, | |
{0x00ff00, 0x000001}, | |
{0x00ffff, -0x000100}, | |
{0x0000ff, 0x010000}, | |
{0xff00ff, -0x000001} | |
}; | |
int t = s % 1530; | |
int section = t / 255; | |
int mul = t % 255; | |
return start_and_shift[section][0] + mul * start_and_shift[section][1]; | |
} | |
int | |
main(void) | |
{ | |
long width = 1530; | |
long height = 40; | |
struct problem *p; | |
size_t sz; | |
uint32_t c; | |
float h; | |
int i, j; | |
if (!(sz = problem_size(width, height))) | |
die("Invalid dimensions"); | |
if (!(p = malloc(sz))) | |
die("Out of memory"); | |
problem_init(p, width, height); | |
for (i = 0; i < width; ++i) { | |
c = colour(i); | |
for (j = 0; j < height; ++j) | |
problem_set(p, i, j, c); | |
} | |
fwrite(p->ppm, p->ppm_size, 1, stdout); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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