/
additive.ts
70 lines (69 loc) · 1.68 KB
/
additive.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import type { Fn } from "@thi.ng/api";
import {
add,
assign,
defn,
float,
FLOAT0,
FLOAT05,
FloatSym,
FloatTerm,
forLoop,
inc,
lt,
mul,
Prim,
ret,
sym,
Term,
} from "@thi.ng/shader-ast";
/**
* Higher order function. Takes an AST type ID, a single-arg scalar
* function `fn`, number of octaves (default: 4) and an optional
* function name. Returns a new function which computes the summed value
* of `fn` over the given number octaves and accepts 3 args:
*
* - position (float)
* - octave shift (float)
* - octave decay (usually 0.5)
*
* For each octave `i` [0..oct), the function is (in principle)
* evaluated as:
*
* n += decay / exp2(i) * fn(pos * exp2(i) + i * shift)
*
* @param fn -
* @param oct -
* @param name -
*/
export const additive = <T extends Prim>(
type: T,
fn: Fn<Term<T>, FloatTerm>,
oct: number | FloatTerm = 4,
name = "additive"
) =>
defn("float", name, [[type], [type], "float"], (pos, shift, decay) => {
let n: FloatSym;
let amp: FloatSym;
return [
(n = sym(FLOAT0)),
(amp = sym(FLOAT05)),
forLoop(
sym(float(0)),
(i) => lt(i, float(oct)),
inc,
(i) => [
assign(
n,
add(
n,
mul(amp, fn(<any>add(<any>pos, mul(i, <any>shift))))
)
),
assign(amp, mul(amp, decay)),
assign(pos, <any>mul(<any>pos, 2)),
]
),
ret(n),
];
});