blind

suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log | Files | Refs | README | LICENSE

commit e76229ac4f95ac8c6e4e38e60689a09a091e4048
parent c91c5cb8e892f1c19c970cef033cc03c9f47f98a
Author: Mattias Andrée <maandree@kth.se>
Date:   Sun,  2 Jul 2017 23:58:01 +0200

Add gradients

Signed-off-by: Mattias Andrée <maandree@kth.se>

Diffstat:
Makefile | 12++++++++++++
src/blind-cone-gradient.c | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-coordinate-field.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-double-sinus-wave.c | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-linear-gradient.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-radial-gradient.c | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-round-wave.c | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-sawtooth-wave.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-sinc-wave.c | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-sinus-wave.c | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-spiral-gradient.c | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-square-gradient.c | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-triangular-wave.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/video-math.h | 4++++
14 files changed, 1267 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -9,7 +9,9 @@ BIN =\ blind-colour-srgb\ blind-compress\ blind-concat\ + blind-cone-gradient\ blind-convert\ + blind-coordinate-field\ blind-crop\ blind-cross-product\ blind-cut\ @@ -17,6 +19,7 @@ BIN =\ blind-disperse\ blind-dissolve\ blind-dot-product\ + blind-double-sinus-wave\ blind-extend\ blind-find-rectangle\ blind-flip\ @@ -29,26 +32,35 @@ BIN =\ blind-gauss-blur\ blind-interleave\ blind-invert-luma\ + blind-linear-gradient\ blind-make-kernel\ blind-next-frame\ blind-norm\ blind-quaternion-product\ blind-premultiply\ + blind-radial-gradient\ blind-read-head\ blind-repeat\ blind-reverse\ blind-rewrite-head\ + blind-round-wave\ + blind-sawtooth-wave\ blind-set-alpha\ blind-set-luma\ blind-set-saturation\ blind-single-colour\ + blind-sinc-wave\ + blind-sinus-wave\ blind-skip-pattern\ + blind-spiral-gradient\ blind-split\ blind-split-cols\ blind-split-rows\ + blind-square-gradient\ blind-stack\ blind-tee\ blind-time-blur\ + blind-triangular-wave\ blind-to-image\ blind-to-named\ blind-to-portable\ diff --git a/src/blind-cone-gradient.c b/src/blind-cone-gradient.c @@ -0,0 +1,126 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-a | -s] -w width -h height") + +static int anticlockwise = 0; +static int symmetric = 0; +static size_t width = 0; +static size_t height = 0; +static int with_multiplier = 0; + + +#define PROCESS(TYPE, SUFFIX)\ + static void\ + process_##SUFFIX(struct stream *stream)\ + {\ + typedef TYPE pixel_t[4];\ + pixel_t buf[BUFSIZ / sizeof(pixel_t)];\ + TYPE *params, x1, y1, x2, y2;\ + TYPE x, y, u, v, m = 1;\ + size_t ix, iy, ptr = 0;\ + for (;;) {\ + while (stream->ptr < stream->frame_size) {\ + if (!eread_stream(stream, stream->frame_size - stream->ptr)) {\ + ewriteall(STDOUT_FILENO, buf, ptr * sizeof(*buf), "<stdout>");\ + return;\ + }\ + }\ + params = (TYPE *)stream->buf;\ + x1 = (params)[0];\ + y1 = (params)[1];\ + x2 = (params)[4];\ + y2 = (params)[5];\ + if (with_multiplier)\ + m = (params)[9];\ + memmove(stream->buf, stream->buf + stream->frame_size,\ + stream->ptr -= stream->frame_size);\ + \ + x2 -= x1;\ + y2 -= y1;\ + u = atan2(y2, x2);\ + \ + for (iy = 0; iy < height; iy++) {\ + y = (TYPE)iy - y1;\ + for (ix = 0; ix < width; ix++) {\ + x = (TYPE)ix - x1;\ + v = atan2(y, x);\ + v -= u;\ + v += 2 * (TYPE)M_PI;\ + v = mod(v, 2 * (TYPE)M_PI);\ + v /= 2 * (TYPE)M_PI;\ + if (anticlockwise)\ + v = 1 - v;\ + v *= m;\ + if (symmetric) {\ + v = mod(2 * v, (TYPE)2);\ + if (v > 1)\ + v = 2 - v;\ + }\ + buf[ptr][0] = buf[ptr][1] = buf[ptr][2] = buf[ptr][3] = v;\ + if (++ptr == ELEMENTSOF(buf)) {\ + ewriteall(STDOUT_FILENO, buf, sizeof(buf), "<stdout>");\ + ptr = 0;\ + }\ + }\ + }\ + }\ + } + +PROCESS(double, lf) +PROCESS(float, f) + + +int +main(int argc, char *argv[]) +{ + struct stream stream; + void (*process)(struct stream *stream); + + ARGBEGIN { + case 'a': + if (symmetric) + usage(); + anticlockwise = 1; + break; + case 's': + if (anticlockwise) + usage(); + symmetric = 1; + break; + case 'w': + width = etozu_flag('w', UARGF(), 1, SIZE_MAX); + break; + case 'h': + height = etozu_flag('h', UARGF(), 1, SIZE_MAX); + break; + default: + usage(); + } ARGEND; + + if (!width || !height || argc) + usage(); + + eopen_stream(&stream, NULL); + + if (!strcmp(stream.pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(stream.pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); + + if (stream.width > 3 || stream.height > 3 || + stream.width * stream.height < 2 || + stream.width * stream.height > 3) + eprintf("<stdin>: each frame must contain exactly 2 or 3 pixels\n"); + + with_multiplier = stream.width * stream.height == 3; + + stream.width = width; + stream.height = height; + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + process(&stream); + return 0; +} diff --git a/src/blind-coordinate-field.c b/src/blind-coordinate-field.c @@ -0,0 +1,77 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-f frames | -f 'inf'] [-F pixel-format] -w width -h height") + +static struct stream stream = { .width = 0, .height = 0, .frames = 1 }; +static int inf = 0; + +#define PROCESS(TYPE)\ + do {\ + TYPE buf[4] = {0, 0, 0, 0};\ + size_t x, y;\ + \ + while (inf || stream.frames--) {\ + for (y = 0; y < stream.height; y++) {\ + buf[1] = (TYPE)y;\ + for (x = 0; x < stream.width; x++) {\ + buf[0] = (TYPE)x;\ + if (write(STDOUT_FILENO, buf, sizeof(buf)) < 0)\ + eprintf("write <stdout>:");\ + }\ + }\ + }\ + } while (0) + +static void process_lf(void) {PROCESS(double);} +static void process_f(void) {PROCESS(float);} + +int +main(int argc, char *argv[]) +{ + char *arg; + const char *pixfmt = "xyza"; + void (*process)(void); + + ARGBEGIN { + case 'f': + arg = UARGF(); + if (!strcmp(arg, "inf")) + inf = 1, stream.frames = 0; + else + stream.frames = etozu_flag('f', arg, 1, SIZE_MAX); + break; + case 'F': + pixfmt = UARGF(); + break; + case 'w': + stream.width = etozu_flag('w', UARGF(), 1, SIZE_MAX); + break; + case 'h': + stream.height = etozu_flag('h', UARGF(), 1, SIZE_MAX); + break; + default: + usage(); + } ARGEND; + + if (!stream.width || !stream.height || argc) + usage(); + + if (inf) + einf_check_fd(STDOUT_FILENO, "<stdout>"); + + pixfmt = get_pixel_format(pixfmt, "xyza"); + if (!strcmp(pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", pixfmt); + + strcpy(stream.pixfmt, pixfmt); + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + + process(); + return 0; +} diff --git a/src/blind-double-sinus-wave.c b/src/blind-double-sinus-wave.c @@ -0,0 +1,94 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-e]") + +static int equal = 0; + + +#define PROCESS(TYPE, SUFFIX)\ + static void\ + process_##SUFFIX(struct stream *stream)\ + {\ + size_t i, n;\ + TYPE x, y, z, a;\ + do {\ + n = stream->ptr / stream->pixel_size;\ + if (equal) {\ + for (i = 0; i < n; i++) {\ + a = ((TYPE *)(stream->buf))[4 * i + 3];\ + a = posmod(a, (TYPE)2);\ + a = a > 1 ? 2 - a : a;\ + a = 1 - (sin(a * (2 * (TYPE)M_PI)) + 1) / 2;\ + ((TYPE *)(stream->buf))[4 * i + 0] = a;\ + ((TYPE *)(stream->buf))[4 * i + 1] = a;\ + ((TYPE *)(stream->buf))[4 * i + 2] = a;\ + ((TYPE *)(stream->buf))[4 * i + 3] = a;\ + }\ + } else {\ + for (i = 0; i < n; i++) {\ + x = ((TYPE *)(stream->buf))[4 * i + 0];\ + y = ((TYPE *)(stream->buf))[4 * i + 1];\ + z = ((TYPE *)(stream->buf))[4 * i + 2];\ + a = ((TYPE *)(stream->buf))[4 * i + 3];\ + x = posmod(x, (TYPE)1);\ + y = posmod(y, (TYPE)1);\ + z = posmod(z, (TYPE)1);\ + a = posmod(a, (TYPE)1);\ + x = x > 1 ? 2 - x : x;\ + y = y > 1 ? 2 - y : y;\ + z = z > 1 ? 2 - z : z;\ + a = a > 1 ? 2 - a : a;\ + x = 1 - (sin(x * (2 * (TYPE)M_PI)) + 1) / 2;\ + y = 1 - (sin(y * (2 * (TYPE)M_PI)) + 1) / 2;\ + z = 1 - (sin(z * (2 * (TYPE)M_PI)) + 1) / 2;\ + a = 1 - (sin(a * (2 * (TYPE)M_PI)) + 1) / 2;\ + ((TYPE *)(stream->buf))[4 * i + 0] = x;\ + ((TYPE *)(stream->buf))[4 * i + 1] = y;\ + ((TYPE *)(stream->buf))[4 * i + 2] = z;\ + ((TYPE *)(stream->buf))[4 * i + 3] = a;\ + }\ + }\ + n *= stream->pixel_size;\ + ewriteall(STDOUT_FILENO, stream->buf, n, "<stdout>");\ + memmove(stream->buf, stream->buf + n, stream->ptr -= n);\ + } while (eread_stream(stream, SIZE_MAX));\ + if (stream->ptr)\ + eprintf("%s: incomplete frame\n", stream->file);\ + } + +PROCESS(double, lf) +PROCESS(float, f) + + +int +main(int argc, char *argv[]) +{ + struct stream stream; + void (*process)(struct stream *stream); + + ARGBEGIN { + case 'e': + equal = 1; + break; + default: + usage(); + } ARGEND; + + if (argc) + usage(); + + eopen_stream(&stream, NULL); + + if (!strcmp(stream.pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(stream.pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); + + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + process(&stream); + return 0; +} diff --git a/src/blind-linear-gradient.c b/src/blind-linear-gradient.c @@ -0,0 +1,101 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-b] -w width -h height") + +static int bilinear = 0; +static size_t width = 0; +static size_t height = 0; + + +#define PROCESS(TYPE, SUFFIX)\ + static void\ + process_##SUFFIX(struct stream *stream)\ + {\ + typedef TYPE pixel_t[4];\ + pixel_t buf[BUFSIZ / sizeof(pixel_t)];\ + TYPE *params, x1, y1, x2, y2, norm2;\ + TYPE x, y;\ + size_t ix, iy, ptr = 0;\ + for (;;) {\ + while (stream->ptr < stream->frame_size) {\ + if (!eread_stream(stream, stream->frame_size - stream->ptr)) {\ + ewriteall(STDOUT_FILENO, buf, ptr * sizeof(*buf), "<stdout>");\ + return;\ + }\ + }\ + params = (TYPE *)stream->buf;\ + x1 = (params)[0];\ + y1 = (params)[1];\ + x2 = (params)[4];\ + y2 = (params)[5];\ + memmove(stream->buf, stream->buf + stream->frame_size,\ + stream->ptr -= stream->frame_size);\ + \ + x2 -= x1;\ + y2 -= y1;\ + norm2 = x2 * x2 + y2 * y2;\ + \ + for (iy = 0; iy < height; iy++) {\ + y = (TYPE)iy - y1;\ + for (ix = 0; ix < width; ix++) {\ + x = (TYPE)ix - x1;\ + x = (x * x2 + y * y2) / norm2;\ + if (bilinear)\ + x = abs(x);\ + buf[ptr][0] = buf[ptr][1] = buf[ptr][2] = buf[ptr][3] = x;\ + if (++ptr == ELEMENTSOF(buf)) {\ + ewriteall(STDOUT_FILENO, buf, sizeof(buf), "<stdout>");\ + ptr = 0;\ + }\ + }\ + }\ + }\ + } + +PROCESS(double, lf) +PROCESS(float, f) + + +int +main(int argc, char *argv[]) +{ + struct stream stream; + void (*process)(struct stream *stream); + + ARGBEGIN { + case 'b': + bilinear = 1; + break; + case 'w': + width = etozu_flag('w', UARGF(), 1, SIZE_MAX); + break; + case 'h': + height = etozu_flag('h', UARGF(), 1, SIZE_MAX); + break; + default: + usage(); + } ARGEND; + + if (!width || !height || argc) + usage(); + + eopen_stream(&stream, NULL); + + if (!strcmp(stream.pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(stream.pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); + + if (stream.width > 2 || stream.height > 2 || stream.width * stream.height != 2) + eprintf("<stdin>: each frame must contain exactly 2 pixels\n"); + + stream.width = width; + stream.height = height; + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + process(&stream); + return 0; +} diff --git a/src/blind-radial-gradient.c b/src/blind-radial-gradient.c @@ -0,0 +1,128 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("-w width -h height") + +static size_t width = 0; +static size_t height = 0; +static int with_params; + + +#define PROCESS(TYPE, SUFFIX)\ + static void\ + process_##SUFFIX(struct stream *stream)\ + {\ + typedef TYPE pixel_t[4];\ + pixel_t buf[BUFSIZ / sizeof(pixel_t)];\ + TYPE *params, x1, y1, x2, y2, norm, rd = 1, pe = 2, re = 2, e = 0.5;\ + TYPE x, y, p, r, rx, ry;\ + size_t ix, iy, ptr = 0;\ + for (;;) {\ + while (stream->ptr < stream->frame_size) {\ + if (!eread_stream(stream, stream->frame_size - stream->ptr)) {\ + ewriteall(STDOUT_FILENO, buf, ptr * sizeof(*buf), "<stdout>");\ + return;\ + }\ + }\ + params = (TYPE *)stream->buf;\ + x1 = (params)[0];\ + y1 = (params)[1];\ + x2 = (params)[4];\ + y2 = (params)[5];\ + if (with_params) {\ + pe = (params)[8];\ + re = (params)[9];\ + rd = (params)[10];\ + e = 1 / sqrt(pe * re);\ + }\ + memmove(stream->buf, stream->buf + stream->frame_size,\ + stream->ptr -= stream->frame_size);\ + \ + x2 -= x1;\ + y2 -= y1;\ + norm = sqrt(x2 * x2 + y2 * y2);\ + \ + if (!with_params) {\ + for (iy = 0; iy < height; iy++) {\ + y = (TYPE)iy - y1;\ + y *= y;\ + for (ix = 0; ix < width; ix++) {\ + x = (TYPE)ix - x1;\ + x = sqrt(x * x + y) / norm;\ + buf[ptr][0] = buf[ptr][1] = buf[ptr][2] = buf[ptr][3] = x;\ + if (++ptr == ELEMENTSOF(buf)) {\ + ewriteall(STDOUT_FILENO, buf, sizeof(buf), "<stdout>");\ + ptr = 0;\ + }\ + }\ + }\ + } else {\ + for (iy = 0; iy < height; iy++) {\ + y = (TYPE)iy - y1;\ + for (ix = 0; ix < width; ix++) {\ + x = (TYPE)ix - x1;\ + p = (x * x2 + y * y2) / norm;\ + rx = x - p * x2 / norm;\ + ry = y - p * y2 / norm;\ + r = sqrt(rx * rx + ry * ry) / rd;\ + p = pow(abs(p / norm), pe);\ + r = pow(abs(r / norm), re);\ + x = pow(p + r, e);\ + buf[ptr][0] = buf[ptr][1] = buf[ptr][2] = buf[ptr][3] = x;\ + if (++ptr == ELEMENTSOF(buf)) {\ + ewriteall(STDOUT_FILENO, buf, sizeof(buf), "<stdout>");\ + ptr = 0;\ + }\ + }\ + }\ + }\ + }\ + } + +PROCESS(double, lf) +PROCESS(float, f) + + +int +main(int argc, char *argv[]) +{ + struct stream stream; + void (*process)(struct stream *stream); + + ARGBEGIN { + case 'w': + width = etozu_flag('w', UARGF(), 1, SIZE_MAX); + break; + case 'h': + height = etozu_flag('h', UARGF(), 1, SIZE_MAX); + break; + default: + usage(); + } ARGEND; + + if (!width || !height || argc) + usage(); + + eopen_stream(&stream, NULL); + + if (!strcmp(stream.pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(stream.pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); + + if (stream.width > 3 || stream.height > 3 || + stream.width * stream.height < 2 || + stream.width * stream.height > 3) + eprintf("<stdin>: each frame must contain exactly 2 pixels\n"); + + with_params = stream.width * stream.height == 3; + + stream.width = width; + stream.height = height; + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + process(&stream); + return 0; +} diff --git a/src/blind-round-wave.c b/src/blind-round-wave.c @@ -0,0 +1,89 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-e]") + +static int equal = 0; + + +#define PROCESS(TYPE, SUFFIX)\ + static void\ + process_##SUFFIX(struct stream *stream)\ + {\ + size_t i, n;\ + TYPE x, y, z, a;\ + do {\ + n = stream->ptr / stream->pixel_size;\ + if (equal) {\ + for (i = 0; i < n; i++) {\ + a = ((TYPE *)(stream->buf))[4 * i + 3];\ + a = mod(a + 1, (TYPE)4) - 1;\ + a = a < 1 ? 1 - a * a / 2 : (a - 2) * (a - 2) / 2;\ + ((TYPE *)(stream->buf))[4 * i + 0] = a;\ + ((TYPE *)(stream->buf))[4 * i + 1] = a;\ + ((TYPE *)(stream->buf))[4 * i + 2] = a;\ + ((TYPE *)(stream->buf))[4 * i + 3] = a;\ + }\ + } else {\ + for (i = 0; i < n; i++) {\ + x = ((TYPE *)(stream->buf))[4 * i + 0];\ + y = ((TYPE *)(stream->buf))[4 * i + 1];\ + z = ((TYPE *)(stream->buf))[4 * i + 2];\ + a = ((TYPE *)(stream->buf))[4 * i + 3];\ + x = mod(x + 1, (TYPE)4) - 1;\ + y = mod(y + 1, (TYPE)4) - 1;\ + z = mod(z + 1, (TYPE)4) - 1;\ + a = mod(a + 1, (TYPE)4) - 1;\ + x = x < 1 ? 1 - x * x / 2 : (x - 2) * (x - 2) / 2;\ + y = y < 1 ? 1 - y * y / 2 : (y - 2) * (y - 2) / 2;\ + z = z < 1 ? 1 - z * z / 2 : (z - 2) * (z - 2) / 2;\ + a = a < 1 ? 1 - a * a / 2 : (a - 2) * (a - 2) / 2;\ + ((TYPE *)(stream->buf))[4 * i + 0] = x;\ + ((TYPE *)(stream->buf))[4 * i + 1] = y;\ + ((TYPE *)(stream->buf))[4 * i + 2] = z;\ + ((TYPE *)(stream->buf))[4 * i + 3] = a;\ + }\ + }\ + n *= stream->pixel_size;\ + ewriteall(STDOUT_FILENO, stream->buf, n, "<stdout>");\ + memmove(stream->buf, stream->buf + n, stream->ptr -= n);\ + } while (eread_stream(stream, SIZE_MAX));\ + if (stream->ptr)\ + eprintf("%s: incomplete frame\n", stream->file);\ + } + +PROCESS(double, lf) +PROCESS(float, f) + + +int +main(int argc, char *argv[]) +{ + struct stream stream; + void (*process)(struct stream *stream); + + ARGBEGIN { + case 'e': + equal = 1; + break; + default: + usage(); + } ARGEND; + + if (argc) + usage(); + + eopen_stream(&stream, NULL); + + if (!strcmp(stream.pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(stream.pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); + + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + process(&stream); + return 0; +} diff --git a/src/blind-sawtooth-wave.c b/src/blind-sawtooth-wave.c @@ -0,0 +1,84 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-e]") + +static int equal = 0; + + +#define PROCESS(TYPE, SUFFIX)\ + static void\ + process_##SUFFIX(struct stream *stream)\ + {\ + size_t i, n;\ + TYPE x, y, z, a;\ + do {\ + n = stream->ptr / stream->pixel_size;\ + if (equal) {\ + for (i = 0; i < n; i++) {\ + a = ((TYPE *)(stream->buf))[4 * i + 3];\ + a = posmod(a, (TYPE)1);\ + ((TYPE *)(stream->buf))[4 * i + 0] = a;\ + ((TYPE *)(stream->buf))[4 * i + 1] = a;\ + ((TYPE *)(stream->buf))[4 * i + 2] = a;\ + ((TYPE *)(stream->buf))[4 * i + 3] = a;\ + }\ + } else {\ + for (i = 0; i < n; i++) {\ + x = ((TYPE *)(stream->buf))[4 * i + 0];\ + y = ((TYPE *)(stream->buf))[4 * i + 1];\ + z = ((TYPE *)(stream->buf))[4 * i + 2];\ + a = ((TYPE *)(stream->buf))[4 * i + 3];\ + x = posmod(x, (TYPE)1);\ + y = posmod(y, (TYPE)1);\ + z = posmod(z, (TYPE)1);\ + a = posmod(a, (TYPE)1);\ + ((TYPE *)(stream->buf))[4 * i + 0] = x;\ + ((TYPE *)(stream->buf))[4 * i + 1] = y;\ + ((TYPE *)(stream->buf))[4 * i + 2] = z;\ + ((TYPE *)(stream->buf))[4 * i + 3] = a;\ + }\ + }\ + n *= stream->pixel_size;\ + ewriteall(STDOUT_FILENO, stream->buf, n, "<stdout>");\ + memmove(stream->buf, stream->buf + n, stream->ptr -= n);\ + } while (eread_stream(stream, SIZE_MAX));\ + if (stream->ptr)\ + eprintf("%s: incomplete frame\n", stream->file);\ + } + +PROCESS(double, lf) +PROCESS(float, f) + + +int +main(int argc, char *argv[]) +{ + struct stream stream; + void (*process)(struct stream *stream); + + ARGBEGIN { + case 'e': + equal = 1; + break; + default: + usage(); + } ARGEND; + + if (argc) + usage(); + + eopen_stream(&stream, NULL); + + if (!strcmp(stream.pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(stream.pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); + + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + process(&stream); + return 0; +} diff --git a/src/blind-sinc-wave.c b/src/blind-sinc-wave.c @@ -0,0 +1,114 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-e] [theta0-stream]") + +static int equal = 0; + + +#define PROCESS(TYPE, SUFFIX)\ + static void\ + process_##SUFFIX(struct stream *grad, struct stream *theta0)\ + {\ + size_t i, n, m = 0;\ + TYPE *theta0xyza;\ + TYPE x, theta0x = 0;\ + TYPE y, theta0y = 0;\ + TYPE z, theta0z = 0;\ + TYPE a, theta0a = 0;\ + echeck_dimensions(grad, WIDTH | HEIGHT, NULL);\ + do {\ + if (!m) {\ + m = grad->frame_size;\ + if (theta0) {\ + while (theta0->ptr < theta0->frame_size)\ + if (!eread_stream(theta0, theta0->frame_size - theta0->ptr))\ + return;\ + theta0xyza = (TYPE *)theta0->buf;\ + theta0x = (theta0xyza)[0];\ + theta0y = (theta0xyza)[1];\ + theta0z = (theta0xyza)[2];\ + theta0a = (theta0xyza)[3];\ + memmove(theta0->buf, theta0->buf + theta0->frame_size,\ + theta0->ptr -= theta0->frame_size);\ + }\ + }\ + n = MIN(grad->ptr, m) / grad->pixel_size;\ + if (equal) {\ + for (i = 0; i < n; i++) {\ + a = ((TYPE *)(grad->buf))[4 * i + 3];\ + a = (a ? sin(a + theta0y) / a : sin(a + theta0y)) / 2 + 0.5;\ + ((TYPE *)(grad->buf))[4 * i + 0] = a;\ + ((TYPE *)(grad->buf))[4 * i + 1] = a;\ + ((TYPE *)(grad->buf))[4 * i + 2] = a;\ + ((TYPE *)(grad->buf))[4 * i + 3] = a;\ + }\ + } else {\ + for (i = 0; i < n; i++) {\ + x = ((TYPE *)(grad->buf))[4 * i + 0];\ + y = ((TYPE *)(grad->buf))[4 * i + 1];\ + z = ((TYPE *)(grad->buf))[4 * i + 2];\ + a = ((TYPE *)(grad->buf))[4 * i + 3];\ + x = (x ? sin(x + theta0x) / x : sin(x + theta0x)) / 2 + 0.5;\ + y = (y ? sin(y + theta0y) / y : sin(y + theta0y)) / 2 + 0.5;\ + z = (z ? sin(z + theta0z) / z : sin(z + theta0z)) / 2 + 0.5;\ + a = (a ? sin(a + theta0a) / a : sin(a + theta0a)) / 2 + 0.5;\ + ((TYPE *)(grad->buf))[4 * i + 0] = x;\ + ((TYPE *)(grad->buf))[4 * i + 1] = y;\ + ((TYPE *)(grad->buf))[4 * i + 2] = z;\ + ((TYPE *)(grad->buf))[4 * i + 3] = a;\ + }\ + }\ + n *= grad->pixel_size;\ + m -= n;\ + ewriteall(STDOUT_FILENO, grad->buf, n, "<stdout>");\ + memmove(grad->buf, grad->buf + n, grad->ptr -= n);\ + } while (eread_stream(grad, SIZE_MAX));\ + if (grad->ptr)\ + eprintf("%s: incomplete frame\n", grad->file);\ + } + +PROCESS(double, lf) +PROCESS(float, f) + + +int +main(int argc, char *argv[]) +{ + struct stream stream, theta0; + int have_theta0; + void (*process)(struct stream *grad, struct stream *theta0); + + ARGBEGIN { + case 'e': + equal = 1; + break; + default: + usage(); + } ARGEND; + + if (argc > 1) + usage(); + + eopen_stream(&stream, NULL); + if ((have_theta0 = argc == 1)) { + eopen_stream(&theta0, argv[0]); + if (theta0.width != 1 || theta0.height != 1) + eprintf("theta0-stream must be of dimension 1x1\n"); + } + + if (!strcmp(stream.pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(stream.pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); + + if (have_theta0 && strcmp(stream.pixfmt, theta0.pixfmt)) + eprintf("videos use incompatible pixel formats\n"); + + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + process(&stream, have_theta0 ? &theta0 : NULL); + return 0; +} diff --git a/src/blind-sinus-wave.c b/src/blind-sinus-wave.c @@ -0,0 +1,94 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-e]") + +static int equal = 0; + + +#define PROCESS(TYPE, SUFFIX)\ + static void\ + process_##SUFFIX(struct stream *stream)\ + {\ + size_t i, n;\ + TYPE x, y, z, a;\ + do {\ + n = stream->ptr / stream->pixel_size;\ + if (equal) {\ + for (i = 0; i < n; i++) {\ + a = ((TYPE *)(stream->buf))[4 * i + 3];\ + a = posmod(a, (TYPE)2);\ + a = a > 1 ? 2 - a : a;\ + a = 1 - (cos(a * (TYPE)M_PI) + 1) / 2;\ + ((TYPE *)(stream->buf))[4 * i + 0] = a;\ + ((TYPE *)(stream->buf))[4 * i + 1] = a;\ + ((TYPE *)(stream->buf))[4 * i + 2] = a;\ + ((TYPE *)(stream->buf))[4 * i + 3] = a;\ + }\ + } else {\ + for (i = 0; i < n; i++) {\ + x = ((TYPE *)(stream->buf))[4 * i + 0];\ + y = ((TYPE *)(stream->buf))[4 * i + 1];\ + z = ((TYPE *)(stream->buf))[4 * i + 2];\ + a = ((TYPE *)(stream->buf))[4 * i + 3];\ + x = posmod(x, (TYPE)1);\ + y = posmod(y, (TYPE)1);\ + z = posmod(z, (TYPE)1);\ + a = posmod(a, (TYPE)1);\ + x = x > 1 ? 2 - x : x;\ + y = y > 1 ? 2 - y : y;\ + z = z > 1 ? 2 - z : z;\ + a = a > 1 ? 2 - a : a;\ + x = 1 - (cos(x * (TYPE)M_PI) + 1) / 2;\ + y = 1 - (cos(y * (TYPE)M_PI) + 1) / 2;\ + z = 1 - (cos(z * (TYPE)M_PI) + 1) / 2;\ + a = 1 - (cos(a * (TYPE)M_PI) + 1) / 2;\ + ((TYPE *)(stream->buf))[4 * i + 0] = x;\ + ((TYPE *)(stream->buf))[4 * i + 1] = y;\ + ((TYPE *)(stream->buf))[4 * i + 2] = z;\ + ((TYPE *)(stream->buf))[4 * i + 3] = a;\ + }\ + }\ + n *= stream->pixel_size;\ + ewriteall(STDOUT_FILENO, stream->buf, n, "<stdout>");\ + memmove(stream->buf, stream->buf + n, stream->ptr -= n);\ + } while (eread_stream(stream, SIZE_MAX));\ + if (stream->ptr)\ + eprintf("%s: incomplete frame\n", stream->file);\ + } + +PROCESS(double, lf) +PROCESS(float, f) + + +int +main(int argc, char *argv[]) +{ + struct stream stream; + void (*process)(struct stream *stream); + + ARGBEGIN { + case 'e': + equal = 1; + break; + default: + usage(); + } ARGEND; + + if (argc) + usage(); + + eopen_stream(&stream, NULL); + + if (!strcmp(stream.pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(stream.pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); + + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + process(&stream); + return 0; +} diff --git a/src/blind-spiral-gradient.c b/src/blind-spiral-gradient.c @@ -0,0 +1,134 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-al] -w width -h height") + +static int anticlockwise = 0; +static int logarithmic = 0; +static size_t width = 0; +static size_t height = 0; +static int with_params; + + +#define PROCESS(TYPE, SUFFIX)\ + static void\ + process_##SUFFIX(struct stream *stream)\ + {\ + typedef TYPE pixel_t[4];\ + pixel_t buf[BUFSIZ / sizeof(pixel_t)];\ + TYPE *params, x1, y1, x2, y2, b, r, u, v;\ + TYPE x, y, a = 0, e = 1, p = 1, k = 1, ep = 1;\ + size_t ix, iy, ptr = 0;\ + for (;;) {\ + while (stream->ptr < stream->frame_size) {\ + if (!eread_stream(stream, stream->frame_size - stream->ptr)) {\ + ewriteall(STDOUT_FILENO, buf, ptr * sizeof(*buf), "<stdout>");\ + return;\ + }\ + }\ + params = (TYPE *)stream->buf;\ + x1 = (params)[0];\ + y1 = (params)[1];\ + x2 = (params)[4];\ + y2 = (params)[5];\ + if (with_params) {\ + a = (params)[8];\ + e = (params)[9];\ + p = (params)[10];\ + k = (params)[11];\ + ep = 1 / (e * p);\ + }\ + memmove(stream->buf, stream->buf + stream->frame_size,\ + stream->ptr -= stream->frame_size);\ + \ + x2 -= x1;\ + y2 -= y1;\ + u = atan2(y2, x2);\ + b = sqrt(x2 * x2 + y2 * y2);\ + if (logarithmic)\ + b = log(b);\ + b /= pow(2 * (TYPE)M_PI, e);\ + \ + for (iy = 0; iy < height; iy++) {\ + y = (TYPE)iy - y1;\ + for (ix = 0; ix < width; ix++) {\ + x = (TYPE)ix - x1;\ + v = atan2(y, x);\ + if (anticlockwise)\ + v = 1 - v;\ + v -= u;\ + v += 4 * (TYPE)M_PI;\ + v = mod(v, 2 * (TYPE)M_PI);\ + r = sqrt(x * x + y * y);\ + r -= a;\ + if (!logarithmic) {\ + r = pow(r / b, ep);\ + r = (r - v) / (2 * (TYPE)M_PI);\ + } else if (r) {\ + r = log(r / k);\ + r = pow(r / b, ep);\ + r = (r - v) / (2 * (TYPE)M_PI);\ + }\ + buf[ptr][0] = buf[ptr][1] = buf[ptr][2] = buf[ptr][3] = r;\ + if (++ptr == ELEMENTSOF(buf)) {\ + ewriteall(STDOUT_FILENO, buf, sizeof(buf), "<stdout>");\ + ptr = 0;\ + }\ + }\ + }\ + }\ + } + +PROCESS(double, lf) +PROCESS(float, f) + + +int +main(int argc, char *argv[]) +{ + struct stream stream; + void (*process)(struct stream *stream); + + ARGBEGIN { + case 'a': + anticlockwise = 1; + break; + case 'l': + logarithmic = 1; + break; + case 'w': + width = etozu_flag('w', UARGF(), 1, SIZE_MAX); + break; + case 'h': + height = etozu_flag('h', UARGF(), 1, SIZE_MAX); + break; + default: + usage(); + } ARGEND; + + if (!width || !height || argc) + usage(); + + eopen_stream(&stream, NULL); + + if (!strcmp(stream.pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(stream.pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); + + if (stream.width > 3 || stream.height > 3 || + stream.width * stream.height < 2 || + stream.width * stream.height > 3) + eprintf("<stdin>: each frame must contain exactly 2 or 3 pixels\n"); + + with_params = stream.width * stream.height == 3; + + stream.width = width; + stream.height = height; + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + process(&stream); + return 0; +} diff --git a/src/blind-square-gradient.c b/src/blind-square-gradient.c @@ -0,0 +1,109 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("-w width -h height") + +static size_t width = 0; +static size_t height = 0; +static int with_multiplier; + + +#define PROCESS(TYPE, SUFFIX)\ + static void\ + process_##SUFFIX(struct stream *stream)\ + {\ + typedef TYPE pixel_t[4];\ + pixel_t buf[BUFSIZ / sizeof(pixel_t)];\ + TYPE *params, x1, y1, x2, y2, norm, rd = 1; \ + TYPE x, y, p, r, rx, ry;\ + size_t ix, iy, ptr = 0;\ + for (;;) {\ + while (stream->ptr < stream->frame_size) {\ + if (!eread_stream(stream, stream->frame_size - stream->ptr)) {\ + ewriteall(STDOUT_FILENO, buf, ptr * sizeof(*buf), "<stdout>");\ + return;\ + }\ + }\ + params = (TYPE *)stream->buf;\ + x1 = (params)[0];\ + y1 = (params)[1];\ + x2 = (params)[4];\ + y2 = (params)[5];\ + if (with_multiplier)\ + rd = (params)[9];\ + memmove(stream->buf, stream->buf + stream->frame_size,\ + stream->ptr -= stream->frame_size);\ + \ + x2 -= x1;\ + y2 -= y1;\ + norm = sqrt(x2 * x2 + y2 * y2);\ + x2 /= norm;\ + y2 /= norm;\ + \ + for (iy = 0; iy < height; iy++) {\ + y = (TYPE)iy - y1;\ + for (ix = 0; ix < width; ix++) {\ + x = (TYPE)ix - x1;\ + p = x * x2 + y * y2;\ + rx = x - p * x2;\ + ry = y - p * y2;\ + r = sqrt(rx * rx + ry * ry) / rd;\ + p = abs(p);\ + x = MAX(p, r) / norm;\ + buf[ptr][0] = buf[ptr][1] = buf[ptr][2] = buf[ptr][3] = x;\ + if (++ptr == ELEMENTSOF(buf)) {\ + ewriteall(STDOUT_FILENO, buf, sizeof(buf), "<stdout>");\ + ptr = 0;\ + }\ + }\ + }\ + }\ + } + +PROCESS(double, lf) +PROCESS(float, f) + + +int +main(int argc, char *argv[]) +{ + struct stream stream; + void (*process)(struct stream *stream); + + ARGBEGIN { + case 'w': + width = etozu_flag('w', UARGF(), 1, SIZE_MAX); + break; + case 'h': + height = etozu_flag('h', UARGF(), 1, SIZE_MAX); + break; + default: + usage(); + } ARGEND; + + if (!width || !height || argc) + usage(); + + eopen_stream(&stream, NULL); + + if (!strcmp(stream.pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(stream.pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); + + if (stream.width > 3 || stream.height > 3 || + stream.width * stream.height < 2 || + stream.width * stream.height > 3) + eprintf("<stdin>: each frame must contain exactly 2 or 3 pixels\n"); + + with_multiplier = stream.width * stream.height == 3; + + stream.width = width; + stream.height = height; + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + process(&stream); + return 0; +} diff --git a/src/blind-triangular-wave.c b/src/blind-triangular-wave.c @@ -0,0 +1,101 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-es]") + +static int equal = 0; +static int spiral = 0; + + +#define PROCESS(TYPE, SUFFIX)\ + static void\ + process_##SUFFIX(struct stream *stream)\ + {\ + size_t i, n;\ + TYPE x, y, z, a;\ + do {\ + n = stream->ptr / stream->pixel_size;\ + if (equal) {\ + for (i = 0; i < n; i++) {\ + a = ((TYPE *)(stream->buf))[4 * i + 3];\ + a = posmod(a, (TYPE)2);\ + a = a > 1 ? 2 - a : a;\ + if (spiral)\ + a = (a > 0.5 ? 1 - a : a) * 2;\ + ((TYPE *)(stream->buf))[4 * i + 0] = a;\ + ((TYPE *)(stream->buf))[4 * i + 1] = a;\ + ((TYPE *)(stream->buf))[4 * i + 2] = a;\ + ((TYPE *)(stream->buf))[4 * i + 3] = a;\ + }\ + } else {\ + for (i = 0; i < n; i++) {\ + x = ((TYPE *)(stream->buf))[4 * i + 0];\ + y = ((TYPE *)(stream->buf))[4 * i + 1];\ + z = ((TYPE *)(stream->buf))[4 * i + 2];\ + a = ((TYPE *)(stream->buf))[4 * i + 3];\ + x = posmod(x, (TYPE)2);\ + y = posmod(y, (TYPE)2);\ + z = posmod(z, (TYPE)2);\ + a = posmod(a, (TYPE)2);\ + x = x > 1 ? 2 - x : x;\ + y = y > 1 ? 2 - y : y;\ + z = z > 1 ? 2 - z : z;\ + a = a > 1 ? 2 - a : a;\ + if (spiral) {\ + x = (x > 0.5 ? 1 - x : x) * 2;\ + y = (y > 0.5 ? 1 - y : y) * 2;\ + z = (z > 0.5 ? 1 - z : z) * 2;\ + a = (a > 0.5 ? 1 - a : a) * 2;\ + }\ + ((TYPE *)(stream->buf))[4 * i + 0] = x;\ + ((TYPE *)(stream->buf))[4 * i + 1] = y;\ + ((TYPE *)(stream->buf))[4 * i + 2] = z;\ + ((TYPE *)(stream->buf))[4 * i + 3] = a;\ + }\ + }\ + n *= stream->pixel_size;\ + ewriteall(STDOUT_FILENO, stream->buf, n, "<stdout>");\ + memmove(stream->buf, stream->buf + n, stream->ptr -= n);\ + } while (eread_stream(stream, SIZE_MAX));\ + if (stream->ptr)\ + eprintf("%s: incomplete frame\n", stream->file);\ + } + +PROCESS(double, lf) +PROCESS(float, f) + + +int +main(int argc, char *argv[]) +{ + struct stream stream; + void (*process)(struct stream *stream); + + ARGBEGIN { + case 'e': + equal = 1; + break; + case 's': + spiral = 1; + break; + default: + usage(); + } ARGEND; + + if (argc) + usage(); + + eopen_stream(&stream, NULL); + + if (!strcmp(stream.pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(stream.pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); + + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + process(&stream); + return 0; +} diff --git a/src/video-math.h b/src/video-math.h @@ -59,6 +59,7 @@ posmodf(float a, float b) #define pow(...) MATH_GENERIC_N(pow, __VA_ARGS__) #define log2(...) MATH_GENERIC_1(log2, __VA_ARGS__) +#define log(...) MATH_GENERIC_1(log, __VA_ARGS__) #define abs(...) MATH_GENERIC_1(fabs, __VA_ARGS__) #define sqrt(...) MATH_GENERIC_1(sqrt, __VA_ARGS__) #define exp(...) MATH_GENERIC_1(exp, __VA_ARGS__) @@ -68,6 +69,9 @@ posmodf(float a, float b) #define nnpow(...) MATH_GENERIC_N(nnpow, __VA_ARGS__) #define mod(...) MATH_GENERIC_N(fmod, __VA_ARGS__) #define posmod(...) MATH_GENERIC_N(posmod, __VA_ARGS__) +#define cos(...) MATH_GENERIC_1(cos, __VA_ARGS__) +#define sin(...) MATH_GENERIC_1(sin, __VA_ARGS__) +#define atan2(...) MATH_GENERIC_N(atan2, __VA_ARGS__) #define srgb_encode(...) BLIND_GENERIC_1(srgb_encode, __VA_ARGS__) #define srgb_decode(...) BLIND_GENERIC_1(srgb_decode, __VA_ARGS__)