commit 4dfdb29707bf7af8df1fae28907d5e492338e8b8
parent f9adfc4c7c21dc0526c0d13285e41f4292176378
Author: Mattias Andrée <maandree@kth.se>
Date: Sun, 2 Jul 2017 16:59:44 +0200
Add blind-{,un}premultiply, blind-{dot,cross,quaternion}-product, and blind-vector-projection
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat:
17 files changed, 673 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -11,10 +11,12 @@ BIN =\
blind-concat\
blind-convert\
blind-crop\
+ blind-cross-product\
blind-cut\
blind-decompress\
blind-disperse\
blind-dissolve\
+ blind-dot-product\
blind-extend\
blind-find-rectangle\
blind-flip\
@@ -29,6 +31,8 @@ BIN =\
blind-invert-luma\
blind-make-kernel\
blind-next-frame\
+ blind-quaternion-product\
+ blind-premultiply\
blind-read-head\
blind-repeat\
blind-reverse\
@@ -51,6 +55,8 @@ BIN =\
blind-to-video\
blind-translate\
blind-transpose\
+ blind-unpremultiply\
+ blind-vector-projection\
blind-write-head\
blind-kernel\
blind-temporal-mean
diff --git a/README b/README
@@ -33,12 +33,18 @@ UTILITIES
blind-convert(1)
Change pixel format of a video
+ blind-cross-product(1)
+ Calculate the cross product of colours in a video
+
blind-crop(1)
Extract subframes for all frames
blind-cut(1)
Retain consecutive frames
+ blind-dot-product(1)
+ Calculate the dot product of colours in a video
+
blind-dissolve(1)
Fade a video by chaning it's alpha channel
@@ -87,6 +93,12 @@ UTILITIES
blind-next-frame(1)
Extracts the next frame from a video
+ blind-premultiply(1)
+ Premultiply the alpha channel of a video
+
+ blind-quaternion-product(1)
+ Calculate the quaternion product of colours in a video
+
blind-read-head(1)
Reads the head from a video
@@ -162,6 +174,12 @@ UTILITIES
blind-transpose(1)
Transpose a video
+ blind-unpremultiply(1)
+ Unpremultiply the alpha channel of a video
+
+ blind-vector-projection(1)
+ Calculate the projection or rejection of colours in a video
+
blind-write-head(1)
Writes the head of a video
diff --git a/TODO b/TODO
@@ -64,6 +64,13 @@ long double (xyza q) could be added as another format.
unsigned char (xyza 8) could be added as another format, it's probably good for previewing
+UNTESTED:
+ blind-dot-product
+ blind-cross-product
+ blind-quaternion-product
+ blind-vector-projection
+
+
HELP REQUIRED:
blind-z-map create a Z-map video from two or more videos
blind-track track the movement of a point
diff --git a/man/blind-arithm.1 b/man/blind-arithm.1
@@ -77,6 +77,10 @@ Do not modify the Y channel (the second channel).
Do not modify the Z channel (the third channel).
.SH SEE ALSO
.BR blind (7),
+.BR blind-dot-product (1),
+.BR blind-cross-product (1),
+.BR blind-quaternion-product (1),
+.BR blind-vector-projection (1),
.BR blind-single-colour (1),
.BR blind-set-alpha (1),
.BR blind-set-luma (1),
diff --git a/man/blind-cross-product.1 b/man/blind-cross-product.1
@@ -0,0 +1,32 @@
+.TH BLIND-CROSS-PRODUCT 1 blind
+.SH NAME
+blind-cross-product - Calculate the cross product of colours in a video
+.SH SYNOPSIS
+.B blind-cross-product
+.I right-hand-stream
+.SH DESCRIPTION
+.B blind-cross-product
+reads left-hand operands from stdin, and right-hand
+operands from
+.IR right-hand-stream ,
+and calculates the cross product of the colours.
+The values of the alpha channels multiple with each
+others with regular scalar-scalar multiplication.
+.P
+If stdin is longer than
+.IR right-hand-stream ,
+the remainder of stdin is printed without any changes.
+If stdin is shorter than
+.IR right-hand-stream ,
+the remainder of
+.I right-hand-stream
+is ignored but may be partially read.
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-arithm (1),
+.BR blind-dot-product (1),
+.BR blind-quaternion-product (1),
+.BR blind-vector-projection (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree@kth.se >
diff --git a/man/blind-dot-product.1 b/man/blind-dot-product.1
@@ -0,0 +1,31 @@
+.TH BLIND-DOT-PRODUCT 1 blind
+.SH NAME
+blind-dot-product - Calculate the dot product of colours in a video
+.SH SYNOPSIS
+.B blind-dot-product
+.I right-hand-stream
+.SH DESCRIPTION
+.B blind-dot-product
+reads left-hand operands from stdin, and right-hand
+operands from
+.IR right-hand-stream ,
+and calculates the dot product of the colours. The
+product is store in all four channels.
+.P
+If stdin is longer than
+.IR right-hand-stream ,
+the remainder of stdin is printed without any changes.
+If stdin is shorter than
+.IR right-hand-stream ,
+the remainder of
+.I right-hand-stream
+is ignored but may be partially read.
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-arithm (1),
+.BR blind-cross-product (1),
+.BR blind-quaternion-product (1),
+.BR blind-vector-projection (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree@kth.se >
diff --git a/man/blind-premultiply.1 b/man/blind-premultiply.1
@@ -0,0 +1,27 @@
+.TH BLIND-PREMULTIPLY 1 blind
+.SH NAME
+blind-premultiply - Premultiply the alpha channel of a video
+.SH SYNOPSIS
+.B blind-premultiply
+[-xyz]
+.SH DESCRIPTION
+.B blind-premultiply
+reads a video from stdin and multiplies the
+colour values with the alpha value for each pixel,
+and prints the resulting video to stdout.
+.SH OPTIONS
+.TP
+.B -x
+Do not modify the X channel (the first channel).
+.TP
+.B -y
+Do not modify the Y channel (the second channel).
+.TP
+.B -z
+Do not modify the Z channel (the third channel).
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-unpremultiply (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree@kth.se >
diff --git a/man/blind-quaternion-product.1 b/man/blind-quaternion-product.1
@@ -0,0 +1,36 @@
+.TH BLIND-QUATERNION-PRODUCT 1 blind
+.SH NAME
+blind-quaternion-product - Calculate the quaternion product of colours in a video
+.SH SYNOPSIS
+.B blind-quaternion-product
+.I right-hand-stream
+.SH DESCRIPTION
+.B blind-quaternion-product
+reads left-hand operands from stdin, and right-hand
+operands from
+.IR right-hand-stream ,
+and calculates the quaternion product of the colours.
+The values in the the first channel (the X channel) are
+treated as real, the values in the the second channel
+(the Y channel) are treated as i-imaginary, the values
+in the the third channel (the Z channel) are treated
+as j-imaginary, and the values in the the fourth channel
+(the alpha channel) are treated as k-imaginary.
+.P
+If stdin is longer than
+.IR right-hand-stream ,
+the remainder of stdin is printed without any changes.
+If stdin is shorter than
+.IR right-hand-stream ,
+the remainder of
+.I right-hand-stream
+is ignored but may be partially read.
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-arithm (1),
+.BR blind-cross-product (1),
+.BR blind-quaternion-product (1),
+.BR blind-vector-projection (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree@kth.se >
diff --git a/man/blind-unpremultiply.1 b/man/blind-unpremultiply.1
@@ -0,0 +1,29 @@
+.TH BLIND-UNPREMULTIPLY 1 blind
+.SH NAME
+blind-unpremultiply - Unpremultiply the alpha channel of a video
+.SH SYNOPSIS
+.B blind-unpremultiply
+[-xyz]
+.SH DESCRIPTION
+.B blind-unpremultiply
+reads a video from stdin and divides the colour
+with the alpha value for each pixel, and prints
+the resulting video to stdout, effectively
+undoing affects of
+.BR blind-unpremultiply (1).
+.SH OPTIONS
+.TP
+.B -x
+Do not modify the X channel (the first channel).
+.TP
+.B -y
+Do not modify the Y channel (the second channel).
+.TP
+.B -z
+Do not modify the Z channel (the third channel).
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-premultiply (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree@kth.se >
diff --git a/man/blind-vector-projection.1 b/man/blind-vector-projection.1
@@ -0,0 +1,41 @@
+.TH BLIND-VECTOR-PROJECTION 1 blind
+.SH NAME
+blind-vector-projection - Calculate the projection or rejection of colours in a video
+.SH SYNOPSIS
+.B blind-vector-projection
+[-r | -s]
+.I plane-stream
+.SH DESCRIPTION
+.B blind-vector-projection
+reads a video from stdin and a video from
+.IR plane-stream ,
+and calculates the projection of the colours from
+stdin onto the colours from
+.I plane-stream
+and prints the resulting video to stdout.
+.P
+If stdin is longer than
+.IR plane-stream ,
+the remainder of stdin is printed without any changes.
+If stdin is shorter than
+.IR plane-stream ,
+the remainder of
+.I plane-stream
+is ignored but may be partially read.
+.SH OPTIONS
+.TP
+.B -r
+Calculate the vector rejection instead of the vector projection.
+.TP
+.B -s
+Calculate the scalar projection instead of the vector projection.
+The scalar projection is stored in all four channels.
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-arithm (1),
+.BR blind-dot-product (1),
+.BR blind-cross-product (1),
+.BR blind-quaternion-product (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree@kth.se >
diff --git a/man/blind.7 b/man/blind.7
@@ -43,6 +43,9 @@ Concatenate videos
.BR blind-convert (1)
Change pixel format of a video
.TP
+.BR blind-cross-product (1)
+Calculate the cross product of colours in a video
+.TP
.BR blind-crop (1)
Extract subframes for all frames
.TP
@@ -58,6 +61,9 @@ Fade a video by chaning it's alpha channel
.BR blind-disperse (1)
Framewise split a video into multiple videos
.TP
+.BR blind-dot-product (1)
+Calculate the dot product of colours in a video
+.TP
.BR blind-extend (1)
Add margins to a video
.TP
@@ -100,6 +106,12 @@ Create a custom convolution matrix
.BR blind-next-frame (1)
Extracts the next frame from a video
.TP
+.BR blind-premultiply (1)
+Premultiply the alpha channel of a video
+.TP
+.BR blind-quaternion-product (1)
+Calculate the quaternion product of colours in a video
+.TP
.BR blind-read-head (1)
Reads the head from a video
.TP
@@ -177,6 +189,12 @@ Perform framewise translation of a video
.BR blind-transpose (1)
Transpose a video
.TP
+.BR blind-unpremultiply (1)
+Unpremultiply the alpha channel of a video
+.TP
+.BR blind-vector-projection (1)
+Calculate the projection or rejection of colours in a video
+.TP
.BR blind-write-head (1)
Writes the head of a video
.SH SEE ALSO
diff --git a/src/blind-cross-product.c b/src/blind-cross-product.c
@@ -0,0 +1,62 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("right-hand-stream")
+
+#if defined(__GNUC__) && !defined(__clang__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
+#endif
+
+#define PROCESS(TYPE, SUFFIX)\
+ static void\
+ process_##SUFFIX(struct stream *left, struct stream *right, size_t n)\
+ {\
+ size_t i;\
+ TYPE *lx, *ly, *lz, *la, *rx, *ry, *rz, *ra, x, y, z, a;\
+ for (i = 0; i < n; i += 4 * sizeof(TYPE)) {\
+ lx = ((TYPE *)(left->buf + i)) + 0, rx = ((TYPE *)(right->buf + i)) + 0;\
+ ly = ((TYPE *)(left->buf + i)) + 1, ry = ((TYPE *)(right->buf + i)) + 1;\
+ lz = ((TYPE *)(left->buf + i)) + 2, rz = ((TYPE *)(right->buf + i)) + 2;\
+ la = ((TYPE *)(left->buf + i)) + 3, ra = ((TYPE *)(right->buf + i)) + 3;\
+ x = *ly * *rz - *lz * *ry;\
+ y = *lz * *rx - *lx * *rz;\
+ z = *lx * *ry - *ly * *rx;\
+ a = *la * *ra;\
+ *lx = x;\
+ *ly = y;\
+ *lz = z;\
+ *la = a;\
+ }\
+ }
+
+PROCESS(double, lf)
+PROCESS(float, f)
+
+#if defined(__GNUC__) && !defined(__clang__)
+# pragma GCC diagnostic pop
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ struct stream left, right;
+ void (*process)(struct stream *left, struct stream *right, size_t n);
+
+ UNOFLAGS(argc != 2);
+
+ eopen_stream(&left, NULL);
+ eopen_stream(&right, argv[1]);
+
+ if (!strcmp(left.pixfmt, "xyza"))
+ process = process_lf;
+ else if (!strcmp(left.pixfmt, "xyza f"))
+ process = process_f;
+ else
+ eprintf("pixel format %s is not supported, try xyza\n", left.pixfmt);
+
+ fprint_stream_head(stdout, &left);
+ efflush(stdout, "<stdout>");
+ process_two_streams(&left, &right, STDOUT_FILENO, "<stdout>", process);
+ return 0;
+}
diff --git a/src/blind-dot-product.c b/src/blind-dot-product.c
@@ -0,0 +1,55 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("right-hand-stream")
+
+#if defined(__GNUC__) && !defined(__clang__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
+#endif
+
+#define PROCESS(TYPE, SUFFIX)\
+ static void\
+ process_##SUFFIX(struct stream *left, struct stream *right, size_t n)\
+ {\
+ size_t i;\
+ TYPE *lx, *ly, *lz, *la, *rx, *ry, *rz, *ra;\
+ for (i = 0; i < n; i += 4 * sizeof(TYPE)) {\
+ lx = ((TYPE *)(left->buf + i)) + 0, rx = ((TYPE *)(right->buf + i)) + 0;\
+ ly = ((TYPE *)(left->buf + i)) + 1, ry = ((TYPE *)(right->buf + i)) + 1;\
+ lz = ((TYPE *)(left->buf + i)) + 2, rz = ((TYPE *)(right->buf + i)) + 2;\
+ la = ((TYPE *)(left->buf + i)) + 3, ra = ((TYPE *)(right->buf + i)) + 3;\
+ *lx = *ly = *lz = *la = *lx * *rx + *ly * *ry + *lz * *rz + *la * *ra;\
+ }\
+ }
+
+PROCESS(double, lf)
+PROCESS(float, f)
+
+#if defined(__GNUC__) && !defined(__clang__)
+# pragma GCC diagnostic pop
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ struct stream left, right;
+ void (*process)(struct stream *left, struct stream *right, size_t n);
+
+ UNOFLAGS(argc != 2);
+
+ eopen_stream(&left, NULL);
+ eopen_stream(&right, argv[1]);
+
+ if (!strcmp(left.pixfmt, "xyza"))
+ process = process_lf;
+ else if (!strcmp(left.pixfmt, "xyza f"))
+ process = process_f;
+ else
+ eprintf("pixel format %s is not supported, try xyza\n", left.pixfmt);
+
+ fprint_stream_head(stdout, &left);
+ efflush(stdout, "<stdout>");
+ process_two_streams(&left, &right, STDOUT_FILENO, "<stdout>", process);
+ return 0;
+}
diff --git a/src/blind-premultiply.c b/src/blind-premultiply.c
@@ -0,0 +1,76 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-xyz]")
+
+static int skip_x = 0;
+static int skip_y = 0;
+static int skip_z = 0;
+
+
+#define PROCESS(TYPE, SUFFIX)\
+ static void\
+ process_##SUFFIX(struct stream *stream)\
+ {\
+ size_t i, n;\
+ TYPE a;\
+ do {\
+ n = stream->ptr / stream->pixel_size;\
+ for (i = 0; i < n; i++) {\
+ a = ((TYPE *)(stream->buf))[4 * i + 3];\
+ if (!skip_x)\
+ ((TYPE *)(stream->buf))[4 * i + 0] *= a;\
+ if (!skip_y)\
+ ((TYPE *)(stream->buf))[4 * i + 1] *= a;\
+ if (!skip_z)\
+ ((TYPE *)(stream->buf))[4 * i + 2] *= 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 'x':
+ skip_x = 1;
+ break;
+ case 'y':
+ skip_y = 1;
+ break;
+ case 'z':
+ skip_z = 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-quaternion-product.c b/src/blind-quaternion-product.c
@@ -0,0 +1,62 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("right-hand-stream")
+
+#if defined(__GNUC__) && !defined(__clang__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
+#endif
+
+#define PROCESS(TYPE, SUFFIX)\
+ static void\
+ process_##SUFFIX(struct stream *left, struct stream *right, size_t n)\
+ {\
+ size_t i;\
+ TYPE *lx, *ly, *lz, *la, *rx, *ry, *rz, *ra, x, y, z, a;\
+ for (i = 0; i < n; i += 4 * sizeof(TYPE)) {\
+ lx = ((TYPE *)(left->buf + i)) + 0, rx = ((TYPE *)(right->buf + i)) + 0;\
+ ly = ((TYPE *)(left->buf + i)) + 1, ry = ((TYPE *)(right->buf + i)) + 1;\
+ lz = ((TYPE *)(left->buf + i)) + 2, rz = ((TYPE *)(right->buf + i)) + 2;\
+ la = ((TYPE *)(left->buf + i)) + 3, ra = ((TYPE *)(right->buf + i)) + 3;\
+ x = *lx * *rx - *ly * *ry - *lz * *rz - *la * *ra;\
+ y = *lz * *ra - *la * *rz + *lx * *ry + *ly * *rx;\
+ z = *la * *ry - *ly * *rz + *lx * *rz + *lz * *rx;\
+ a = *ly * *rz - *lz * *rz + *lx * *ra + *la * *rx;\
+ *lx = x;\
+ *ly = y;\
+ *lz = z;\
+ *la = a;\
+ }\
+ }
+
+PROCESS(double, lf)
+PROCESS(float, f)
+
+#if defined(__GNUC__) && !defined(__clang__)
+# pragma GCC diagnostic pop
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ struct stream left, right;
+ void (*process)(struct stream *left, struct stream *right, size_t n);
+
+ UNOFLAGS(argc != 2);
+
+ eopen_stream(&left, NULL);
+ eopen_stream(&right, argv[1]);
+
+ if (!strcmp(left.pixfmt, "xyza"))
+ process = process_lf;
+ else if (!strcmp(left.pixfmt, "xyza f"))
+ process = process_f;
+ else
+ eprintf("pixel format %s is not supported, try xyza\n", left.pixfmt);
+
+ fprint_stream_head(stdout, &left);
+ efflush(stdout, "<stdout>");
+ process_two_streams(&left, &right, STDOUT_FILENO, "<stdout>", process);
+ return 0;
+}
diff --git a/src/blind-unpremultiply.c b/src/blind-unpremultiply.c
@@ -0,0 +1,78 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-xyz]")
+
+static int skip_x = 0;
+static int skip_y = 0;
+static int skip_z = 0;
+
+
+#define PROCESS(TYPE, SUFFIX)\
+ static void\
+ process_##SUFFIX(struct stream *stream)\
+ {\
+ size_t i, n;\
+ TYPE a;\
+ do {\
+ n = stream->ptr / stream->pixel_size;\
+ for (i = 0; i < n; i++) {\
+ a = ((TYPE *)(stream->buf))[4 * i + 3];\
+ if (!a)\
+ continue;\
+ if (!skip_x)\
+ ((TYPE *)(stream->buf))[4 * i + 0] /= a;\
+ if (!skip_y)\
+ ((TYPE *)(stream->buf))[4 * i + 1] /= a;\
+ if (!skip_z)\
+ ((TYPE *)(stream->buf))[4 * i + 2] /= 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 'x':
+ skip_x = 1;
+ break;
+ case 'y':
+ skip_y = 1;
+ break;
+ case 'z':
+ skip_z = 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-vector-projection.c b/src/blind-vector-projection.c
@@ -0,0 +1,91 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-r | -s] plane-stream")
+
+static int level = 1;
+
+#if defined(__GNUC__) && !defined(__clang__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations"
+#endif
+
+#define PROCESS(TYPE, SUFFIX)\
+ static void\
+ process_##SUFFIX(struct stream *left, struct stream *right, size_t n)\
+ {\
+ size_t i;\
+ TYPE *lx, *ly, *lz, *la, rx, ry, rz, ra, x, y, z, a, norm;\
+ for (i = 0; i < n; i += 4 * sizeof(TYPE)) {\
+ lx = ((TYPE *)(left->buf + i)) + 0, rx = ((TYPE *)(right->buf + i))[0];\
+ ly = ((TYPE *)(left->buf + i)) + 1, ry = ((TYPE *)(right->buf + i))[1];\
+ lz = ((TYPE *)(left->buf + i)) + 2, rz = ((TYPE *)(right->buf + i))[2];\
+ la = ((TYPE *)(left->buf + i)) + 3, ra = ((TYPE *)(right->buf + i))[3];\
+ norm = rx * rx + ry * ry + rz * rz + ra * ra;\
+ norm = sqrt(norm);\
+ x = y = z = a = *lx * rx + *ly * ry + *lz * rz + *la * ra;\
+ if (level) {\
+ x *= rx;\
+ y *= ry;\
+ z *= rz;\
+ a *= rz;\
+ if (level > 1) {\
+ x = *lx - x;\
+ y = *ly - y;\
+ z = *lz - z;\
+ a = *la - a;\
+ }\
+ }\
+ *lx = x;\
+ *ly = y;\
+ *lz = z;\
+ *la = a;\
+ }\
+ }
+
+PROCESS(double, lf)
+PROCESS(float, f)
+
+#if defined(__GNUC__) && !defined(__clang__)
+# pragma GCC diagnostic pop
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ struct stream left, right;
+ void (*process)(struct stream *left, struct stream *right, size_t n);
+
+ ARGBEGIN {
+ case 'r':
+ if (level == 0)
+ usage();
+ level = 2;
+ break;
+ case 's':
+ if (level == 2)
+ usage();
+ level = 0;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc != 2)
+ usage();
+
+ eopen_stream(&left, NULL);
+ eopen_stream(&right, argv[1]);
+
+ if (!strcmp(left.pixfmt, "xyza"))
+ process = process_lf;
+ else if (!strcmp(left.pixfmt, "xyza f"))
+ process = process_f;
+ else
+ eprintf("pixel format %s is not supported, try xyza\n", left.pixfmt);
+
+ fprint_stream_head(stdout, &left);
+ efflush(stdout, "<stdout>");
+ process_two_streams(&left, &right, STDOUT_FILENO, "<stdout>", process);
+ return 0;
+}