@matboks/utilities 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/dist/constants.d.ts +1 -0
  2. package/dist/constants.js +1 -0
  3. package/dist/geometry/aabb.d.ts +40 -0
  4. package/dist/geometry/aabb.js +143 -0
  5. package/dist/geometry/cut-polygon.d.ts +7 -0
  6. package/dist/geometry/cut-polygon.js +116 -0
  7. package/dist/geometry/hollowgon.d.ts +24 -0
  8. package/dist/geometry/hollowgon.js +156 -0
  9. package/dist/geometry/index.d.ts +13 -0
  10. package/dist/geometry/index.js +14 -0
  11. package/dist/geometry/line.d.ts +10 -0
  12. package/dist/geometry/line.js +26 -0
  13. package/dist/geometry/polygon-operations.d.ts +31 -0
  14. package/dist/geometry/polygon-operations.js +159 -0
  15. package/dist/geometry/polygon.d.ts +55 -0
  16. package/dist/geometry/polygon.js +353 -0
  17. package/dist/geometry/polyline.d.ts +23 -0
  18. package/dist/geometry/polyline.js +100 -0
  19. package/dist/geometry/ray.d.ts +6 -0
  20. package/dist/geometry/ray.js +6 -0
  21. package/dist/geometry/ray3.d.ts +7 -0
  22. package/dist/geometry/ray3.js +10 -0
  23. package/dist/geometry/segment.d.ts +16 -0
  24. package/dist/geometry/segment.js +50 -0
  25. package/dist/geometry/shared.d.ts +5 -0
  26. package/dist/geometry/shared.js +60 -0
  27. package/dist/geometry/transformations.d.ts +7 -0
  28. package/dist/geometry/transformations.js +28 -0
  29. package/dist/geometry/vec2.d.ts +71 -0
  30. package/dist/geometry/vec2.js +225 -0
  31. package/dist/geometry/vec3.d.ts +102 -0
  32. package/dist/geometry/vec3.js +256 -0
  33. package/dist/geometry/vec4.d.ts +71 -0
  34. package/dist/geometry/vec4.js +238 -0
  35. package/dist/index.d.ts +11 -0
  36. package/dist/index.js +11 -0
  37. package/dist/math/clamp.d.ts +1 -0
  38. package/dist/math/clamp.js +5 -0
  39. package/dist/math/fract.d.ts +1 -0
  40. package/dist/math/fract.js +3 -0
  41. package/dist/math/index.d.ts +8 -0
  42. package/dist/math/index.js +8 -0
  43. package/dist/math/mix.d.ts +1 -0
  44. package/dist/math/mix.js +3 -0
  45. package/dist/math/mod.d.ts +1 -0
  46. package/dist/math/mod.js +5 -0
  47. package/dist/math/signed.d.ts +1 -0
  48. package/dist/math/signed.js +3 -0
  49. package/dist/math/smoothstep.d.ts +3 -0
  50. package/dist/math/smoothstep.js +24 -0
  51. package/dist/math/split-into-int-and-fract.d.ts +1 -0
  52. package/dist/math/split-into-int-and-fract.js +5 -0
  53. package/dist/math/units.d.ts +2 -0
  54. package/dist/math/units.js +6 -0
  55. package/dist/noise/idw.d.ts +11 -0
  56. package/dist/noise/idw.js +10 -0
  57. package/dist/noise/index.d.ts +6 -0
  58. package/dist/noise/index.js +6 -0
  59. package/dist/noise/perlin.d.ts +5 -0
  60. package/dist/noise/perlin.js +29 -0
  61. package/dist/noise/random.d.ts +13 -0
  62. package/dist/noise/random.js +39 -0
  63. package/dist/noise/value.d.ts +4 -0
  64. package/dist/noise/value.js +20 -0
  65. package/dist/noise/voronoise.d.ts +10 -0
  66. package/dist/noise/voronoise.js +26 -0
  67. package/dist/noise/worley.d.ts +4 -0
  68. package/dist/noise/worley.js +39 -0
  69. package/dist/shader-modules/index.d.ts +2 -0
  70. package/dist/shader-modules/index.js +2 -0
  71. package/dist/shader-modules/library.d.ts +2 -0
  72. package/dist/shader-modules/library.js +36 -0
  73. package/dist/shader-modules/modules/camera.d.ts +1 -0
  74. package/dist/shader-modules/modules/camera.js +43 -0
  75. package/dist/shader-modules/modules/color/blend.d.ts +1 -0
  76. package/dist/shader-modules/modules/color/blend.js +108 -0
  77. package/dist/shader-modules/modules/color/index.d.ts +1 -0
  78. package/dist/shader-modules/modules/color/index.js +135 -0
  79. package/dist/shader-modules/modules/constants.d.ts +1 -0
  80. package/dist/shader-modules/modules/constants.js +14 -0
  81. package/dist/shader-modules/modules/geometry.d.ts +1 -0
  82. package/dist/shader-modules/modules/geometry.js +110 -0
  83. package/dist/shader-modules/modules/math.d.ts +1 -0
  84. package/dist/shader-modules/modules/math.js +19 -0
  85. package/dist/shader-modules/modules/noise.d.ts +1 -0
  86. package/dist/shader-modules/modules/noise.js +410 -0
  87. package/dist/shader-modules/modules/random.d.ts +1 -0
  88. package/dist/shader-modules/modules/random.js +147 -0
  89. package/dist/shader-modules/modules/ray-marching.d.ts +1 -0
  90. package/dist/shader-modules/modules/ray-marching.js +54 -0
  91. package/dist/shader-modules/modules/sdf/index.d.ts +1 -0
  92. package/dist/shader-modules/modules/sdf/index.js +183 -0
  93. package/dist/shader-modules/modules/sdf/operations.d.ts +1 -0
  94. package/dist/shader-modules/modules/sdf/operations.js +77 -0
  95. package/dist/shader-modules/modules/utils.d.ts +1 -0
  96. package/dist/shader-modules/modules/utils.js +115 -0
  97. package/dist/shader-modules/registry.d.ts +2 -0
  98. package/dist/shader-modules/registry.js +7 -0
  99. package/dist/shader-modules/shaders.d.ts +1 -0
  100. package/dist/shader-modules/shaders.js +109 -0
  101. package/dist/shader-renderer/helpers.d.ts +10 -0
  102. package/dist/shader-renderer/helpers.js +19 -0
  103. package/dist/shader-renderer/index.d.ts +2 -0
  104. package/dist/shader-renderer/index.js +2 -0
  105. package/dist/shader-renderer/pixel-shader.d.ts +32 -0
  106. package/dist/shader-renderer/pixel-shader.js +172 -0
  107. package/dist/shader-renderer/pixel-vertex-shader.d.ts +1 -0
  108. package/dist/shader-renderer/pixel-vertex-shader.js +14 -0
  109. package/dist/shader-renderer/texture.d.ts +28 -0
  110. package/dist/shader-renderer/texture.js +97 -0
  111. package/dist/shader-renderer/types.d.ts +17 -0
  112. package/dist/shader-renderer/types.js +4 -0
  113. package/dist/shader-renderer/uniform.d.ts +16 -0
  114. package/dist/shader-renderer/uniform.js +134 -0
  115. package/dist/tilings/delaunay.d.ts +11 -0
  116. package/dist/tilings/delaunay.js +28 -0
  117. package/dist/tilings/grid.d.ts +5 -0
  118. package/dist/tilings/grid.js +29 -0
  119. package/dist/tilings/hexagononal.d.ts +4 -0
  120. package/dist/tilings/hexagononal.js +40 -0
  121. package/dist/tilings/index.d.ts +12 -0
  122. package/dist/tilings/index.js +12 -0
  123. package/dist/tilings/line.d.ts +5 -0
  124. package/dist/tilings/line.js +19 -0
  125. package/dist/tilings/mediterranean.d.ts +3 -0
  126. package/dist/tilings/mediterranean.js +49 -0
  127. package/dist/tilings/pythagorean.d.ts +3 -0
  128. package/dist/tilings/pythagorean.js +40 -0
  129. package/dist/tilings/random-cuts.d.ts +6 -0
  130. package/dist/tilings/random-cuts.js +16 -0
  131. package/dist/tilings/recursive-cuts.d.ts +5 -0
  132. package/dist/tilings/recursive-cuts.js +11 -0
  133. package/dist/tilings/rhombille.d.ts +3 -0
  134. package/dist/tilings/rhombille.js +16 -0
  135. package/dist/tilings/rightangled-triangle.d.ts +3 -0
  136. package/dist/tilings/rightangled-triangle.js +29 -0
  137. package/dist/tilings/triangle.d.ts +3 -0
  138. package/dist/tilings/triangle.js +17 -0
  139. package/dist/tilings/voronoi.d.ts +11 -0
  140. package/dist/tilings/voronoi.js +29 -0
  141. package/dist/tilings/weaving.d.ts +1 -0
  142. package/dist/tilings/weaving.js +8 -0
  143. package/dist/transforms/camera/camera.d.ts +32 -0
  144. package/dist/transforms/camera/camera.js +60 -0
  145. package/dist/transforms/camera/index.d.ts +3 -0
  146. package/dist/transforms/camera/index.js +3 -0
  147. package/dist/transforms/camera/orthographic.d.ts +15 -0
  148. package/dist/transforms/camera/orthographic.js +31 -0
  149. package/dist/transforms/camera/perspective.d.ts +16 -0
  150. package/dist/transforms/camera/perspective.js +40 -0
  151. package/dist/transforms/index.d.ts +2 -0
  152. package/dist/transforms/index.js +2 -0
  153. package/dist/transforms/normalize-transform.d.ts +12 -0
  154. package/dist/transforms/normalize-transform.js +20 -0
  155. package/dist/types.d.ts +1 -0
  156. package/dist/types.js +1 -0
  157. package/dist/utilities/create-frame.d.ts +2 -0
  158. package/dist/utilities/create-frame.js +6 -0
  159. package/dist/utilities/ensure-array.d.ts +1 -0
  160. package/dist/utilities/ensure-array.js +3 -0
  161. package/dist/utilities/idw-interpolator.d.ts +9 -0
  162. package/dist/utilities/idw-interpolator.js +18 -0
  163. package/dist/utilities/index.d.ts +8 -0
  164. package/dist/utilities/index.js +8 -0
  165. package/dist/utilities/marching-squares.d.ts +51 -0
  166. package/dist/utilities/marching-squares.js +177 -0
  167. package/dist/utilities/point-sampler.d.ts +12 -0
  168. package/dist/utilities/point-sampler.js +24 -0
  169. package/dist/utilities/poisson/grid.d.ts +21 -0
  170. package/dist/utilities/poisson/grid.js +51 -0
  171. package/dist/utilities/poisson/poissonnier.d.ts +50 -0
  172. package/dist/utilities/poisson/poissonnier.js +118 -0
  173. package/dist/utilities/resolution.d.ts +10 -0
  174. package/dist/utilities/resolution.js +14 -0
  175. package/dist/utilities/rng.d.ts +13 -0
  176. package/dist/utilities/rng.js +80 -0
  177. package/package.json +28 -0
@@ -0,0 +1,172 @@
1
+ import { Resolution } from "../utilities/resolution.js";
2
+ import { parseShaderUniforms } from "./helpers.js";
3
+ import { pixelVertexShader } from "./pixel-vertex-shader.js";
4
+ import { ShaderTexture } from "./texture.js";
5
+ import { UniformHandler } from "./uniform.js";
6
+ export class PixelShader {
7
+ constructor(options) {
8
+ this.textures = {};
9
+ this.textureUnitCounter = 0;
10
+ let { fragmentShader, resolution = new Resolution(100, 100), attributes, gl: customGL } = options;
11
+ let canvas;
12
+ let gl;
13
+ let programData;
14
+ if (customGL) {
15
+ canvas = customGL.canvas;
16
+ resolution = new Resolution(canvas.width, canvas.height);
17
+ ({ gl, programData } = setupWebGL(customGL, pixelVertexShader, fragmentShader, attributes));
18
+ }
19
+ else {
20
+ canvas = new OffscreenCanvas(resolution.width, resolution.height);
21
+ ({ gl, programData } = setupWebGL(canvas, pixelVertexShader, fragmentShader, attributes));
22
+ }
23
+ this.resolution = resolution;
24
+ this.canvas = canvas;
25
+ this.gl = gl;
26
+ this.programData = programData;
27
+ this.uniforms = new UniformHandler(gl, programData.uniforms);
28
+ }
29
+ setUniform(...args) {
30
+ this.ensureCurrentProgram();
31
+ let data;
32
+ if (args.length === 2) {
33
+ data = { [args[0]]: args[1] };
34
+ }
35
+ else {
36
+ data = args[0];
37
+ }
38
+ for (const name in data) {
39
+ this.uniforms.setUniform(name, data[name]);
40
+ }
41
+ return this;
42
+ }
43
+ createTexture(name, spec) {
44
+ const tex = new ShaderTexture(this.gl, spec);
45
+ this.textures[name] = tex;
46
+ return tex;
47
+ }
48
+ setTextureData(name, width, height, data) {
49
+ const tex = this.textures[name];
50
+ if (!tex)
51
+ throw new Error(`Texture ${name} not found`);
52
+ tex.setData(width, height, data);
53
+ }
54
+ updateTextureSpec(name, partial) {
55
+ const tex = this.textures[name];
56
+ if (!tex)
57
+ throw new Error(`Texture ${name} not found`);
58
+ tex.updateSpec(partial);
59
+ }
60
+ ensureCurrentProgram() {
61
+ const { program, vao } = this.programData;
62
+ this.gl.useProgram(program);
63
+ this.gl.bindVertexArray(vao);
64
+ }
65
+ render(target) {
66
+ const { gl, programData, textures, resolution: { width, height } } = this;
67
+ gl.viewport(0, 0, width, height);
68
+ gl.clearColor(0, 0, 0, 0);
69
+ gl.clear(gl.COLOR_BUFFER_BIT);
70
+ this.ensureCurrentProgram();
71
+ let unit = 0;
72
+ for (const name in textures) {
73
+ const tex = textures[name];
74
+ const uniform = programData.uniforms[name];
75
+ if (!uniform)
76
+ continue;
77
+ gl.activeTexture(gl.TEXTURE0 + unit);
78
+ gl.bindTexture(gl.TEXTURE_2D, tex.texture);
79
+ gl.uniform1i(uniform.location, unit);
80
+ unit++;
81
+ }
82
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
83
+ let ctx = null;
84
+ if (target instanceof HTMLCanvasElement || target instanceof OffscreenCanvas) {
85
+ ctx = target.getContext("2d");
86
+ }
87
+ else if (target instanceof CanvasRenderingContext2D || target instanceof OffscreenCanvasRenderingContext2D) {
88
+ ctx = target;
89
+ }
90
+ if (ctx) {
91
+ const transform = ctx.getTransform();
92
+ ctx.resetTransform();
93
+ ctx.drawImage(this.canvas, 0, 0);
94
+ ctx.setTransform(transform);
95
+ }
96
+ }
97
+ resize(resolution) {
98
+ const { resolution: currentResolution } = this;
99
+ if (currentResolution.width === resolution.width && currentResolution.height === resolution.height)
100
+ return;
101
+ this.resolution = resolution;
102
+ this.canvas.width = resolution.width;
103
+ this.canvas.height = resolution.height;
104
+ }
105
+ }
106
+ export function setupWebGL(target, vertexShaderDefinition, fragmentShaderDefinition, attributes) {
107
+ let gl;
108
+ if (target instanceof WebGL2RenderingContext) {
109
+ gl = target;
110
+ }
111
+ else {
112
+ gl = target.getContext("webgl2", attributes);
113
+ }
114
+ if (!gl)
115
+ throw new Error("Unable to create WebGL2 context");
116
+ const program = createProgram(gl, vertexShaderDefinition, fragmentShaderDefinition);
117
+ const positionAttribLocation = gl.getAttribLocation(program, "p");
118
+ const positionBuffer = gl.createBuffer();
119
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
120
+ const positionData = new Float32Array([
121
+ 0, 0,
122
+ 1, 0,
123
+ 1, 1,
124
+ 0, 0,
125
+ 1, 1,
126
+ 0, 1
127
+ ]);
128
+ gl.bufferData(gl.ARRAY_BUFFER, positionData, gl.STATIC_DRAW);
129
+ const vao = gl.createVertexArray();
130
+ gl.bindVertexArray(vao);
131
+ gl.enableVertexAttribArray(positionAttribLocation);
132
+ gl.vertexAttribPointer(positionAttribLocation, 2, gl.FLOAT, false, 0, 0);
133
+ gl.useProgram(program);
134
+ const parsedUniforms = parseShaderUniforms(fragmentShaderDefinition);
135
+ const uniformMap = {};
136
+ for (const u of parsedUniforms) {
137
+ const location = gl.getUniformLocation(program, u.name);
138
+ uniformMap[u.name] = { ...u, location };
139
+ }
140
+ const programData = {
141
+ program,
142
+ vao,
143
+ uniforms: uniformMap
144
+ };
145
+ return { gl, programData };
146
+ }
147
+ function createProgram(gl, vertexShaderDefinition, fragmentShaderDefinition) {
148
+ const program = gl.createProgram();
149
+ const vertexShader = createShader(gl, "VERTEX", vertexShaderDefinition);
150
+ const fragmentShader = createShader(gl, "FRAGMENT", fragmentShaderDefinition);
151
+ gl.attachShader(program, vertexShader);
152
+ gl.attachShader(program, fragmentShader);
153
+ gl.linkProgram(program);
154
+ const linkStatus = gl.getProgramParameter(program, gl.LINK_STATUS);
155
+ if (!linkStatus) {
156
+ gl.deleteProgram(program);
157
+ throw new Error(`Error linking program: ${gl.getProgramParameter(program, gl.LINK_STATUS)}`);
158
+ }
159
+ return program;
160
+ }
161
+ function createShader(gl, type, definition) {
162
+ const shader = gl.createShader(gl[`${type}_SHADER`]);
163
+ gl.shaderSource(shader, definition);
164
+ gl.compileShader(shader);
165
+ const compileStatus = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
166
+ if (!compileStatus) {
167
+ const error = gl.getShaderInfoLog(shader);
168
+ gl.deleteShader(shader);
169
+ throw new Error(`Unable to compile ${type}: ${error}`);
170
+ }
171
+ return shader;
172
+ }
@@ -0,0 +1 @@
1
+ export declare const pixelVertexShader: string;
@@ -0,0 +1,14 @@
1
+ export const pixelVertexShader = /*glsl*/ `
2
+ #version 300 es
3
+
4
+ precision highp float;
5
+
6
+ in vec2 p;
7
+ out vec2 uv;
8
+
9
+ void main() {
10
+ uv = p;
11
+ gl_Position = vec4(-1.0 + 2.0*p, 0, 1);
12
+ }
13
+
14
+ `.trim();
@@ -0,0 +1,28 @@
1
+ import { Vec2 } from "../geometry/vec2.js";
2
+ import { Vec3 } from "../geometry/vec3.js";
3
+ import { Vec4 } from "../geometry/vec4.js";
4
+ export type TextureDimension = 1 | 2 | 3 | 4;
5
+ export type TextureDataItem = number | Vec2 | Vec3 | Vec4;
6
+ export type TextureData = Array<TextureDataItem> | TexImageSource;
7
+ export type TextureSpec = {
8
+ dimension: TextureDimension;
9
+ width?: number;
10
+ height?: number;
11
+ filter?: GLenum;
12
+ wrap?: GLenum;
13
+ };
14
+ export declare class ShaderTexture {
15
+ gl: WebGL2RenderingContext;
16
+ texture: WebGLTexture;
17
+ spec: TextureSpec;
18
+ constructor(gl: WebGL2RenderingContext, spec: TextureSpec);
19
+ private createGLTexture;
20
+ /** Update only filtering, wrapping, etc. */
21
+ updateSpec(partial: Partial<TextureSpec>): void;
22
+ /** Uploads data – reallocates if width/height changed */
23
+ setData(width: number, height: number, data: TextureData): void;
24
+ /** Converts Vec2/Vec3/Vec4/number to Float32Array */
25
+ private convertToFlatArray;
26
+ private internalFormat;
27
+ private format;
28
+ }
@@ -0,0 +1,97 @@
1
+ export class ShaderTexture {
2
+ constructor(gl, spec) {
3
+ this.gl = gl;
4
+ this.spec = {
5
+ filter: gl.NEAREST,
6
+ wrap: gl.CLAMP_TO_EDGE,
7
+ width: 20,
8
+ height: 1,
9
+ ...spec,
10
+ };
11
+ this.texture = this.createGLTexture();
12
+ }
13
+ createGLTexture() {
14
+ const { gl } = this;
15
+ const tex = gl.createTexture();
16
+ gl.bindTexture(gl.TEXTURE_2D, tex);
17
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.spec.filter);
18
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.spec.filter);
19
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.spec.wrap);
20
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.spec.wrap);
21
+ // allocate empty storage initially
22
+ const { width, height } = this.spec;
23
+ gl.texImage2D(gl.TEXTURE_2D, 0, this.internalFormat(), width, height, 0, this.format(), gl.FLOAT, null);
24
+ return tex;
25
+ }
26
+ /** Update only filtering, wrapping, etc. */
27
+ updateSpec(partial) {
28
+ Object.assign(this.spec, partial);
29
+ const { gl, texture } = this;
30
+ gl.bindTexture(gl.TEXTURE_2D, texture);
31
+ if (partial.filter !== undefined) {
32
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.spec.filter);
33
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.spec.filter);
34
+ }
35
+ if (partial.wrap !== undefined) {
36
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.spec.wrap);
37
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.spec.wrap);
38
+ }
39
+ }
40
+ /** Uploads data – reallocates if width/height changed */
41
+ setData(width, height, data) {
42
+ const { gl } = this;
43
+ let texData;
44
+ if (Array.isArray(data)) {
45
+ const expectedItems = width * height;
46
+ if (data.length !== expectedItems) {
47
+ throw new Error(`Texture data mismatch: expected ${expectedItems}, got ${data.length}`);
48
+ }
49
+ texData = this.convertToFlatArray(data);
50
+ }
51
+ else {
52
+ texData = data;
53
+ }
54
+ gl.bindTexture(gl.TEXTURE_2D, this.texture);
55
+ const dimensionChanged = width !== this.spec.width || height !== this.spec.height;
56
+ if (dimensionChanged) {
57
+ this.spec.width = width;
58
+ this.spec.height = height;
59
+ gl.texImage2D(gl.TEXTURE_2D, 0, this.internalFormat(), width, height, 0, this.format(), gl.FLOAT, texData);
60
+ }
61
+ else {
62
+ // Faster path when dimension stays constant
63
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, this.format(), gl.FLOAT, texData);
64
+ }
65
+ }
66
+ /** Converts Vec2/Vec3/Vec4/number to Float32Array */
67
+ convertToFlatArray(data) {
68
+ const { dimension } = this.spec;
69
+ let flatData = [];
70
+ if (dimension === 1) {
71
+ flatData = data;
72
+ }
73
+ else {
74
+ for (const item of data)
75
+ flatData.push(...item.toArray());
76
+ }
77
+ return new Float32Array(flatData);
78
+ }
79
+ internalFormat() {
80
+ const gl = this.gl;
81
+ return {
82
+ 1: gl.R32F,
83
+ 2: gl.RG32F,
84
+ 3: gl.RGB32F,
85
+ 4: gl.RGBA32F,
86
+ }[this.spec.dimension];
87
+ }
88
+ format() {
89
+ const gl = this.gl;
90
+ return {
91
+ 1: gl.RED,
92
+ 2: gl.RG,
93
+ 3: gl.RGB,
94
+ 4: gl.RGBA,
95
+ }[this.spec.dimension];
96
+ }
97
+ }
@@ -0,0 +1,17 @@
1
+ import { Vec2 } from "../geometry/vec2.js";
2
+ import { Vec3 } from "../geometry/vec3.js";
3
+ import { Vec4 } from "../geometry/vec4.js";
4
+ import { ParsedUniform } from "./helpers.js";
5
+ export type Uniform = ParsedUniform & {
6
+ location: WebGLUniformLocation;
7
+ };
8
+ export type UniformMap = Record<string, Uniform>;
9
+ export type ProgramData = {
10
+ program: WebGLProgram;
11
+ vao: WebGLVertexArrayObject;
12
+ uniforms: UniformMap;
13
+ };
14
+ export type UniformPrimitive = number | boolean | Vec2 | Vec3 | Vec4 | Array<boolean>;
15
+ export type UniformValue = UniformPrimitive | Array<UniformPrimitive>;
16
+ export type UniformData = Record<string, UniformValue>;
17
+ export declare const vecClasses: readonly [typeof Vec2, typeof Vec3, typeof Vec4];
@@ -0,0 +1,4 @@
1
+ import { Vec2 } from "../geometry/vec2.js";
2
+ import { Vec3 } from "../geometry/vec3.js";
3
+ import { Vec4 } from "../geometry/vec4.js";
4
+ export const vecClasses = [Vec2, Vec3, Vec4];
@@ -0,0 +1,16 @@
1
+ import { UniformMap } from "./types.js";
2
+ export declare class UniformHandler {
3
+ gl: WebGL2RenderingContext;
4
+ uniforms: UniformMap;
5
+ constructor(gl: WebGL2RenderingContext, uniforms: UniformMap);
6
+ setUniform(name: string, value: any): void;
7
+ private throwError;
8
+ private setFloatUniform;
9
+ private setIntUniform;
10
+ private setBoolUniform;
11
+ private setVecUniform;
12
+ private setIVecUniform;
13
+ private setBVecUniform;
14
+ private setMatUniform;
15
+ private processUniformValue;
16
+ }
@@ -0,0 +1,134 @@
1
+ import { vecClasses } from "./types.js";
2
+ export class UniformHandler {
3
+ constructor(gl, uniforms) {
4
+ this.gl = gl;
5
+ this.uniforms = uniforms;
6
+ }
7
+ setUniform(name, value) {
8
+ const uniform = this.uniforms[name];
9
+ if (!uniform)
10
+ throw new Error(`Uniform with name ${name} not found`);
11
+ const processedValue = this.processUniformValue(uniform, value);
12
+ const { type } = uniform;
13
+ if (type === "float") {
14
+ this.setFloatUniform(uniform, processedValue);
15
+ }
16
+ else if (type === "int") {
17
+ this.setIntUniform(uniform, processedValue);
18
+ }
19
+ else if (type === "bool") {
20
+ this.setBoolUniform(uniform, processedValue);
21
+ }
22
+ else if (type.startsWith("vec")) {
23
+ this.setVecUniform(uniform, processedValue);
24
+ }
25
+ else if (type.startsWith("ivec")) {
26
+ this.setIVecUniform(uniform, processedValue);
27
+ }
28
+ else if (type.startsWith("bvec")) {
29
+ this.setBVecUniform(uniform, processedValue);
30
+ }
31
+ else if (type.startsWith("mat")) {
32
+ this.setMatUniform(uniform, processedValue);
33
+ }
34
+ else {
35
+ throw new Error(`Invalid uniform type: ${type}`);
36
+ }
37
+ }
38
+ throwError(uniform, error, value) {
39
+ const { name } = uniform;
40
+ throw new Error(`Error when setting ${name}: ${error} value: ${JSON.stringify(value)}`);
41
+ }
42
+ setFloatUniform(uniform, value) {
43
+ if (value.some((v) => typeof v !== "number"))
44
+ this.throwError(uniform, `not all values are numbers.`, value);
45
+ this.gl.uniform1fv(uniform.location, value);
46
+ }
47
+ setIntUniform(uniform, value) {
48
+ if (!allAreInt(value))
49
+ this.throwError(uniform, `not all values are integers.`, value);
50
+ this.gl.uniform1iv(uniform.location, value);
51
+ }
52
+ setBoolUniform(uniform, value) {
53
+ if (!allAreBool(value))
54
+ this.throwError(uniform, `not all values are booleans.`, value);
55
+ this.gl.uniform1iv(uniform.location, value.map((v) => v ? 1 : 0));
56
+ }
57
+ setVecUniform(uniform, value) {
58
+ if (!allAreVec(value))
59
+ this.throwError(uniform, `not all values are VecN.`, value);
60
+ const array = value
61
+ .map((v) => v.toArray())
62
+ .flat();
63
+ switch (uniform.type) {
64
+ case "vec4": return this.gl.uniform4fv(uniform.location, array);
65
+ case "vec3": return this.gl.uniform3fv(uniform.location, array);
66
+ case "vec2": return this.gl.uniform2fv(uniform.location, array);
67
+ }
68
+ }
69
+ setIVecUniform(uniform, value) {
70
+ if (!allAreVec(value))
71
+ this.throwError(uniform, `not all values are Vec.`, value);
72
+ const array = value.map((v) => v.toArray()).flat();
73
+ if (!allAreInt(array))
74
+ this.throwError(uniform, `not all entries are integers.`, array);
75
+ switch (uniform.type) {
76
+ case "ivec4": return this.gl.uniform4iv(uniform.location, array);
77
+ case "ivec3": return this.gl.uniform3iv(uniform.location, array);
78
+ case "ivec2": return this.gl.uniform2iv(uniform.location, array);
79
+ }
80
+ }
81
+ setBVecUniform(uniform, value) {
82
+ if (!value.every(allAreBool))
83
+ this.throwError(uniform, `not all values are arrays of booleans.`, value);
84
+ const array = value
85
+ .flat()
86
+ .map((v) => v ? 1 : 0);
87
+ switch (uniform.type) {
88
+ case "bvec4": return this.gl.uniform4iv(uniform.location, array);
89
+ case "bvec3": return this.gl.uniform3iv(uniform.location, array);
90
+ case "bvec2": return this.gl.uniform2iv(uniform.location, array);
91
+ }
92
+ }
93
+ setMatUniform(_uniform, _value) {
94
+ throw new Error("Not implemented yet");
95
+ }
96
+ processUniformValue(uniform, value) {
97
+ const { type, isArray } = uniform;
98
+ let wrappedValue = [];
99
+ // Start with types that are arrays of arrays
100
+ if (type.startsWith("bvec") || type.startsWith("mat")) {
101
+ if (isArray) {
102
+ if (!Array.isArray(value) || !Array.isArray(value[0]))
103
+ this.throwError(uniform, `Expected array of arrays.`, value);
104
+ wrappedValue = value;
105
+ }
106
+ else {
107
+ if (Array.isArray(value[0]))
108
+ this.throwError(uniform, `Expected array of values.`, value);
109
+ wrappedValue = [value];
110
+ }
111
+ }
112
+ else {
113
+ if (!isArray && Array.isArray(value))
114
+ this.throwError(uniform, `Expected non-array.`, value);
115
+ wrappedValue = Array.isArray(value) ? value : [value];
116
+ }
117
+ if (isArray) {
118
+ if (!Array.isArray(value))
119
+ this.throwError(uniform, `Array value expected.`, value);
120
+ if (value.length !== uniform.arraySize)
121
+ this.throwError(uniform, `Invalid array length, expected size ${uniform.arraySize}, received ${value.length}`);
122
+ }
123
+ return wrappedValue;
124
+ }
125
+ }
126
+ function allAreVec(value) {
127
+ return value.every((v) => vecClasses.some((C) => v instanceof C));
128
+ }
129
+ function allAreInt(value) {
130
+ return value.every((v) => typeof v === "number" && Math.floor(v) === v);
131
+ }
132
+ function allAreBool(value) {
133
+ return value.every((v) => typeof v === "boolean");
134
+ }
@@ -0,0 +1,11 @@
1
+ import { Polygon } from "../geometry/polygon.js";
2
+ import { RNG } from "../utilities/rng.js";
3
+ import { PointSamplerStrategy } from "../utilities/point-sampler.js";
4
+ import { Hollowgon } from "../geometry/hollowgon.js";
5
+ export type DelaunaySubdivisionOptions = {
6
+ shape: Polygon | Hollowgon;
7
+ numPoints: number;
8
+ rng: RNG;
9
+ strategy?: PointSamplerStrategy;
10
+ };
11
+ export declare function delaunaySubdivision(options: DelaunaySubdivisionOptions): Polygon[];
@@ -0,0 +1,28 @@
1
+ import { Delaunay } from "d3-delaunay";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ import { vec2 } from "../geometry/vec2.js";
4
+ import { pointSampler } from "../utilities/point-sampler.js";
5
+ import { clip } from "../geometry/polygon-operations.js";
6
+ import { Hollowgon } from "../geometry/hollowgon.js";
7
+ export function delaunaySubdivision(options) {
8
+ const { shape, numPoints, rng, strategy = "poisson" } = options;
9
+ const pointBuffer = [];
10
+ for (const { x, y } of pointSampler({ shape, size: numPoints, strategy, rng })) {
11
+ pointBuffer.push(x, y);
12
+ }
13
+ // TODO figure out if there is a way to triangulate directly on polygon with holes
14
+ const vertices = shape instanceof Hollowgon ? shape.boundary.vertices : shape.vertices;
15
+ for (const { x, y } of vertices)
16
+ pointBuffer.push(x, y);
17
+ const delaunay = new Delaunay(pointBuffer);
18
+ let triangles = delaunay.trianglePolygons();
19
+ const polygons = [];
20
+ for (const triangle of triangles) {
21
+ const vertices = [];
22
+ for (const vertex of triangle) {
23
+ vertices.push(vec2(vertex[0], vertex[1]));
24
+ }
25
+ polygons.push(new Polygon(vertices));
26
+ }
27
+ return clip(polygons, shape);
28
+ }
@@ -0,0 +1,5 @@
1
+ import { Hollowgon } from "../geometry/hollowgon.js";
2
+ import { OperationShape } from "../geometry/polygon-operations.js";
3
+ import { Polygon } from "../geometry/polygon.js";
4
+ export declare function gridSubdivision(shape: Polygon, rotation: number, resolution: number): Array<Polygon>;
5
+ export declare function gridSubdivision(shape: Hollowgon, rotation: number, resolution: number): Array<OperationShape>;
@@ -0,0 +1,29 @@
1
+ import { Line } from "../geometry/line.js";
2
+ import { subdivide } from "../geometry/polygon-operations.js";
3
+ import { Vec2, vec2 } from "../geometry/vec2.js";
4
+ export function gridSubdivision(shape, rotation, resolution) {
5
+ const centroid = shape.centroid();
6
+ const { xMin, yMin, width, height, aspectRatio } = shape
7
+ .clone()
8
+ .rotate(-rotation, centroid)
9
+ .aabb();
10
+ const [columns, rows] = aspectRatio > 1 ?
11
+ [Math.round(aspectRatio * resolution), resolution] :
12
+ [resolution, Math.round(resolution / aspectRatio)];
13
+ const columnSpacing = width / columns;
14
+ let polygons = [shape];
15
+ let cutDirection = Vec2.fromPolar(1, Math.PI / 2 + rotation);
16
+ for (let i = 1; i < columns; i++) {
17
+ const point = vec2(xMin + columnSpacing * i, yMin - 1).rotate(rotation, centroid);
18
+ const cutLine = new Line(point, cutDirection);
19
+ polygons = subdivide(polygons, cutLine);
20
+ }
21
+ const rowSpacing = height / rows;
22
+ cutDirection = Vec2.fromPolar(1, rotation);
23
+ for (let i = 1; i < rows; i++) {
24
+ const point = vec2(xMin - 1, yMin + rowSpacing * i).rotate(rotation, centroid);
25
+ const cutLine = new Line(point, cutDirection);
26
+ polygons = subdivide(polygons, cutLine);
27
+ }
28
+ return polygons;
29
+ }
@@ -0,0 +1,4 @@
1
+ import { Hollowgon } from "../geometry/hollowgon.js";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ export declare function hexagonalTiling(shape: Polygon | Hollowgon, rotation: number, resolution: number): Polygon[];
4
+ export declare function hexagonalTileHelper(shape: Polygon | Hollowgon, rotation: number, resolution: number): Polygon[];
@@ -0,0 +1,40 @@
1
+ import { clip } from "../geometry/polygon-operations.js";
2
+ import { Polygon } from "../geometry/polygon.js";
3
+ import { vec2 } from "../geometry/vec2.js";
4
+ const SQRT_3 = Math.sqrt(3);
5
+ export function hexagonalTiling(shape, rotation, resolution) {
6
+ const polygons = hexagonalTileHelper(shape, rotation, resolution);
7
+ for (const polygon of polygons)
8
+ polygon.rotate(rotation, shape.centroid());
9
+ return clip(polygons, shape);
10
+ }
11
+ export function hexagonalTileHelper(shape, rotation, resolution) {
12
+ const { xMin, xMax, yMin, width, height, aspectRatio } = shape
13
+ .clone()
14
+ .rotate(-rotation, shape.centroid())
15
+ .aabb();
16
+ const size = (aspectRatio > 1 ? 1.5 * height : Math.sqrt(3) * width) / resolution;
17
+ const hexagonWidth = Math.sqrt(3) * size;
18
+ const hexagonHeight = 1.5 * size;
19
+ const columns = Math.ceil(width / hexagonWidth);
20
+ // Compensate for hexagon height portion that is tapered
21
+ const rows = Math.ceil((height + 0.5 * size) / hexagonHeight);
22
+ let polygons = [];
23
+ for (let row = 0; row < rows; row++) {
24
+ const y0 = yMin + row * hexagonHeight;
25
+ for (let column = row % 2 === 0 ? 0 : -0.5; column < columns; column++) {
26
+ const x0 = xMin + column * hexagonWidth;
27
+ if (x0 > xMax)
28
+ break;
29
+ polygons.push(new Polygon([
30
+ vec2(x0, y0),
31
+ vec2(x0 + 0.5 * SQRT_3 * size, y0 - 0.5 * size),
32
+ vec2(x0 + SQRT_3 * size, y0),
33
+ vec2(x0 + SQRT_3 * size, y0 + size),
34
+ vec2(x0 + 0.5 * SQRT_3 * size, y0 + 1.5 * size),
35
+ vec2(x0, y0 + size),
36
+ ]));
37
+ }
38
+ }
39
+ return polygons;
40
+ }
@@ -0,0 +1,12 @@
1
+ export * from "./delaunay.js";
2
+ export * from "./grid.js";
3
+ export * from "./hexagononal.js";
4
+ export * from "./line.js";
5
+ export * from "./pythagorean.js";
6
+ export * from "./random-cuts.js";
7
+ export * from "./recursive-cuts.js";
8
+ export * from "./rhombille.js";
9
+ export * from "./rightangled-triangle.js";
10
+ export * from "./triangle.js";
11
+ export * from "./voronoi.js";
12
+ export * from "./mediterranean.js";
@@ -0,0 +1,12 @@
1
+ export * from "./delaunay.js";
2
+ export * from "./grid.js";
3
+ export * from "./hexagononal.js";
4
+ export * from "./line.js";
5
+ export * from "./pythagorean.js";
6
+ export * from "./random-cuts.js";
7
+ export * from "./recursive-cuts.js";
8
+ export * from "./rhombille.js";
9
+ export * from "./rightangled-triangle.js";
10
+ export * from "./triangle.js";
11
+ export * from "./voronoi.js";
12
+ export * from "./mediterranean.js";
@@ -0,0 +1,5 @@
1
+ import { Hollowgon } from "../geometry/hollowgon.js";
2
+ import { OperationShape } from "../geometry/polygon-operations.js";
3
+ import { Polygon } from "../geometry/polygon.js";
4
+ export declare function lineSubdivision(shape: Polygon, rotation: number, columns: number): Array<Polygon>;
5
+ export declare function lineSubdivision(shape: Hollowgon, rotation: number, columns: number): Array<OperationShape>;
@@ -0,0 +1,19 @@
1
+ import { Line } from "../geometry/line.js";
2
+ import { subdivide } from "../geometry/polygon-operations.js";
3
+ import { Vec2, vec2 } from "../geometry/vec2.js";
4
+ export function lineSubdivision(shape, rotation, columns) {
5
+ const centroid = shape.centroid();
6
+ const { xMin, yMin, width } = shape
7
+ .clone()
8
+ .rotate(-rotation, centroid)
9
+ .aabb();
10
+ const spacing = width / columns;
11
+ let polygons = [shape];
12
+ const cutDirection = Vec2.fromPolar(1, Math.PI / 2 + rotation);
13
+ for (let i = 1; i < columns; i++) {
14
+ const point = vec2(xMin + spacing * i, yMin - 1).rotate(rotation, centroid);
15
+ const cutLine = new Line(point, cutDirection);
16
+ polygons = subdivide(polygons, cutLine);
17
+ }
18
+ return polygons;
19
+ }