## -*- mode: tcl ; fill-column: 90 -*-
# # ## ### ##### ######## ############# #####################
## Image transformer - Binary math (pixel wise)
# # ## ### ##### ######## ############# #####################
## Highlevel operations implemented on top of the C core
operator op::math::difference {
section transform math binary
note Returns image holding the absolute difference `abs(A-B)` of the inputs.
input a Image A
input b Image B
body {
return [aktive op math1 abs [sub $a $b]]
}
}
operator op::math::screen {
section transform math binary
note Returns image holding the `screen(A,B) = A+B-A*B = A*(1-B)+B` of the inputs.
input a Image A
input b Image B
body {
# (a+b)-ab = a-ab+b = a(1-b)+b
return [sub [add $a $b] [mul $a $b]]
}
}
# # ## ### ##### ######## ############# #####################
## Binary without parameters
proc logical {} { ::return {
op::math::nand
op::math::and
op::math::or
op::math::nor
op::math::xor
}}
operator { cfunction vfunction dexpr} {
op::math::nand aktive_nand nand {!(A && B)}
op::math::nor aktive_nor nor {!(A || B)}
op::math::atan2 atan2 atan2 {atan2(A, B)}
op::math::div aktive_div div {A / B}
op::math::eq aktive_eq eq {A == B}
op::math::ge aktive_ge ge {A >= B}
op::math::gt aktive_gt gt {A > B}
op::math::hypot hypot hypot {hypot (A, B)}
op::math::le aktive_le le {A <= B}
op::math::lt aktive_lt lt {A < B}
op::math::mod fmod fmod {A % B}
op::math::ne aktive_ne ne {A != B}
op::math::pow pow pow {pow (A, B)}
op::math::sub aktive_sub sub {A - B}
} {
op -> _ _ fun
note Returns image with the binary operation `${dexpr}` applied to \
all shared pixels of the two inputs.
note The result geometry is the intersection of the inputs.
if {$__op in [logical]} {
section transform math binary logical
note As a logical operation the inputs are trivially thresholded at 0.5. \
Values <= 0.5 are seen as false, else as true.
} else {
section transform math binary
}
input a Image A
input b Image B
blit binary {
{AH {y AY 1 up} {y 0 1 up} {y 0 1 up}}
{AW*DD {xz AX 1 up} {xz 0 1 up} {xz 0 1 up}}
} vec/binary/$vfunction
state -setup {
aktive_geometry* a = aktive_image_get_geometry (srcs->v[0]);
aktive_geometry* b = aktive_image_get_geometry (srcs->v[1]);
aktive_rectangle_intersect (aktive_geometry_as_rectangle (domain),
aktive_geometry_as_rectangle (a),
aktive_geometry_as_rectangle (b));
domain->depth = MIN (a->depth, b->depth);
}
pixels {
// As the result geometry is the intersection of the inputs
// we trivially know that the request is good for both inputs.
aktive_block* src0 = aktive_region_fetch_area (0, request);
aktive_block* src1 = aktive_region_fetch_area (1, request);
if ((block->domain.depth != src0->domain.depth) ||
(block->domain.depth != src1->domain.depth)) {
// mismatching depths -> xz-folding not possible - fall back to base form
aktive_blit_binary (block, dst, @@cfunction@@, src0, src1);
} else {
// all depths matching -> fold x/z, and vector functions
#define AH (dst->height)
#define AW (dst->width)
#define AX (dst->x)
#define AY (dst->y)
#define DD (block->domain.depth)
#define DH (block->domain.height)
#define DST (block->pixel)
#define DSTCAP (block->used)
#define DW (block->domain.width)
#define S0D (src0->domain.depth)
#define S0H (src0->domain.height)
#define SRC0 (src0->pixel)
#define SRC0CAP (src0->used)
#define S0W (src0->domain.width)
#define S1D (src1->domain.depth)
#define S1H (src1->domain.height)
#define SRC1 (src1->pixel)
#define SRC1CAP (src1->used)
#define S1W (src1->domain.width)
@@binary@@
}
}
}
# # ## ### ##### ######## ############# #####################
## Multi-ary operations of commutative any-associative binary ops
operator {cfunction dexpr} {
op::math::and aktive_and {A && B}
op::math::or aktive_or {A || B}
op::math::xor aktive_xor {A ^^ B}
op::math::add aktive_add {A + B}
op::math::mul aktive_mul {A * B}
op::math::max fmax {max(A, B)}
op::math::min fmin {min(A, B)}
} {
op -> _ _ fun
if {$__op in [logical]} {
section transform math n-ary logical
note As a logical operation the inputs are trivially thresholded at 0.5. \
Values <= 0.5 are seen as `false`, else as `true`.
} else {
section transform math n-ary
}
input...
note Returns image aggregated from the application of the associative \
binary operation `${dexpr}` to all shared pixels of all the inputs.
note Expects 2 or more input images. Throws an error if there are less.
# A single input is accepted, and passed unchanged
simplify for call/arity == 1 returns first
state -setup {
if (srcs->c < 1) aktive_fail ("not enough inputs, expected 2 or more");
aktive_uint i;
aktive_geometry* g = aktive_image_get_geometry (srcs->v[0]);
aktive_geometry_copy (domain, g);
domain->depth = MIN (domain->depth, g->depth);
for (i = 1; i < srcs->c; i++) {
g = aktive_image_get_geometry (srcs->v[i]);
aktive_rectangle_intersect (aktive_geometry_as_rectangle (domain),
aktive_geometry_as_rectangle (domain),
aktive_geometry_as_rectangle (g));
domain->depth = MIN (domain->depth, g->depth);
}
}
pixels {
// As the result geometry is the intersection of all inputs
// we trivially know that the request is good for all inputs.
aktive_uint i;
aktive_blit_copy0 (block, dst, aktive_region_fetch_area (0, request));
for (i = 1; i < srcs->c; i++) {
aktive_blit_binary_acc (block, dst, @@cfunction@@,
aktive_region_fetch_area (i, request));
}
}
}
##
# # ## ### ##### ######## ############# #####################
::return
|