three-text 0.4.11 → 0.4.12

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