Skip to content

Instantly share code, notes, and snippets.

@louisswarren
Last active December 30, 2022 08:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save louisswarren/f7729fb1630156153187c0317220f7ba to your computer and use it in GitHub Desktop.
Save louisswarren/f7729fb1630156153187c0317220f7ba to your computer and use it in GitHub Desktop.
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: 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
#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;
}
#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;
}
#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);
#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);
}
#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