fractal/palette.c

116 lines
2.5 KiB
C

/*
* fractal
* Written in 2020 by Lucas
* CC0 1.0 Universal/Public domain - No rights reserved
*
* To the extent possible under law, the author(s) have dedicated all
* copyright and related and neighboring rights to this software to the
* public domain worldwide. This software is distributed without any
* warranty. You should have received a copy of the CC0 Public Domain
* Dedication along with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
/* gepopt visibility for GLIBC */
#if !defined(__OpenBSD__)
#define _DEFAULT_SOURCE
#endif
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include "palette.h"
#include "pnmout.h"
#include "util.h"
#define CLAMP(x, a, b) ((x) < (a) ? (a) : (x) > (b) ? (b) : (x))
static double
bezier3(double t, double p0, double p1, double p2, double p3)
{
double u = 1.0 - t;
return u * u * u * p0
+ 3.0 * u * u * t * p1
+ 3.0 * u * t * t * p2
+ t * t * t * p3;
}
static double
bezier4(double t, double p0, double p1, double p2, double p3)
{
return (1.0 - t) * bezier3(t, p0, p1, p2, p3)
+ t * bezier3(t, p1, p2, p3, p0);
}
struct color *
palette_gen(size_t n)
{
struct color *palette;
double p[12] = {
drand48(), drand48(), drand48(),
drand48(), drand48(), drand48(),
drand48(), drand48(), drand48(),
drand48(), drand48(), drand48(),
};
double r, g, b, t;
size_t i;
if ((palette = malloc(n * sizeof(*palette))) == NULL)
errx(1, "out of memory");
for (i = 0; i < n; i++) {
t = i / (double)n;
r = bezier4(t, p[0], p[3], p[6], p[9]);
g = bezier4(t, p[1], p[4], p[7], p[10]);
b = bezier4(t, p[2], p[5], p[8], p[11]);
palette[i].r = 65535.0 * CLAMP(r, 0.0, 1.0);
palette[i].g = 65535.0 * CLAMP(g, 0.0, 1.0);
palette[i].b = 65535.0 * CLAMP(b, 0.0, 1.0);
}
return palette;
}
static void
usage(void)
{
fprintf(stderr, "Usage: %s palette [-h height] [-w width]\n",
xgetprogname());
exit(1);
}
int
palette_main(int argc, char *argv[])
{
struct color *palette;
int ch, i, j, width, height;
height = 50;
width = 500;
while ((ch = getopt(argc, argv, "h:w:")) != -1)
switch (ch) {
case 'h':
height = parse_integer(optarg, 1, 65535);
break;
case 'w':
width = parse_integer(optarg, 1, 65535);
break;
default:
usage();
}
argc -= optind;
argv += optind;
if (argc > 1)
usage();
palette = palette_gen(width);
pnmout_header(stdout, width, height);
for (i = 0; i < height; i++)
for (j = 0; j < width; j++)
pnmout_pixel(stdout, palette[j]);
free(palette);
return !(fflush(stdout) == 0);
}