/
rects.ts
108 lines (93 loc) · 2.9 KB
/
rects.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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { Buffer } from "regl";
import { CandyGraph } from "../candygraph";
import { NumberArray } from "../common";
import { Primitive, NamedDrawCommands } from "./primitive";
import { Dataset, createDataset } from "../dataset";
export interface RectsOptions {
/** The color of the rectangles. If this value is a single Vector4, it will apply to all the rectangles. Default [0, 0, 0, 0.5]. */
colors?: NumberArray | Dataset;
}
const DEFAULT_OPTIONS = {
colors: [0, 0, 0, 0.5],
};
interface Props {
position: Buffer;
rect: Buffer;
color: Buffer;
colorDivisor: number;
instances: number;
}
export class Rects extends Primitive {
public readonly rects: Dataset;
public readonly colors: Dataset;
private positionBuffer: Buffer;
/**
* @param rects The x, y position of the lower-left corner of the rectangle
* and its width and height in the form `[x0, y0, w0, h0, x1, y1, w1, h1, ...]`.
*/
constructor(private cg: CandyGraph, rects: NumberArray | Dataset, options: RectsOptions = {}) {
super();
const opts = { ...DEFAULT_OPTIONS, ...options };
this.rects = createDataset(cg, rects);
this.colors = createDataset(cg, opts.colors);
this.positionBuffer = cg.regl.buffer([0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1]);
}
/** @internal */
public commands(glsl: string): NamedDrawCommands {
return {
rects: this.cg.regl({
vert: `
precision highp float;
attribute vec2 position;
attribute vec4 rect;
attribute vec4 color;
varying vec4 vColor;
${glsl}
void main() {
gl_Position = domainToClip(rect.xy + position.xy * rect.zw);
vColor = color;
}`,
frag: `
precision highp float;
varying vec4 vColor;
void main() {
gl_FragColor = vColor;
}`,
attributes: {
position: {
buffer: this.cg.regl.prop<Props, "position">("position"),
divisor: 0,
},
rect: {
buffer: this.cg.regl.prop<Props, "rect">("rect"),
divisor: 1,
},
color: {
buffer: this.cg.regl.prop<Props, "color">("color"),
divisor: this.cg.regl.prop<Props, "colorDivisor">("colorDivisor"),
},
},
count: 6,
instances: this.cg.regl.prop<Props, "instances">("instances"),
}),
};
}
/** @internal */
public render(commands: NamedDrawCommands): void {
const { rects, colors } = this;
const instances = rects.count(4);
commands.rects({
instances,
position: this.positionBuffer,
rect: rects.buffer,
color: colors.buffer,
colorDivisor: colors.divisor(instances, 4),
});
}
/** Releases all GPU resources and renders this instance unusable. */
public dispose(): void {
this.rects.dispose();
this.colors.dispose();
this.positionBuffer.destroy();
}
}