three-text 0.4.11 → 0.5.0

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 (94) hide show
  1. package/LICENSE +5 -660
  2. package/LICENSE_THIRD_PARTY +15 -49
  3. package/README.md +265 -44
  4. package/dist/index.cjs +3424 -3450
  5. package/dist/index.d.ts +163 -9
  6. package/dist/index.js +3420 -3451
  7. package/dist/index.min.cjs +718 -676
  8. package/dist/index.min.js +721 -679
  9. package/dist/index.umd.js +3561 -3579
  10. package/dist/index.umd.min.js +803 -756
  11. package/dist/p5/index.cjs +2738 -5
  12. package/dist/p5/index.js +2738 -5
  13. package/dist/patterns/index.js +0 -4
  14. package/dist/slug/index.cjs +380 -0
  15. package/dist/slug/index.d.ts +62 -0
  16. package/dist/slug/index.js +374 -0
  17. package/dist/three/index.cjs +50 -35
  18. package/dist/three/index.js +50 -35
  19. package/dist/three/react.cjs +5 -2
  20. package/dist/three/react.d.ts +66 -120
  21. package/dist/three/react.js +6 -3
  22. package/dist/types/core/Text.d.ts +3 -10
  23. package/dist/types/core/cache/sharedCaches.d.ts +2 -1
  24. package/dist/types/core/shaping/DrawCallbacks.d.ts +11 -3
  25. package/dist/types/core/shaping/TextShaper.d.ts +1 -5
  26. package/dist/types/core/types.d.ts +84 -0
  27. package/dist/types/index.d.ts +7 -3
  28. package/dist/types/{core/cache → mesh}/GlyphContourCollector.d.ts +4 -4
  29. package/dist/types/{core/cache → mesh}/GlyphGeometryBuilder.d.ts +5 -5
  30. package/dist/types/mesh/MeshGeometryBuilder.d.ts +18 -0
  31. package/dist/types/{core → mesh}/geometry/BoundaryClusterer.d.ts +1 -1
  32. package/dist/types/{core → mesh}/geometry/Extruder.d.ts +1 -1
  33. package/dist/types/{core → mesh}/geometry/PathOptimizer.d.ts +1 -1
  34. package/dist/types/{core → mesh}/geometry/Polygonizer.d.ts +1 -1
  35. package/dist/types/{core → mesh}/geometry/Tessellator.d.ts +1 -1
  36. package/dist/types/react/utils.d.ts +2 -0
  37. package/dist/types/vector/GlyphOutlineCollector.d.ts +25 -0
  38. package/dist/types/vector/GlyphVectorGeometryBuilder.d.ts +26 -0
  39. package/dist/types/vector/LoopBlinnGeometry.d.ts +68 -0
  40. package/dist/types/vector/index.d.ts +29 -0
  41. package/dist/types/vector/loopBlinnTSL.d.ts +11 -0
  42. package/dist/types/vector/react.d.ts +24 -0
  43. package/dist/types/vector/webgl/index.d.ts +7 -0
  44. package/dist/types/vector/webgpu/index.d.ts +11 -0
  45. package/dist/vector/index.cjs +1458 -0
  46. package/dist/vector/index.d.ts +122 -0
  47. package/dist/vector/index.js +1434 -0
  48. package/dist/vector/react.cjs +153 -0
  49. package/dist/vector/react.d.ts +317 -0
  50. package/dist/vector/react.js +132 -0
  51. package/dist/vector/types/slug-lib/src/SlugPacker.d.ts +17 -0
  52. package/dist/vector/types/slug-lib/src/WebGL2Renderer.d.ts +21 -0
  53. package/dist/vector/types/slug-lib/src/WebGPURenderer.d.ts +16 -0
  54. package/dist/vector/types/slug-lib/src/index.d.ts +15 -0
  55. package/dist/vector/types/slug-lib/src/shaderStrings.d.ts +9 -0
  56. package/dist/vector/types/slug-lib/src/types.d.ts +34 -0
  57. package/dist/vector/types/src/core/types.d.ts +381 -0
  58. package/dist/vector/types/src/hyphenation/HyphenationPatternLoader.d.ts +2 -0
  59. package/dist/vector/types/src/hyphenation/index.d.ts +7 -0
  60. package/dist/vector/types/src/hyphenation/types.d.ts +6 -0
  61. package/dist/vector/types/src/utils/Cache.d.ts +14 -0
  62. package/dist/vector/types/src/utils/vectors.d.ts +75 -0
  63. package/dist/vector/types/src/vector/VectorDataBuilder.d.ts +30 -0
  64. package/dist/vector/types/src/vector/VectorThreeAdapter.d.ts +27 -0
  65. package/dist/vector/types/src/vector/index.d.ts +15 -0
  66. package/dist/vector/webgl/index.cjs +229 -0
  67. package/dist/vector/webgl/index.d.ts +53 -0
  68. package/dist/vector/webgl/index.js +227 -0
  69. package/dist/vector/webgpu/index.cjs +321 -0
  70. package/dist/vector/webgpu/index.d.ts +57 -0
  71. package/dist/vector/webgpu/index.js +319 -0
  72. package/dist/webgl-vector/index.cjs +243 -0
  73. package/dist/webgl-vector/index.d.ts +34 -0
  74. package/dist/webgl-vector/index.js +241 -0
  75. package/dist/webgpu-vector/index.cjs +336 -0
  76. package/dist/webgpu-vector/index.d.ts +38 -0
  77. package/dist/webgpu-vector/index.js +334 -0
  78. package/package.json +49 -4
  79. package/dist/patterns/cs.cjs +0 -14
  80. package/dist/patterns/cs.d.ts +0 -28
  81. package/dist/patterns/cs.js +0 -14
  82. package/dist/patterns/cs.umd.js +0 -14
  83. package/dist/patterns/id.cjs +0 -14
  84. package/dist/patterns/id.d.ts +0 -28
  85. package/dist/patterns/id.js +0 -14
  86. package/dist/patterns/id.umd.js +0 -14
  87. package/dist/patterns/mk.cjs +0 -14
  88. package/dist/patterns/mk.d.ts +0 -28
  89. package/dist/patterns/mk.js +0 -14
  90. package/dist/patterns/mk.umd.js +0 -14
  91. package/dist/patterns/sr-cyrl.cjs +0 -14
  92. package/dist/patterns/sr-cyrl.d.ts +0 -28
  93. package/dist/patterns/sr-cyrl.js +0 -14
  94. package/dist/patterns/sr-cyrl.umd.js +0 -14
@@ -0,0 +1,336 @@
1
+ 'use strict';
2
+
3
+ /// <reference types="@webgpu/types" />
4
+ function createBufferWithData(device, data, usage) {
5
+ const byteLength = Math.max(4, data.byteLength);
6
+ const buffer = device.createBuffer({
7
+ size: byteLength,
8
+ usage,
9
+ mappedAtCreation: true
10
+ });
11
+ if (data.byteLength > 0) {
12
+ const mapped = new Uint8Array(buffer.getMappedRange());
13
+ mapped.set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
14
+ }
15
+ buffer.unmap();
16
+ return buffer;
17
+ }
18
+ function createGeometryResources(device, data) {
19
+ const interiorPositionBuffer = createBufferWithData(device, data.interiorPositions, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST);
20
+ const interiorIndexBuffer = createBufferWithData(device, data.interiorIndices, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST);
21
+ const curvePositionBuffer = createBufferWithData(device, data.curvePositions, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST);
22
+ const fillPositions = new Float32Array([
23
+ data.planeBounds.min.x,
24
+ data.planeBounds.min.y,
25
+ 0,
26
+ data.planeBounds.max.x,
27
+ data.planeBounds.min.y,
28
+ 0,
29
+ data.planeBounds.max.x,
30
+ data.planeBounds.max.y,
31
+ 0,
32
+ data.planeBounds.min.x,
33
+ data.planeBounds.max.y,
34
+ 0
35
+ ]);
36
+ const fillIndices = new Uint16Array([0, 1, 2, 0, 2, 3]);
37
+ const fillPositionBuffer = createBufferWithData(device, fillPositions, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST);
38
+ const fillIndexBuffer = createBufferWithData(device, fillIndices, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST);
39
+ return {
40
+ interiorPositionBuffer,
41
+ interiorIndexBuffer,
42
+ interiorIndexCount: data.interiorIndices.length,
43
+ interiorIndexFormat: data.interiorIndices instanceof Uint16Array ? 'uint16' : 'uint32',
44
+ curvePositionBuffer,
45
+ curveVertexCount: data.curvePositions.length / 3,
46
+ fillPositionBuffer,
47
+ fillIndexBuffer,
48
+ fillIndexCount: fillIndices.length
49
+ };
50
+ }
51
+ function destroyGeometryResources(resources) {
52
+ resources.interiorPositionBuffer.destroy();
53
+ resources.interiorIndexBuffer.destroy();
54
+ resources.curvePositionBuffer.destroy();
55
+ resources.fillPositionBuffer.destroy();
56
+ resources.fillIndexBuffer.destroy();
57
+ }
58
+ function createWebGPUVectorRenderer(device, format, options = {}) {
59
+ const depthStencilFormat = options.depthStencilFormat ?? 'depth24plus-stencil8';
60
+ const sampleCount = options.sampleCount ?? 4;
61
+ const uniformBuffer = device.createBuffer({
62
+ size: 80,
63
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
64
+ });
65
+ const bindGroupLayout = device.createBindGroupLayout({
66
+ entries: [
67
+ {
68
+ binding: 0,
69
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
70
+ buffer: { type: 'uniform' }
71
+ }
72
+ ]
73
+ });
74
+ const pipelineLayout = device.createPipelineLayout({
75
+ bindGroupLayouts: [bindGroupLayout]
76
+ });
77
+ const bindGroup = device.createBindGroup({
78
+ layout: bindGroupLayout,
79
+ entries: [{ binding: 0, resource: { buffer: uniformBuffer } }]
80
+ });
81
+ const vertexBufferLayout = {
82
+ arrayStride: 12,
83
+ attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x3' }]
84
+ };
85
+ const baseVertexShader = `
86
+ struct Uniforms {
87
+ mvp: mat4x4<f32>,
88
+ color: vec4<f32>,
89
+ }
90
+
91
+ @group(0) @binding(0) var<uniform> uniforms: Uniforms;
92
+
93
+ struct VertexInput {
94
+ @location(0) position: vec3<f32>,
95
+ }
96
+
97
+ struct VertexOutput {
98
+ @builtin(position) position: vec4<f32>,
99
+ }
100
+
101
+ @vertex
102
+ fn main(input: VertexInput) -> VertexOutput {
103
+ var output: VertexOutput;
104
+ output.position = uniforms.mvp * vec4<f32>(input.position, 1.0);
105
+ return output;
106
+ }`;
107
+ const curveVertexShader = `
108
+ struct Uniforms {
109
+ mvp: mat4x4<f32>,
110
+ color: vec4<f32>,
111
+ }
112
+
113
+ @group(0) @binding(0) var<uniform> uniforms: Uniforms;
114
+
115
+ struct VertexInput {
116
+ @location(0) position: vec3<f32>,
117
+ }
118
+
119
+ struct VertexOutput {
120
+ @builtin(position) position: vec4<f32>,
121
+ @location(0) uv: vec2<f32>,
122
+ }
123
+
124
+ @vertex
125
+ fn main(input: VertexInput, @builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
126
+ let localVertex = vertexIndex % 3u;
127
+ let u = f32(localVertex) * 0.5;
128
+ var output: VertexOutput;
129
+ output.uv = vec2<f32>(u, floor(u));
130
+ output.position = uniforms.mvp * vec4<f32>(input.position, 1.0);
131
+ return output;
132
+ }`;
133
+ const stencilFragmentShader = `
134
+ @fragment
135
+ fn main() -> @location(0) vec4<f32> {
136
+ return vec4<f32>(1.0);
137
+ }`;
138
+ const curveFragmentShader = `
139
+ struct FragmentInput {
140
+ @location(0) uv: vec2<f32>,
141
+ }
142
+
143
+ @fragment
144
+ fn main(input: FragmentInput) -> @location(0) vec4<f32> {
145
+ let px = dpdx(input.uv);
146
+ let py = dpdy(input.uv);
147
+ let fx = 2.0 * input.uv.x * px.x - px.y;
148
+ let fy = 2.0 * input.uv.x * py.x - py.y;
149
+ let denom = sqrt(fx * fx + fy * fy);
150
+
151
+ if (denom < 1e-6) {
152
+ discard;
153
+ }
154
+
155
+ let sd = (input.uv.x * input.uv.x - input.uv.y) / denom;
156
+ let alpha = clamp(0.5 - sd, 0.0, 1.0);
157
+ if (alpha <= 0.0) {
158
+ discard;
159
+ }
160
+
161
+ return vec4<f32>(1.0, 1.0, 1.0, alpha);
162
+ }`;
163
+ const colorFragmentShader = `
164
+ struct Uniforms {
165
+ mvp: mat4x4<f32>,
166
+ color: vec4<f32>,
167
+ }
168
+
169
+ @group(0) @binding(0) var<uniform> uniforms: Uniforms;
170
+
171
+ @fragment
172
+ fn main() -> @location(0) vec4<f32> {
173
+ return uniforms.color;
174
+ }`;
175
+ const baseStencilStateFront = {
176
+ compare: 'always',
177
+ failOp: 'keep',
178
+ depthFailOp: 'keep',
179
+ passOp: 'invert'
180
+ };
181
+ const baseStencilStateBack = {
182
+ compare: 'always',
183
+ failOp: 'keep',
184
+ depthFailOp: 'keep',
185
+ passOp: 'invert'
186
+ };
187
+ const colorStencilStateFront = {
188
+ compare: 'not-equal',
189
+ failOp: 'keep',
190
+ depthFailOp: 'keep',
191
+ passOp: 'zero'
192
+ };
193
+ const colorStencilStateBack = {
194
+ compare: 'not-equal',
195
+ failOp: 'keep',
196
+ depthFailOp: 'keep',
197
+ passOp: 'zero'
198
+ };
199
+ const interiorPipeline = device.createRenderPipeline({
200
+ layout: pipelineLayout,
201
+ vertex: {
202
+ module: device.createShaderModule({ code: baseVertexShader }),
203
+ entryPoint: 'main',
204
+ buffers: [vertexBufferLayout]
205
+ },
206
+ fragment: {
207
+ module: device.createShaderModule({ code: stencilFragmentShader }),
208
+ entryPoint: 'main',
209
+ targets: [{ format, writeMask: 0 }]
210
+ },
211
+ primitive: {
212
+ topology: 'triangle-list',
213
+ cullMode: 'none'
214
+ },
215
+ depthStencil: {
216
+ format: depthStencilFormat,
217
+ depthWriteEnabled: false,
218
+ depthCompare: 'always',
219
+ stencilFront: baseStencilStateFront,
220
+ stencilBack: baseStencilStateBack,
221
+ stencilReadMask: 0xff,
222
+ stencilWriteMask: 0xff
223
+ },
224
+ multisample: {
225
+ count: sampleCount,
226
+ alphaToCoverageEnabled: false
227
+ }
228
+ });
229
+ const curvePipeline = device.createRenderPipeline({
230
+ layout: pipelineLayout,
231
+ vertex: {
232
+ module: device.createShaderModule({ code: curveVertexShader }),
233
+ entryPoint: 'main',
234
+ buffers: [vertexBufferLayout]
235
+ },
236
+ fragment: {
237
+ module: device.createShaderModule({ code: curveFragmentShader }),
238
+ entryPoint: 'main',
239
+ targets: [{ format, writeMask: 0 }]
240
+ },
241
+ primitive: {
242
+ topology: 'triangle-list',
243
+ cullMode: 'none'
244
+ },
245
+ depthStencil: {
246
+ format: depthStencilFormat,
247
+ depthWriteEnabled: false,
248
+ depthCompare: 'always',
249
+ stencilFront: baseStencilStateFront,
250
+ stencilBack: baseStencilStateBack,
251
+ stencilReadMask: 0xff,
252
+ stencilWriteMask: 0xff
253
+ },
254
+ multisample: {
255
+ count: sampleCount,
256
+ alphaToCoverageEnabled: true
257
+ }
258
+ });
259
+ const colorPipeline = device.createRenderPipeline({
260
+ layout: pipelineLayout,
261
+ vertex: {
262
+ module: device.createShaderModule({ code: baseVertexShader }),
263
+ entryPoint: 'main',
264
+ buffers: [vertexBufferLayout]
265
+ },
266
+ fragment: {
267
+ module: device.createShaderModule({ code: colorFragmentShader }),
268
+ entryPoint: 'main',
269
+ targets: [{ format, writeMask: GPUColorWrite.ALL }]
270
+ },
271
+ primitive: {
272
+ topology: 'triangle-list',
273
+ cullMode: 'none'
274
+ },
275
+ depthStencil: {
276
+ format: depthStencilFormat,
277
+ depthWriteEnabled: false,
278
+ depthCompare: 'always',
279
+ stencilFront: colorStencilStateFront,
280
+ stencilBack: colorStencilStateBack,
281
+ stencilReadMask: 0xff,
282
+ stencilWriteMask: 0xff
283
+ },
284
+ multisample: {
285
+ count: sampleCount,
286
+ alphaToCoverageEnabled: false
287
+ }
288
+ });
289
+ const uniformData = new Float32Array(20);
290
+ let geometryResources = null;
291
+ return {
292
+ setGeometry(data) {
293
+ if (geometryResources) {
294
+ destroyGeometryResources(geometryResources);
295
+ }
296
+ geometryResources = createGeometryResources(device, data);
297
+ },
298
+ render(passEncoder, mvp, color) {
299
+ if (!geometryResources) {
300
+ return;
301
+ }
302
+ uniformData.set(mvp, 0);
303
+ uniformData[16] = color[0];
304
+ uniformData[17] = color[1];
305
+ uniformData[18] = color[2];
306
+ uniformData[19] = color[3];
307
+ device.queue.writeBuffer(uniformBuffer, 0, uniformData);
308
+ passEncoder.setBindGroup(0, bindGroup);
309
+ passEncoder.setStencilReference(0);
310
+ if (geometryResources.interiorIndexCount > 0) {
311
+ passEncoder.setPipeline(interiorPipeline);
312
+ passEncoder.setVertexBuffer(0, geometryResources.interiorPositionBuffer);
313
+ passEncoder.setIndexBuffer(geometryResources.interiorIndexBuffer, geometryResources.interiorIndexFormat);
314
+ passEncoder.drawIndexed(geometryResources.interiorIndexCount);
315
+ }
316
+ if (geometryResources.curveVertexCount > 0) {
317
+ passEncoder.setPipeline(curvePipeline);
318
+ passEncoder.setVertexBuffer(0, geometryResources.curvePositionBuffer);
319
+ passEncoder.draw(geometryResources.curveVertexCount);
320
+ }
321
+ passEncoder.setPipeline(colorPipeline);
322
+ passEncoder.setVertexBuffer(0, geometryResources.fillPositionBuffer);
323
+ passEncoder.setIndexBuffer(geometryResources.fillIndexBuffer, 'uint16');
324
+ passEncoder.drawIndexed(geometryResources.fillIndexCount);
325
+ },
326
+ dispose() {
327
+ if (geometryResources) {
328
+ destroyGeometryResources(geometryResources);
329
+ geometryResources = null;
330
+ }
331
+ uniformBuffer.destroy();
332
+ }
333
+ };
334
+ }
335
+
336
+ exports.createWebGPUVectorRenderer = createWebGPUVectorRenderer;
@@ -0,0 +1,38 @@
1
+ interface BoundingBox {
2
+ min: {
3
+ x: number;
4
+ y: number;
5
+ z: number;
6
+ };
7
+ max: {
8
+ x: number;
9
+ y: number;
10
+ z: number;
11
+ };
12
+ }
13
+
14
+ interface LoopBlinnMeshData {
15
+ interiorPositions: Float32Array;
16
+ interiorIndices: Uint32Array;
17
+ curvePositions: Float32Array;
18
+ planeBounds: BoundingBox;
19
+ stats: {
20
+ glyphCount: number;
21
+ contourCount: number;
22
+ interiorTriangleCount: number;
23
+ curveTriangleCount: number;
24
+ };
25
+ }
26
+
27
+ interface WebGPUVectorRenderer {
28
+ setGeometry(data: LoopBlinnMeshData): void;
29
+ render(passEncoder: GPURenderPassEncoder, mvp: Float32Array, color: Float32Array): void;
30
+ dispose(): void;
31
+ }
32
+ interface WebGPUVectorRendererOptions {
33
+ depthStencilFormat?: GPUTextureFormat;
34
+ sampleCount?: number;
35
+ }
36
+ declare function createWebGPUVectorRenderer(device: GPUDevice, format: GPUTextureFormat, options?: WebGPUVectorRendererOptions): WebGPUVectorRenderer;
37
+
38
+ export { WebGPUVectorRenderer, WebGPUVectorRendererOptions, createWebGPUVectorRenderer };
@@ -0,0 +1,334 @@
1
+ /// <reference types="@webgpu/types" />
2
+ function createBufferWithData(device, data, usage) {
3
+ const byteLength = Math.max(4, data.byteLength);
4
+ const buffer = device.createBuffer({
5
+ size: byteLength,
6
+ usage,
7
+ mappedAtCreation: true
8
+ });
9
+ if (data.byteLength > 0) {
10
+ const mapped = new Uint8Array(buffer.getMappedRange());
11
+ mapped.set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
12
+ }
13
+ buffer.unmap();
14
+ return buffer;
15
+ }
16
+ function createGeometryResources(device, data) {
17
+ const interiorPositionBuffer = createBufferWithData(device, data.interiorPositions, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST);
18
+ const interiorIndexBuffer = createBufferWithData(device, data.interiorIndices, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST);
19
+ const curvePositionBuffer = createBufferWithData(device, data.curvePositions, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST);
20
+ const fillPositions = new Float32Array([
21
+ data.planeBounds.min.x,
22
+ data.planeBounds.min.y,
23
+ 0,
24
+ data.planeBounds.max.x,
25
+ data.planeBounds.min.y,
26
+ 0,
27
+ data.planeBounds.max.x,
28
+ data.planeBounds.max.y,
29
+ 0,
30
+ data.planeBounds.min.x,
31
+ data.planeBounds.max.y,
32
+ 0
33
+ ]);
34
+ const fillIndices = new Uint16Array([0, 1, 2, 0, 2, 3]);
35
+ const fillPositionBuffer = createBufferWithData(device, fillPositions, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST);
36
+ const fillIndexBuffer = createBufferWithData(device, fillIndices, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST);
37
+ return {
38
+ interiorPositionBuffer,
39
+ interiorIndexBuffer,
40
+ interiorIndexCount: data.interiorIndices.length,
41
+ interiorIndexFormat: data.interiorIndices instanceof Uint16Array ? 'uint16' : 'uint32',
42
+ curvePositionBuffer,
43
+ curveVertexCount: data.curvePositions.length / 3,
44
+ fillPositionBuffer,
45
+ fillIndexBuffer,
46
+ fillIndexCount: fillIndices.length
47
+ };
48
+ }
49
+ function destroyGeometryResources(resources) {
50
+ resources.interiorPositionBuffer.destroy();
51
+ resources.interiorIndexBuffer.destroy();
52
+ resources.curvePositionBuffer.destroy();
53
+ resources.fillPositionBuffer.destroy();
54
+ resources.fillIndexBuffer.destroy();
55
+ }
56
+ function createWebGPUVectorRenderer(device, format, options = {}) {
57
+ const depthStencilFormat = options.depthStencilFormat ?? 'depth24plus-stencil8';
58
+ const sampleCount = options.sampleCount ?? 4;
59
+ const uniformBuffer = device.createBuffer({
60
+ size: 80,
61
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
62
+ });
63
+ const bindGroupLayout = device.createBindGroupLayout({
64
+ entries: [
65
+ {
66
+ binding: 0,
67
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
68
+ buffer: { type: 'uniform' }
69
+ }
70
+ ]
71
+ });
72
+ const pipelineLayout = device.createPipelineLayout({
73
+ bindGroupLayouts: [bindGroupLayout]
74
+ });
75
+ const bindGroup = device.createBindGroup({
76
+ layout: bindGroupLayout,
77
+ entries: [{ binding: 0, resource: { buffer: uniformBuffer } }]
78
+ });
79
+ const vertexBufferLayout = {
80
+ arrayStride: 12,
81
+ attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x3' }]
82
+ };
83
+ const baseVertexShader = `
84
+ struct Uniforms {
85
+ mvp: mat4x4<f32>,
86
+ color: vec4<f32>,
87
+ }
88
+
89
+ @group(0) @binding(0) var<uniform> uniforms: Uniforms;
90
+
91
+ struct VertexInput {
92
+ @location(0) position: vec3<f32>,
93
+ }
94
+
95
+ struct VertexOutput {
96
+ @builtin(position) position: vec4<f32>,
97
+ }
98
+
99
+ @vertex
100
+ fn main(input: VertexInput) -> VertexOutput {
101
+ var output: VertexOutput;
102
+ output.position = uniforms.mvp * vec4<f32>(input.position, 1.0);
103
+ return output;
104
+ }`;
105
+ const curveVertexShader = `
106
+ struct Uniforms {
107
+ mvp: mat4x4<f32>,
108
+ color: vec4<f32>,
109
+ }
110
+
111
+ @group(0) @binding(0) var<uniform> uniforms: Uniforms;
112
+
113
+ struct VertexInput {
114
+ @location(0) position: vec3<f32>,
115
+ }
116
+
117
+ struct VertexOutput {
118
+ @builtin(position) position: vec4<f32>,
119
+ @location(0) uv: vec2<f32>,
120
+ }
121
+
122
+ @vertex
123
+ fn main(input: VertexInput, @builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
124
+ let localVertex = vertexIndex % 3u;
125
+ let u = f32(localVertex) * 0.5;
126
+ var output: VertexOutput;
127
+ output.uv = vec2<f32>(u, floor(u));
128
+ output.position = uniforms.mvp * vec4<f32>(input.position, 1.0);
129
+ return output;
130
+ }`;
131
+ const stencilFragmentShader = `
132
+ @fragment
133
+ fn main() -> @location(0) vec4<f32> {
134
+ return vec4<f32>(1.0);
135
+ }`;
136
+ const curveFragmentShader = `
137
+ struct FragmentInput {
138
+ @location(0) uv: vec2<f32>,
139
+ }
140
+
141
+ @fragment
142
+ fn main(input: FragmentInput) -> @location(0) vec4<f32> {
143
+ let px = dpdx(input.uv);
144
+ let py = dpdy(input.uv);
145
+ let fx = 2.0 * input.uv.x * px.x - px.y;
146
+ let fy = 2.0 * input.uv.x * py.x - py.y;
147
+ let denom = sqrt(fx * fx + fy * fy);
148
+
149
+ if (denom < 1e-6) {
150
+ discard;
151
+ }
152
+
153
+ let sd = (input.uv.x * input.uv.x - input.uv.y) / denom;
154
+ let alpha = clamp(0.5 - sd, 0.0, 1.0);
155
+ if (alpha <= 0.0) {
156
+ discard;
157
+ }
158
+
159
+ return vec4<f32>(1.0, 1.0, 1.0, alpha);
160
+ }`;
161
+ const colorFragmentShader = `
162
+ struct Uniforms {
163
+ mvp: mat4x4<f32>,
164
+ color: vec4<f32>,
165
+ }
166
+
167
+ @group(0) @binding(0) var<uniform> uniforms: Uniforms;
168
+
169
+ @fragment
170
+ fn main() -> @location(0) vec4<f32> {
171
+ return uniforms.color;
172
+ }`;
173
+ const baseStencilStateFront = {
174
+ compare: 'always',
175
+ failOp: 'keep',
176
+ depthFailOp: 'keep',
177
+ passOp: 'invert'
178
+ };
179
+ const baseStencilStateBack = {
180
+ compare: 'always',
181
+ failOp: 'keep',
182
+ depthFailOp: 'keep',
183
+ passOp: 'invert'
184
+ };
185
+ const colorStencilStateFront = {
186
+ compare: 'not-equal',
187
+ failOp: 'keep',
188
+ depthFailOp: 'keep',
189
+ passOp: 'zero'
190
+ };
191
+ const colorStencilStateBack = {
192
+ compare: 'not-equal',
193
+ failOp: 'keep',
194
+ depthFailOp: 'keep',
195
+ passOp: 'zero'
196
+ };
197
+ const interiorPipeline = device.createRenderPipeline({
198
+ layout: pipelineLayout,
199
+ vertex: {
200
+ module: device.createShaderModule({ code: baseVertexShader }),
201
+ entryPoint: 'main',
202
+ buffers: [vertexBufferLayout]
203
+ },
204
+ fragment: {
205
+ module: device.createShaderModule({ code: stencilFragmentShader }),
206
+ entryPoint: 'main',
207
+ targets: [{ format, writeMask: 0 }]
208
+ },
209
+ primitive: {
210
+ topology: 'triangle-list',
211
+ cullMode: 'none'
212
+ },
213
+ depthStencil: {
214
+ format: depthStencilFormat,
215
+ depthWriteEnabled: false,
216
+ depthCompare: 'always',
217
+ stencilFront: baseStencilStateFront,
218
+ stencilBack: baseStencilStateBack,
219
+ stencilReadMask: 0xff,
220
+ stencilWriteMask: 0xff
221
+ },
222
+ multisample: {
223
+ count: sampleCount,
224
+ alphaToCoverageEnabled: false
225
+ }
226
+ });
227
+ const curvePipeline = device.createRenderPipeline({
228
+ layout: pipelineLayout,
229
+ vertex: {
230
+ module: device.createShaderModule({ code: curveVertexShader }),
231
+ entryPoint: 'main',
232
+ buffers: [vertexBufferLayout]
233
+ },
234
+ fragment: {
235
+ module: device.createShaderModule({ code: curveFragmentShader }),
236
+ entryPoint: 'main',
237
+ targets: [{ format, writeMask: 0 }]
238
+ },
239
+ primitive: {
240
+ topology: 'triangle-list',
241
+ cullMode: 'none'
242
+ },
243
+ depthStencil: {
244
+ format: depthStencilFormat,
245
+ depthWriteEnabled: false,
246
+ depthCompare: 'always',
247
+ stencilFront: baseStencilStateFront,
248
+ stencilBack: baseStencilStateBack,
249
+ stencilReadMask: 0xff,
250
+ stencilWriteMask: 0xff
251
+ },
252
+ multisample: {
253
+ count: sampleCount,
254
+ alphaToCoverageEnabled: true
255
+ }
256
+ });
257
+ const colorPipeline = device.createRenderPipeline({
258
+ layout: pipelineLayout,
259
+ vertex: {
260
+ module: device.createShaderModule({ code: baseVertexShader }),
261
+ entryPoint: 'main',
262
+ buffers: [vertexBufferLayout]
263
+ },
264
+ fragment: {
265
+ module: device.createShaderModule({ code: colorFragmentShader }),
266
+ entryPoint: 'main',
267
+ targets: [{ format, writeMask: GPUColorWrite.ALL }]
268
+ },
269
+ primitive: {
270
+ topology: 'triangle-list',
271
+ cullMode: 'none'
272
+ },
273
+ depthStencil: {
274
+ format: depthStencilFormat,
275
+ depthWriteEnabled: false,
276
+ depthCompare: 'always',
277
+ stencilFront: colorStencilStateFront,
278
+ stencilBack: colorStencilStateBack,
279
+ stencilReadMask: 0xff,
280
+ stencilWriteMask: 0xff
281
+ },
282
+ multisample: {
283
+ count: sampleCount,
284
+ alphaToCoverageEnabled: false
285
+ }
286
+ });
287
+ const uniformData = new Float32Array(20);
288
+ let geometryResources = null;
289
+ return {
290
+ setGeometry(data) {
291
+ if (geometryResources) {
292
+ destroyGeometryResources(geometryResources);
293
+ }
294
+ geometryResources = createGeometryResources(device, data);
295
+ },
296
+ render(passEncoder, mvp, color) {
297
+ if (!geometryResources) {
298
+ return;
299
+ }
300
+ uniformData.set(mvp, 0);
301
+ uniformData[16] = color[0];
302
+ uniformData[17] = color[1];
303
+ uniformData[18] = color[2];
304
+ uniformData[19] = color[3];
305
+ device.queue.writeBuffer(uniformBuffer, 0, uniformData);
306
+ passEncoder.setBindGroup(0, bindGroup);
307
+ passEncoder.setStencilReference(0);
308
+ if (geometryResources.interiorIndexCount > 0) {
309
+ passEncoder.setPipeline(interiorPipeline);
310
+ passEncoder.setVertexBuffer(0, geometryResources.interiorPositionBuffer);
311
+ passEncoder.setIndexBuffer(geometryResources.interiorIndexBuffer, geometryResources.interiorIndexFormat);
312
+ passEncoder.drawIndexed(geometryResources.interiorIndexCount);
313
+ }
314
+ if (geometryResources.curveVertexCount > 0) {
315
+ passEncoder.setPipeline(curvePipeline);
316
+ passEncoder.setVertexBuffer(0, geometryResources.curvePositionBuffer);
317
+ passEncoder.draw(geometryResources.curveVertexCount);
318
+ }
319
+ passEncoder.setPipeline(colorPipeline);
320
+ passEncoder.setVertexBuffer(0, geometryResources.fillPositionBuffer);
321
+ passEncoder.setIndexBuffer(geometryResources.fillIndexBuffer, 'uint16');
322
+ passEncoder.drawIndexed(geometryResources.fillIndexCount);
323
+ },
324
+ dispose() {
325
+ if (geometryResources) {
326
+ destroyGeometryResources(geometryResources);
327
+ geometryResources = null;
328
+ }
329
+ uniformBuffer.destroy();
330
+ }
331
+ };
332
+ }
333
+
334
+ export { createWebGPUVectorRenderer };