Skip to content

Commit 98a78a7

Browse files
committed
adding types to builtin functions
1 parent 0797a1b commit 98a78a7

File tree

1 file changed

+62
-43
lines changed

1 file changed

+62
-43
lines changed

src/webgl/ShaderGen.js

Lines changed: 62 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import { parse } from 'acorn';
9-
import { simple } from 'acorn-walk';
9+
import { ancestor } from 'acorn-walk';
1010
import escodegen from 'escodegen';
1111

1212
function shadergen(p5, fn) {
@@ -23,7 +23,7 @@ function shadergen(p5, fn) {
2323
ecmaVersion: 2021,
2424
locations: options.srcLocations
2525
});
26-
simple(ast, ASTCallbacks);
26+
ancestor(ast, ASTCallbacks);
2727
const transpiledSource = escodegen.generate(ast);
2828
generatorFunction = new Function(
2929
transpiledSource.slice(
@@ -103,7 +103,6 @@ function shadergen(p5, fn) {
103103
},
104104
}
105105

106-
107106
// Javascript Node API.
108107
// These classes are for expressing GLSL functions in Javascript without
109108
// needing to transpile the user's code.
@@ -114,7 +113,6 @@ function shadergen(p5, fn) {
114113
}
115114
this.type = type;
116115
this.componentNames = [];
117-
this.swizzleAccessed = false;
118116
this.swizzleChanged = false;
119117
// For tracking recursion depth and creating temporary variables
120118
this.isInternal = isInternal;
@@ -151,7 +149,6 @@ function shadergen(p5, fn) {
151149
let value = new ComponentNode(this, componentName, 'float', true);
152150
Object.defineProperty(this, componentName, {
153151
get() {
154-
this.swizzleAccessed = true;
155152
return value;
156153
},
157154
set(newValue) {
@@ -215,7 +212,6 @@ function shadergen(p5, fn) {
215212
mod(other) { return new ModulusNode(this, this.enforceType(other)); }
216213

217214
// Check that the types of the operands are compatible.
218-
// TODO: improve this with less branching if elses
219215
enforceType(other){
220216
if (isShaderNode(other)){
221217
if ((isFloatNode(this) || isVectorNode(this)) && isIntNode(other)) {
@@ -228,7 +224,10 @@ function shadergen(p5, fn) {
228224
return new IntNode(other);
229225
}
230226
return new FloatNode(other);
231-
}
227+
}
228+
else if(Array.isArray(other)) {
229+
return new VectorNode(other, `vec${other.length}`)
230+
}
232231
else {
233232
return new this.constructor(other);
234233
}
@@ -474,7 +473,7 @@ function shadergen(p5, fn) {
474473
return (isShaderNode(node) && (node.type === 'float'));
475474
}
476475

477-
function isVectorNode(node) {
476+
function isVectorNode(node) {
478477
return (isShaderNode(node) && (node.type === 'vec2'|| node.type === 'vec3' || node.type === 'vec4'));
479478
}
480479

@@ -507,27 +506,35 @@ function shadergen(p5, fn) {
507506
return this.output;
508507
}
509508

509+
// This method generates the hook overrides which the user calls in their modify function.
510510
generateHookOverrides(originalShader) {
511511
const availableHooks = {
512512
...originalShader.hooks.vertex,
513513
...originalShader.hooks.fragment,
514514
}
515-
// Defines a function for each of the hooks for the shader we are modifying.
515+
516516
Object.keys(availableHooks).forEach((hookName) => {
517517
const hookTypes = originalShader.hookTypes(hookName)
518518
console.log(hookTypes);
519+
519520
this[hookTypes.name] = function(userOverride) {
520521
let argNodes = []
522+
521523
const argsArray = hookTypes.parameters.map((parameter) => {
522524
argNodes.push(
523525
new VariableNode(parameter.name, parameter.type.typeName, true)
524526
);
525527
const qualifiers = parameter.type.qualifiers.length > 0 ? parameter.type.qualifiers.join(' ') : '';
526528
return `${qualifiers} ${parameter.type.typeName} ${parameter.name}`.trim();
527529
});
528-
529530
const argsString = `(${argsArray.join(', ')}) {`;
530-
const toGLSLResult = userOverride(...argNodes).toGLSLBase(this.context);
531+
532+
let returnedValue = userOverride(...argNodes);
533+
if (!isShaderNode(returnedValue)) {
534+
const expectedReturnType = hookTypes.returnType;
535+
returnedValue = nodeConstructors[expectedReturnType.typeName](returnedValue)
536+
}
537+
const toGLSLResult = returnedValue.toGLSLBase(this.context);
531538
let codeLines = [ argsString, ...this.context.declarations ];
532539
codeLines.push(`\n${hookTypes.returnType.typeName} finalReturnValue = ${toGLSLResult};
533540
\nreturn finalReturnValue;
@@ -602,13 +609,12 @@ function shadergen(p5, fn) {
602609

603610
ShaderGenerator.prototype[uniformMethodName] = function(...args) {
604611
let [name, ...defaultValue] = args;
612+
605613
if(glslType.startsWith('vec')) {
606614
defaultValue = conformVectorParameters(defaultValue, +glslType.slice(3));
607615
this.output.uniforms[`${glslType} ${name}`] = defaultValue;
608616
}
609617
else {
610-
console.log("defaultValue: ",defaultValue);
611-
console.log("defaultValue[0]: ",defaultValue[0])
612618
this.output.uniforms[`${glslType} ${name}`] = defaultValue[0];
613619
}
614620

@@ -637,59 +643,69 @@ function shadergen(p5, fn) {
637643
}
638644

639645
// GLSL Built in functions
640-
// TODO:
641646
// Add a whole lot of these functions.
642647
// https://docs.gl/el3/abs
648+
// TODO:
649+
// In reality many of these have multiple overrides which will need to address later.
650+
// Also, their return types depend on the genType which will need to address urgently
651+
// genType clamp(genType x,
652+
// genType minVal,
653+
// genType maxVal);
654+
// genType clamp(genType x,
655+
// float minVal,
656+
// float maxVal);
657+
643658

644-
// constructor(name, args, type, isInternal = false) {
645659

646660
const builtInFunctions = {
647-
// Trigonometry
648-
'acos': {},
661+
//////////// Trigonometry //////////
662+
'acos': { args: ['genType'], returnType: 'float'},
649663
// 'acosh': {},
650-
'asin': {},
664+
'asin': { args: ['genType'], returnType: 'float'},
651665
// 'asinh': {},
652-
'atan': {},
666+
'atan': { args: ['genType'], returnType: 'float'},
653667
// 'atanh': {},
654-
'cos': {},
668+
'cos': { args: ['genType'], returnType: 'float', isp5Function: true},
655669
// 'cosh': {},
656-
'degrees': {},
657-
'radians': {},
658-
'sin': {},
670+
'degrees': { args: ['genType'], returnType: 'float'},
671+
'radians': { args: ['genType'], returnType: 'float'},
672+
'sin': { args: ['genType'], returnType: 'float' , isp5Function: true},
659673
// 'sinh': {},
660-
'tan': {},
674+
'tan': { args: ['genType'], returnType: 'float', isp5Function: true},
661675
// 'tanh': {},
662-
// Mathematics
663-
'abs': {},
664-
'ceil': {},
665-
'clamp': {},
666-
'dFdx': {},
667-
'dFdy': {},
668-
'exp': {},
669-
'exp2': {},
670-
'floor': {},
676+
677+
////////// Mathematics //////////
678+
'abs': { args: ['genType'], returnType: 'float'},
679+
'ceil': { args: ['genType'], returnType: 'float'},
680+
'clamp': { args: ['genType', 'genType', 'genType'], returnType: 'float'},
681+
// 'dFdx': {},
682+
// 'dFdy': {},
683+
'exp': { args: ['genType'], returnType: 'float'},
684+
'exp2': { args: ['genType'], returnType: 'float'},
685+
'floor': { args: ['genType'], returnType: 'float'},
671686
// 'fma': {},
672-
'fract': {},
687+
'fract': { args: ['genType'], returnType: 'float'},
673688
// 'fwidth': {},
674689
// 'inversesqrt': {},
675690
// 'isinf': {},
676691
// 'isnan': {},
677692
// 'log': {},
678693
// 'log2': {},
679-
'max': {},
680-
'min': {},
681-
'mix': {},
694+
'max': { args: ['genType'], returnType: 'genType'},
695+
'min': { args: ['genType'], returnType: 'genType'},
696+
'mix': { args: ['genType'], returnType: 'genType'},
682697
// 'mod': {},
683698
// 'modf': {},
684-
'pow': {},
699+
'pow': { args: ['genType'], returnType: 'float'},
685700
// 'round': {},
686701
// 'roundEven': {},
687702
// 'sign': {},
688-
'smoothstep': {},
689-
'sqrt': {},
690-
'step': {},
703+
'smoothstep': { args: ['genType', 'genType', 'genType'], returnType: 'float'},
704+
'sqrt': { args: ['genType'], returnType: 'genType'},
705+
'step': { args: ['genType', 'genType'], returnType: 'genType'},
691706
// 'trunc': {},
692-
// Vector
707+
708+
////////// Vector //////////
693709
'cross': {},
694710
'distance': {},
695711
'dot': {},
@@ -704,7 +720,10 @@ function shadergen(p5, fn) {
704720
'texture': {},
705721
}
706722

707-
// Object.entries(builtInFunctions).forEach(([glslFnName, properties]) => {
723+
// Object.entries(builtInFunctions).forEach(([functionName, properties]) => {
724+
// fn[functionName] = function () {
725+
// new FunctionCallNode(functionName, args, type, isInternal = false)
726+
// }
708727
// })
709728

710729
const oldTexture = p5.prototype.texture;

0 commit comments

Comments
 (0)