p5 2.2.3 → 2.3.0-rc.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.
- package/dist/accessibility/color_namer.js +9 -11
- package/dist/accessibility/describe.js +0 -1
- package/dist/accessibility/gridOutput.js +0 -1
- package/dist/accessibility/index.js +9 -10
- package/dist/accessibility/outputs.js +0 -1
- package/dist/accessibility/textOutput.js +0 -1
- package/dist/app.js +11 -10
- package/dist/app.node.js +122 -0
- package/dist/color/color_conversion.js +9 -11
- package/dist/color/creating_reading.js +1 -1
- package/dist/color/index.js +2 -2
- package/dist/color/p5.Color.js +1 -1
- package/dist/color/setting.js +25 -12
- package/dist/{constants-BdTiYOQI.js → constants-CYF6mp5_.js} +2 -2
- package/dist/core/States.js +1 -1
- package/dist/core/constants.js +1 -1
- package/dist/core/environment.js +28 -29
- package/dist/core/filterShaders.js +1 -1
- package/dist/core/friendly_errors/fes_core.js +9 -8
- package/dist/core/friendly_errors/file_errors.js +1 -2
- package/dist/core/friendly_errors/index.js +1 -1
- package/dist/core/friendly_errors/param_validator.js +737 -640
- package/dist/core/friendly_errors/sketch_verifier.js +1 -1
- package/dist/core/friendly_errors/stacktrace.js +0 -1
- package/dist/core/helpers.js +3 -4
- package/dist/core/init.js +24 -21
- package/dist/core/internationalization.js +1 -1
- package/dist/core/legacy.js +9 -11
- package/dist/core/main.js +9 -10
- package/dist/core/p5.Graphics.js +5 -5
- package/dist/core/p5.Renderer.js +3 -3
- package/dist/core/p5.Renderer2D.js +9 -10
- package/dist/core/p5.Renderer3D.js +5 -5
- package/dist/core/rendering.js +5 -5
- package/dist/core/structure.js +0 -1
- package/dist/core/transform.js +7 -16
- package/dist/{creating_reading-C7hu6sg1.js → creating_reading-DLkHH80h.js} +11 -8
- package/dist/data/local_storage.js +0 -1
- package/dist/dom/dom.js +2 -3
- package/dist/dom/index.js +2 -2
- package/dist/dom/p5.Element.js +2 -2
- package/dist/dom/p5.MediaElement.js +2 -2
- package/dist/events/acceleration.js +5 -3
- package/dist/events/keyboard.js +0 -1
- package/dist/events/pointer.js +0 -2
- package/dist/image/const.js +1 -1
- package/dist/image/filterRenderer2D.js +19 -12
- package/dist/image/image.js +5 -5
- package/dist/image/index.js +5 -5
- package/dist/image/loading_displaying.js +5 -5
- package/dist/image/p5.Image.js +3 -3
- package/dist/image/pixels.js +0 -1
- package/dist/io/files.js +5 -5
- package/dist/io/index.js +5 -5
- package/dist/io/p5.Table.js +0 -1
- package/dist/io/p5.TableRow.js +0 -1
- package/dist/io/p5.XML.js +0 -1
- package/dist/{ir_builders-Cd6rU9Vm.js → ir_builders-C2ebb6Lu.js} +234 -1
- package/dist/{main-H_nu4eDs.js → main-D2MtO721.js} +107 -136
- package/dist/math/Matrices/Matrix.js +1 -1
- package/dist/math/Matrices/MatrixNumjs.js +1 -1
- package/dist/math/calculation.js +0 -1
- package/dist/math/index.js +3 -1
- package/dist/math/math.js +3 -17
- package/dist/math/noise.js +0 -1
- package/dist/math/p5.Matrix.js +1 -2
- package/dist/math/p5.Vector.js +233 -279
- package/dist/math/patch-vector.js +75 -0
- package/dist/math/random.js +0 -1
- package/dist/math/trigonometry.js +3 -4
- package/dist/{p5.Renderer-BmD2P6Wv.js → p5.Renderer-C0Kzy71d.js} +31 -24
- package/dist/{rendering-CC8JNTwG.js → rendering-CvNr0bB8.js} +732 -44
- package/dist/shape/2d_primitives.js +1 -4
- package/dist/shape/attributes.js +43 -8
- package/dist/shape/curves.js +0 -1
- package/dist/shape/custom_shapes.js +260 -5
- package/dist/shape/index.js +2 -2
- package/dist/shape/vertex.js +0 -2
- package/dist/strands/ir_builders.js +1 -1
- package/dist/strands/ir_types.js +5 -1
- package/dist/strands/p5.strands.js +286 -31
- package/dist/strands/strands_api.js +179 -8
- package/dist/strands/strands_codegen.js +26 -8
- package/dist/strands/strands_conditionals.js +1 -1
- package/dist/strands/strands_for.js +1 -1
- package/dist/strands/strands_node.js +1 -1
- package/dist/strands/strands_ternary.js +56 -0
- package/dist/strands/strands_transpiler.js +416 -251
- package/dist/strands_glslBackend-i-ReKgZo.js +423 -0
- package/dist/type/index.js +3 -3
- package/dist/type/lib/Typr.js +1 -1
- package/dist/type/p5.Font.js +3 -3
- package/dist/type/textCore.js +31 -24
- package/dist/utilities/conversion.js +0 -1
- package/dist/utilities/time_date.js +0 -1
- package/dist/utilities/utility_functions.js +0 -1
- package/dist/webgl/3d_primitives.js +5 -5
- package/dist/webgl/GeometryBuilder.js +1 -1
- package/dist/webgl/ShapeBuilder.js +26 -1
- package/dist/webgl/enums.js +1 -1
- package/dist/webgl/index.js +8 -9
- package/dist/webgl/interaction.js +8 -4
- package/dist/webgl/light.js +5 -5
- package/dist/webgl/loading.js +60 -21
- package/dist/webgl/material.js +5 -5
- package/dist/webgl/p5.Camera.js +5 -5
- package/dist/webgl/p5.Framebuffer.js +5 -5
- package/dist/webgl/p5.Geometry.js +3 -5
- package/dist/webgl/p5.Quat.js +1 -1
- package/dist/webgl/p5.RendererGL.js +17 -21
- package/dist/webgl/p5.Shader.js +129 -36
- package/dist/webgl/p5.Texture.js +5 -5
- package/dist/webgl/strands_glslBackend.js +5 -386
- package/dist/webgl/text.js +5 -5
- package/dist/webgl/utils.js +5 -5
- package/dist/webgl2Compatibility-DA7DLMuq.js +7 -0
- package/dist/webgpu/index.js +7 -3
- package/dist/webgpu/p5.RendererWebGPU.js +1036 -180
- package/dist/webgpu/shaders/color.js +1 -1
- package/dist/webgpu/shaders/compute.js +32 -0
- package/dist/webgpu/shaders/functions/randomComputeWGSL.js +31 -0
- package/dist/webgpu/shaders/functions/randomVertWGSL.js +30 -0
- package/dist/webgpu/shaders/functions/randomWGSL.js +30 -0
- package/dist/webgpu/shaders/line.js +1 -1
- package/dist/webgpu/shaders/material.js +3 -3
- package/dist/webgpu/strands_wgslBackend.js +137 -15
- package/lib/p5.esm.js +4088 -1950
- package/lib/p5.esm.min.js +1 -1
- package/lib/p5.js +4088 -1950
- package/lib/p5.min.js +1 -1
- package/lib/p5.webgpu.esm.js +1638 -306
- package/lib/p5.webgpu.js +1637 -305
- package/lib/p5.webgpu.min.js +1 -1
- package/package.json +6 -1
- package/types/global.d.ts +4137 -2396
- package/types/p5.d.ts +2702 -1658
- package/dist/noise3DGLSL-Bwrdi4gi.js +0 -9
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { u as unaryOpNode, c as createStrandsNode, S as StrandsNode, p as primitiveConstructorNode, v as variableNode, b as binaryOpNode,
|
|
1
|
+
import { u as unaryOpNode, c as createStrandsNode, S as StrandsNode, p as primitiveConstructorNode, v as variableNode, b as binaryOpNode, a as statementNode, f as functionCallNode, d as structInstanceNode, e as structConstructorNode } from '../ir_builders-C2ebb6Lu.js';
|
|
2
2
|
import { OperatorTable, StatementType, NodeType, DataType, BaseType, BlockType, isStructType, structType } from './ir_types.js';
|
|
3
3
|
import { strandsBuiltinFunctions } from './strands_builtins.js';
|
|
4
4
|
import { StrandsConditional } from './strands_conditionals.js';
|
|
5
5
|
import { StrandsFor } from './strands_for.js';
|
|
6
|
+
import { buildTernary } from './strands_ternary.js';
|
|
6
7
|
import { createBasicBlock, addEdge, pushBlock, recordInBasicBlock, popBlock } from './ir_cfg.js';
|
|
7
8
|
import { createNodeData, getOrCreateNode, getNodeDataFromID } from './ir_dag.js';
|
|
8
9
|
import { userError } from './strands_FES.js';
|
|
@@ -181,6 +182,10 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
|
|
|
181
182
|
return new StrandsFor(strandsContext, initialCb, conditionCb, updateCb, bodyCb, initialVars).build();
|
|
182
183
|
};
|
|
183
184
|
augmentFn(fn, p5, 'strandsFor', p5.strandsFor);
|
|
185
|
+
p5.strandsTernary = function(condition, ifTrue, ifFalse) {
|
|
186
|
+
return buildTernary(strandsContext, condition, ifTrue, ifFalse);
|
|
187
|
+
};
|
|
188
|
+
augmentFn(fn, p5, 'strandsTernary', p5.strandsTernary);
|
|
184
189
|
p5.strandsEarlyReturn = function(value) {
|
|
185
190
|
const { dag, cfg } = strandsContext;
|
|
186
191
|
|
|
@@ -201,7 +206,7 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
|
|
|
201
206
|
const nodeData = createNodeData({
|
|
202
207
|
nodeType: NodeType.STATEMENT,
|
|
203
208
|
statementType: StatementType.EARLY_RETURN,
|
|
204
|
-
dependsOn: [valueNode.id]
|
|
209
|
+
dependsOn: value !== undefined ? [valueNode.id] : []
|
|
205
210
|
});
|
|
206
211
|
const earlyReturnID = getOrCreateNode(dag, nodeData);
|
|
207
212
|
recordInBasicBlock(cfg, cfg.currentBlock, earlyReturnID);
|
|
@@ -266,6 +271,33 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
|
|
|
266
271
|
}
|
|
267
272
|
}
|
|
268
273
|
|
|
274
|
+
// Alias lerp to GLSL mix in strands context
|
|
275
|
+
const originalLerp = fn.lerp;
|
|
276
|
+
augmentFn(fn, p5, 'lerp', function (...args) {
|
|
277
|
+
if (strandsContext.active) {
|
|
278
|
+
return fn.mix(...args);
|
|
279
|
+
} else {
|
|
280
|
+
return originalLerp.apply(this, args);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
const originalMap = fn.map;
|
|
285
|
+
augmentFn(fn, p5, 'map', function (...args) {
|
|
286
|
+
if (!strandsContext.active) {
|
|
287
|
+
return originalMap.apply(this, args);
|
|
288
|
+
}
|
|
289
|
+
const [n, start1, stop1, start2, stop2, withinBounds] = args;
|
|
290
|
+
const nNode = p5.strandsNode(n);
|
|
291
|
+
const start1Node = p5.strandsNode(start1);
|
|
292
|
+
const stop1Node = p5.strandsNode(stop1);
|
|
293
|
+
const t = nNode.sub(start1Node).div(stop1Node.sub(start1Node));
|
|
294
|
+
const result = this.mix(start2, stop2, t);
|
|
295
|
+
if (withinBounds) {
|
|
296
|
+
return this.clamp(result, this.min(start2, stop2), this.max(start2, stop2));
|
|
297
|
+
}
|
|
298
|
+
return result;
|
|
299
|
+
});
|
|
300
|
+
|
|
269
301
|
augmentFn(fn, p5, 'getTexture', function (...rawArgs) {
|
|
270
302
|
if (strandsContext.active) {
|
|
271
303
|
const { id, dimension } = strandsContext.backend.createGetTextureCall(strandsContext, rawArgs);
|
|
@@ -290,6 +322,8 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
|
|
|
290
322
|
// Add noise function with backend-agnostic implementation
|
|
291
323
|
const originalNoise = fn.noise;
|
|
292
324
|
const originalNoiseDetail = fn.noiseDetail;
|
|
325
|
+
const originalRandom = fn.random;
|
|
326
|
+
const originalRandomSeed = fn.randomSeed;
|
|
293
327
|
const originalMillis = fn.millis;
|
|
294
328
|
|
|
295
329
|
strandsContext._noiseOctaves = null;
|
|
@@ -309,9 +343,10 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
|
|
|
309
343
|
return originalNoise.apply(this, args); // fallback to regular p5.js noise
|
|
310
344
|
}
|
|
311
345
|
// Get noise shader snippet from the current renderer
|
|
312
|
-
const noiseSnippet =
|
|
346
|
+
const noiseSnippet = strandsContext.backend.getNoiseShaderSnippet();
|
|
313
347
|
strandsContext.vertexDeclarations.add(noiseSnippet);
|
|
314
348
|
strandsContext.fragmentDeclarations.add(noiseSnippet);
|
|
349
|
+
strandsContext.computeDeclarations.add(noiseSnippet);
|
|
315
350
|
|
|
316
351
|
// Make each input into a strands node so that we can check their dimensions
|
|
317
352
|
const strandsArgs = args.flat().map(arg => p5.strandsNode(arg));
|
|
@@ -353,6 +388,84 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
|
|
|
353
388
|
return createStrandsNode(id, dimension, strandsContext);
|
|
354
389
|
});
|
|
355
390
|
|
|
391
|
+
strandsContext._randomSeed = null;
|
|
392
|
+
|
|
393
|
+
augmentFn(fn, p5, 'randomSeed', function (seed) {
|
|
394
|
+
if (!strandsContext.active) {
|
|
395
|
+
return originalRandomSeed.apply(this, arguments);
|
|
396
|
+
}
|
|
397
|
+
strandsContext._randomSeed = seed;
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
augmentFn(fn, p5, 'random', function (...args) {
|
|
401
|
+
if (!strandsContext.active) {
|
|
402
|
+
return originalRandom.apply(this, args);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const randomVertSnippet = strandsContext.backend.getRandomVertexShaderSnippet();
|
|
406
|
+
const randomFragSnippet = strandsContext.backend.getRandomFragmentShaderSnippet();
|
|
407
|
+
|
|
408
|
+
strandsContext.vertexDeclarations.add(randomVertSnippet);
|
|
409
|
+
strandsContext.fragmentDeclarations.add(randomFragSnippet);
|
|
410
|
+
|
|
411
|
+
if (strandsContext.backend.getRandomComputeShaderSnippet) {
|
|
412
|
+
const randomComputeSnippet = strandsContext.backend.getRandomComputeShaderSnippet();
|
|
413
|
+
strandsContext.computeDeclarations.add(randomComputeSnippet);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
let seedNode;
|
|
417
|
+
if (strandsContext._randomSeed !== null && strandsContext._randomSeed.isStrandsNode) {
|
|
418
|
+
seedNode = strandsContext._randomSeed;
|
|
419
|
+
} else {
|
|
420
|
+
const userSeed = strandsContext._randomSeed;
|
|
421
|
+
seedNode = getOrCreateUniformNode(
|
|
422
|
+
strandsContext,
|
|
423
|
+
'_p5_randomSeed',
|
|
424
|
+
DataType.float1,
|
|
425
|
+
userSeed !== null
|
|
426
|
+
? () => userSeed
|
|
427
|
+
: () => performance.now(),
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// The shader-side random() owns a private per-invocation counter, so a
|
|
432
|
+
// single AST node still produces distinct values across runtime loop
|
|
433
|
+
// iterations. We just pass the seed.
|
|
434
|
+
const nodeArgs = [seedNode];
|
|
435
|
+
const randomOverloads = [{
|
|
436
|
+
params: [DataType.float1],
|
|
437
|
+
returnType: DataType.float1,
|
|
438
|
+
}];
|
|
439
|
+
|
|
440
|
+
if (args.length === 0) {
|
|
441
|
+
const { id, dimension } = functionCallNode(strandsContext, 'random', nodeArgs, {
|
|
442
|
+
overloads: randomOverloads,
|
|
443
|
+
});
|
|
444
|
+
return createStrandsNode(id, dimension, strandsContext);
|
|
445
|
+
} else if (args.length === 1) {
|
|
446
|
+
// random(max) → [0, max)
|
|
447
|
+
const rawNode = functionCallNode(strandsContext, 'random', nodeArgs, {
|
|
448
|
+
overloads: randomOverloads,
|
|
449
|
+
});
|
|
450
|
+
const rawStrandsNode = createStrandsNode(rawNode.id, rawNode.dimension, strandsContext);
|
|
451
|
+
return rawStrandsNode.mult(p5.strandsNode(args[0]));
|
|
452
|
+
} else if (args.length === 2) {
|
|
453
|
+
// random(min, max) → [min, max)
|
|
454
|
+
const rawNode = functionCallNode(strandsContext, 'random', nodeArgs, {
|
|
455
|
+
overloads: randomOverloads,
|
|
456
|
+
});
|
|
457
|
+
const rawStrandsNode = createStrandsNode(rawNode.id, rawNode.dimension, strandsContext);
|
|
458
|
+
const minNode = p5.strandsNode(args[0]);
|
|
459
|
+
const maxNode = p5.strandsNode(args[1]);
|
|
460
|
+
// min + raw * (max - min)
|
|
461
|
+
return rawStrandsNode.mult(maxNode.sub(minNode)).add(minNode);
|
|
462
|
+
} else {
|
|
463
|
+
p5._friendlyError(
|
|
464
|
+
`It looks like you've called random() with ${args.length} arguments. In strands, random() supports 0, 1, or 2 numeric arguments.`
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
|
|
356
469
|
augmentFn(fn, p5, 'millis', function (...args) {
|
|
357
470
|
if (!strandsContext.active) {
|
|
358
471
|
return originalMillis.apply(this, args);
|
|
@@ -464,6 +577,53 @@ function initGlobalStrandsAPI(p5, fn, strandsContext) {
|
|
|
464
577
|
}
|
|
465
578
|
});
|
|
466
579
|
}
|
|
580
|
+
|
|
581
|
+
// Storage buffer uniform function for compute shaders
|
|
582
|
+
fn.uniformStorage = function(name, bufferOrSchema) {
|
|
583
|
+
let schema = null;
|
|
584
|
+
let defaultValue = null;
|
|
585
|
+
|
|
586
|
+
// If it's a function, evaluate it immediately to infer schema,
|
|
587
|
+
// then store the function so it gets called each frame.
|
|
588
|
+
let value = bufferOrSchema;
|
|
589
|
+
if (typeof bufferOrSchema === 'function') {
|
|
590
|
+
value = bufferOrSchema();
|
|
591
|
+
if (value?._schema) {
|
|
592
|
+
defaultValue = bufferOrSchema;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
if (value?._schema) {
|
|
597
|
+
// Struct storage buffer with pre-computed schema
|
|
598
|
+
schema = value._schema;
|
|
599
|
+
if (defaultValue === null) defaultValue = value;
|
|
600
|
+
} else if (value && typeof value === 'object' && !value._isStorageBuffer) {
|
|
601
|
+
// Plain object schema template -- only used to infer struct layout, not as a default value
|
|
602
|
+
schema = strandsContext.renderer?._inferStructSchema(value) ?? null;
|
|
603
|
+
} else if (value?._isStorageBuffer) {
|
|
604
|
+
defaultValue = bufferOrSchema;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
const { id, dimension } = variableNode(
|
|
608
|
+
strandsContext,
|
|
609
|
+
{ baseType: 'storage', dimension: 1 },
|
|
610
|
+
name
|
|
611
|
+
);
|
|
612
|
+
strandsContext.uniforms.push({
|
|
613
|
+
name,
|
|
614
|
+
typeInfo: { baseType: 'storage', dimension: 1, schema },
|
|
615
|
+
defaultValue,
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
// Create StrandsNode with _originalIdentifier set (like varying variables)
|
|
619
|
+
// This enables proper assignment node creation and ordering preservation
|
|
620
|
+
const node = createStrandsNode(id, dimension, strandsContext);
|
|
621
|
+
node._originalIdentifier = name;
|
|
622
|
+
node._originalBaseType = 'storage';
|
|
623
|
+
node._originalDimension = 1;
|
|
624
|
+
node._schema = schema;
|
|
625
|
+
return node;
|
|
626
|
+
};
|
|
467
627
|
}
|
|
468
628
|
//////////////////////////////////////////////
|
|
469
629
|
// Per-Hook functions
|
|
@@ -582,10 +742,14 @@ function createShaderHooksFunctions(strandsContext, fn, shader) {
|
|
|
582
742
|
const fragmentHooksWithContext = Object.fromEntries(
|
|
583
743
|
Object.entries(shader.hooks.fragment).map(([name, hook]) => [name, { ...hook, shaderContext: 'fragment' }])
|
|
584
744
|
);
|
|
745
|
+
const computeHooksWithContext = Object.fromEntries(
|
|
746
|
+
Object.entries(shader.hooks.compute).map(([name, hook]) => [name, { ...hook, shaderContext: 'compute' }])
|
|
747
|
+
);
|
|
585
748
|
|
|
586
749
|
const availableHooks = {
|
|
587
750
|
...vertexHooksWithContext,
|
|
588
751
|
...fragmentHooksWithContext,
|
|
752
|
+
...computeHooksWithContext,
|
|
589
753
|
};
|
|
590
754
|
const hookTypes = Object.keys(availableHooks).map(name => shader.hookTypes(name));
|
|
591
755
|
|
|
@@ -615,9 +779,11 @@ function createShaderHooksFunctions(strandsContext, fn, shader) {
|
|
|
615
779
|
if (numStructArgs === 1) {
|
|
616
780
|
argIdx = hookType.parameters.findIndex(param => param.type.properties);
|
|
617
781
|
}
|
|
782
|
+
hook._properties = [];
|
|
618
783
|
for (let i = 0; i < args.length; i++) {
|
|
619
784
|
if (i === argIdx) {
|
|
620
785
|
for (const key of args[argIdx].structProperties || []) {
|
|
786
|
+
hook._properties.push(key);
|
|
621
787
|
Object.defineProperty(hook, key, {
|
|
622
788
|
get() {
|
|
623
789
|
return args[argIdx][key];
|
|
@@ -632,6 +798,7 @@ function createShaderHooksFunctions(strandsContext, fn, shader) {
|
|
|
632
798
|
hook.set(args[argIdx]);
|
|
633
799
|
}
|
|
634
800
|
} else {
|
|
801
|
+
hook._properties.push(hookType.parameters[i].name);
|
|
635
802
|
hook[hookType.parameters[i].name] = args[i];
|
|
636
803
|
}
|
|
637
804
|
}
|
|
@@ -702,17 +869,21 @@ function createShaderHooksFunctions(strandsContext, fn, shader) {
|
|
|
702
869
|
return newStruct.id;
|
|
703
870
|
}
|
|
704
871
|
}
|
|
872
|
+
else if (!expectedReturnType.dataType || expectedReturnType.typeName?.trim() === 'void') {
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
705
875
|
else /*if(isNativeType(expectedReturnType.typeName))*/ {
|
|
706
|
-
if (!expectedReturnType.dataType) {
|
|
707
|
-
throw new Error(`Missing dataType for return type ${expectedReturnType.typeName}`);
|
|
708
|
-
}
|
|
709
876
|
const expectedTypeInfo = expectedReturnType.dataType;
|
|
710
877
|
return enforceReturnTypeMatch(strandsContext, expectedTypeInfo, retNode, hookType.name);
|
|
711
878
|
}
|
|
712
879
|
};
|
|
713
880
|
for (const { valueNode, earlyReturnID } of hook.earlyReturns) {
|
|
714
881
|
const id = handleRetVal(valueNode);
|
|
715
|
-
|
|
882
|
+
if (id !== null) {
|
|
883
|
+
dag.dependsOn[earlyReturnID] = [id];
|
|
884
|
+
} else {
|
|
885
|
+
dag.dependsOn[earlyReturnID] = [];
|
|
886
|
+
}
|
|
716
887
|
}
|
|
717
888
|
rootNodeID = userReturned ? handleRetVal(userReturned) : undefined;
|
|
718
889
|
const fullHookName = `${hookType.returnType.typeName} ${hookType.name}`;
|
|
@@ -721,7 +892,7 @@ function createShaderHooksFunctions(strandsContext, fn, shader) {
|
|
|
721
892
|
hookType,
|
|
722
893
|
entryBlockID,
|
|
723
894
|
rootNodeID,
|
|
724
|
-
shaderContext: hookInfo?.shaderContext, // 'vertex' or '
|
|
895
|
+
shaderContext: hookInfo?.shaderContext, // 'vertex', 'fragment', or 'compute'
|
|
725
896
|
});
|
|
726
897
|
popBlock(cfg);
|
|
727
898
|
} hook.begin = setupHook;
|
|
@@ -7,18 +7,26 @@ function generateShaderCode(strandsContext) {
|
|
|
7
7
|
cfg,
|
|
8
8
|
backend,
|
|
9
9
|
vertexDeclarations,
|
|
10
|
-
fragmentDeclarations
|
|
10
|
+
fragmentDeclarations,
|
|
11
|
+
computeDeclarations
|
|
11
12
|
} = strandsContext;
|
|
12
13
|
|
|
13
14
|
const hooksObj = {
|
|
14
15
|
uniforms: {},
|
|
16
|
+
storageUniforms: {},
|
|
15
17
|
varyingVariables: [],
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
for (const {name, typeInfo, defaultValue} of strandsContext.uniforms) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
if (typeInfo.baseType === 'storage') {
|
|
22
|
+
if (defaultValue !== null && defaultValue !== undefined) {
|
|
23
|
+
hooksObj.storageUniforms[name] = defaultValue;
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
const key = backend.generateHookUniformKey(name, typeInfo);
|
|
27
|
+
if (key !== null) {
|
|
28
|
+
hooksObj.uniforms[key] = defaultValue;
|
|
29
|
+
}
|
|
22
30
|
}
|
|
23
31
|
}
|
|
24
32
|
|
|
@@ -27,6 +35,11 @@ function generateShaderCode(strandsContext) {
|
|
|
27
35
|
backend.addTextureBindingsToDeclarations(strandsContext);
|
|
28
36
|
}
|
|
29
37
|
|
|
38
|
+
// Add storage buffer bindings to declarations for WebGPU backend
|
|
39
|
+
if (backend.addStorageBufferBindingsToDeclarations) {
|
|
40
|
+
backend.addStorageBufferBindingsToDeclarations(strandsContext);
|
|
41
|
+
}
|
|
42
|
+
|
|
30
43
|
for (const { hookType, rootNodeID, entryBlockID, shaderContext } of strandsContext.hooks) {
|
|
31
44
|
const generationContext = {
|
|
32
45
|
indent: 1,
|
|
@@ -51,14 +64,13 @@ function generateShaderCode(strandsContext) {
|
|
|
51
64
|
let returnType;
|
|
52
65
|
if (hookType.returnType.properties) {
|
|
53
66
|
returnType = structType(hookType.returnType);
|
|
67
|
+
} else if (!hookType.returnType.dataType || hookType.returnType.typeName?.trim() === 'void') {
|
|
68
|
+
returnType = null;
|
|
54
69
|
} else {
|
|
55
|
-
if (!hookType.returnType.dataType) {
|
|
56
|
-
throw new Error(`Missing dataType for return type ${hookType.returnType.typeName}`);
|
|
57
|
-
}
|
|
58
70
|
returnType = hookType.returnType.dataType;
|
|
59
71
|
}
|
|
60
72
|
|
|
61
|
-
if (rootNodeID) {
|
|
73
|
+
if (rootNodeID !== undefined) {
|
|
62
74
|
backend.generateReturnStatement(strandsContext, generationContext, rootNodeID, returnType);
|
|
63
75
|
}
|
|
64
76
|
hooksObj[`${hookType.returnType.typeName} ${hookType.name}`] = [firstLine, ...generationContext.codeLines, '}'].join('\n');
|
|
@@ -81,8 +93,14 @@ function generateShaderCode(strandsContext) {
|
|
|
81
93
|
}
|
|
82
94
|
}
|
|
83
95
|
|
|
96
|
+
// Register instanceID varying if used in a fragment hook
|
|
97
|
+
if (strandsContext._instanceIDUsedInFragment) {
|
|
98
|
+
hooksObj.instanceIDVarying = backend.generateInstanceIDVarying();
|
|
99
|
+
}
|
|
100
|
+
|
|
84
101
|
hooksObj.vertexDeclarations = [...vertexDeclarations].join('\n');
|
|
85
102
|
hooksObj.fragmentDeclarations = [...fragmentDeclarations].join('\n');
|
|
103
|
+
hooksObj.computeDeclarations = [...computeDeclarations].join('\n');
|
|
86
104
|
|
|
87
105
|
return hooksObj;
|
|
88
106
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createBasicBlock, addEdge, pushBlock, popBlock, pushBlockForModification, recordInBasicBlock } from './ir_cfg.js';
|
|
2
2
|
import { getOrCreateNode } from './ir_dag.js';
|
|
3
3
|
import { BlockType, NodeType } from './ir_types.js';
|
|
4
|
-
import { c as createStrandsNode } from '../ir_builders-
|
|
4
|
+
import { c as createStrandsNode } from '../ir_builders-C2ebb6Lu.js';
|
|
5
5
|
import { createPhiNode } from './strands_phi_utils.js';
|
|
6
6
|
import './strands_FES.js';
|
|
7
7
|
import './strands_builtins.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createBasicBlock, addEdge, pushBlock, popBlock, pushBlockForModification, recordInBasicBlock } from './ir_cfg.js';
|
|
2
2
|
import { getNodeDataFromID, createNodeData, getOrCreateNode } from './ir_dag.js';
|
|
3
3
|
import { BlockType, NodeType, StatementType, OpCode, BaseType } from './ir_types.js';
|
|
4
|
-
import { c as createStrandsNode, p as primitiveConstructorNode } from '../ir_builders-
|
|
4
|
+
import { c as createStrandsNode, p as primitiveConstructorNode } from '../ir_builders-C2ebb6Lu.js';
|
|
5
5
|
import { createPhiNode } from './strands_phi_utils.js';
|
|
6
6
|
import './strands_FES.js';
|
|
7
7
|
import './strands_builtins.js';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { extractNodeTypeInfo, propagateTypeToAssignOnUse, createNodeData, getOrCreateNode } from './ir_dag.js';
|
|
2
|
+
import { recordInBasicBlock } from './ir_cfg.js';
|
|
3
|
+
import { BaseType, OpCode, NodeType } from './ir_types.js';
|
|
4
|
+
import { c as createStrandsNode } from '../ir_builders-C2ebb6Lu.js';
|
|
5
|
+
import { userError } from './strands_FES.js';
|
|
6
|
+
import './strands_builtins.js';
|
|
7
|
+
|
|
8
|
+
function buildTernary(strandsContext, condition, ifTrue, ifFalse) {
|
|
9
|
+
const { dag, cfg, p5 } = strandsContext;
|
|
10
|
+
|
|
11
|
+
// Ensure all inputs are StrandsNodes
|
|
12
|
+
const condNode = condition?.isStrandsNode ? condition : p5.strandsNode(condition);
|
|
13
|
+
const trueNode = ifTrue?.isStrandsNode ? ifTrue : p5.strandsNode(ifTrue);
|
|
14
|
+
const falseNode = ifFalse?.isStrandsNode ? ifFalse : p5.strandsNode(ifFalse);
|
|
15
|
+
|
|
16
|
+
// Get type info for both nodes
|
|
17
|
+
let trueType = extractNodeTypeInfo(dag, trueNode.id);
|
|
18
|
+
let falseType = extractNodeTypeInfo(dag, falseNode.id);
|
|
19
|
+
|
|
20
|
+
// Propagate type from the known branch to any ASSIGN_ON_USE branch
|
|
21
|
+
if (trueType.baseType === BaseType.ASSIGN_ON_USE && falseType.baseType !== BaseType.ASSIGN_ON_USE) {
|
|
22
|
+
propagateTypeToAssignOnUse(dag, trueNode.id, falseType.baseType, falseType.dimension);
|
|
23
|
+
trueType = extractNodeTypeInfo(dag, trueNode.id);
|
|
24
|
+
} else if (falseType.baseType === BaseType.ASSIGN_ON_USE && trueType.baseType !== BaseType.ASSIGN_ON_USE) {
|
|
25
|
+
propagateTypeToAssignOnUse(dag, falseNode.id, trueType.baseType, trueType.dimension);
|
|
26
|
+
falseType = extractNodeTypeInfo(dag, falseNode.id);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// After ASSIGN_ON_USE propagation, if both types are known, they must match
|
|
30
|
+
if (
|
|
31
|
+
trueType.baseType !== BaseType.ASSIGN_ON_USE &&
|
|
32
|
+
falseType.baseType !== BaseType.ASSIGN_ON_USE &&
|
|
33
|
+
(trueType.baseType !== falseType.baseType || trueType.dimension !== falseType.dimension)
|
|
34
|
+
) {
|
|
35
|
+
userError('type error',
|
|
36
|
+
'The true and false branches of a ternary expression must have the same type. ' +
|
|
37
|
+
`Right now, the true branch is a ${trueType.baseType}${trueType.dimension}, and the false branch is a ${falseType.baseType}${falseType.dimension}.`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const resultType = trueType;
|
|
42
|
+
|
|
43
|
+
const nodeData = createNodeData({
|
|
44
|
+
nodeType: NodeType.OPERATION,
|
|
45
|
+
opCode: OpCode.Nary.TERNARY,
|
|
46
|
+
dependsOn: [condNode.id, trueNode.id, falseNode.id],
|
|
47
|
+
baseType: resultType.baseType,
|
|
48
|
+
dimension: resultType.dimension,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const id = getOrCreateNode(dag, nodeData);
|
|
52
|
+
recordInBasicBlock(cfg, cfg.currentBlock, id);
|
|
53
|
+
return createStrandsNode(id, resultType.dimension, strandsContext);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { buildTernary };
|