Skip to content

Commit 9cac072

Browse files
committed
input structs now working
1 parent 01ef185 commit 9cac072

File tree

1 file changed

+59
-28
lines changed

1 file changed

+59
-28
lines changed

src/webgl/ShaderGen.js

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ function shadergen(p5, fn) {
112112
arguments: [node.left, node.right]
113113
}
114114
node.left = leftReplacementNode;
115-
console.log(escodegen.generate(leftReplacementNode))
116115
}
117116

118117
// Replace the binary operator with a call expression
@@ -141,6 +140,7 @@ function shadergen(p5, fn) {
141140
// Javascript Node API.
142141
// These classes are for expressing GLSL functions in Javascript without
143142
// needing to transpile the user's code.
143+
144144
class BaseNode {
145145
constructor(isInternal, type) {
146146
if (new.target === BaseNode) {
@@ -248,6 +248,9 @@ function shadergen(p5, fn) {
248248
// Check that the types of the operands are compatible.
249249
enforceType(other){
250250
if (isShaderNode(other)){
251+
if (!isGLSLNativeType(other.type)) {
252+
throw new TypeError (`You've tried to perform an operation on a struct of type: ${other.type}. Try accessing a member on that struct with '.'`)
253+
}
251254
if ((isFloatNode(this) || isVectorNode(this)) && isIntNode(other)) {
252255
return new FloatNode(other)
253256
}
@@ -366,6 +369,7 @@ function shadergen(p5, fn) {
366369
this.name = name;
367370
this.addVectorComponents();
368371
}
372+
369373
toGLSL(context) {
370374
return `${this.name}`;
371375
}
@@ -519,13 +523,20 @@ function shadergen(p5, fn) {
519523
return (node instanceof VariableNode || node instanceof ComponentNode || typeof(node.temporaryVariable) != 'undefined');
520524
}
521525

526+
// Helper function to check if a type is a user defined struct or native type
527+
function isGLSLNativeType(typeName) {
528+
// Supported types for now
529+
const glslNativeTypes = ['int', 'float', 'vec2', 'vec3', 'vec4', 'sampler2D'];
530+
return glslNativeTypes.includes(typeName);
531+
}
532+
522533
// Shader Generator
523534
// This class is responsible for converting the nodes into an object containing GLSL code, to be used by p5.Shader.modify
524535

525536
class ShaderGenerator {
526-
constructor(modifyFunction, originalShader, srcLocations) {
537+
constructor(userCallback, originalShader, srcLocations) {
527538
GLOBAL_SHADER = this;
528-
this.modifyFunction = modifyFunction;
539+
this.userCallback = userCallback;
529540
this.srcLocations = srcLocations;
530541
this.generateHookOverrides(originalShader);
531542
this.output = {
@@ -535,8 +546,7 @@ function shadergen(p5, fn) {
535546
}
536547

537548
generate() {
538-
this.modifyFunction();
539-
console.log(this.output);
549+
this.userCallback();
540550
return this.output;
541551
}
542552

@@ -548,31 +558,52 @@ function shadergen(p5, fn) {
548558
}
549559

550560
Object.keys(availableHooks).forEach((hookName) => {
551-
const hookTypes = originalShader.hookTypes(hookName)
552-
// console.log(hookTypes);
553-
554-
this[hookTypes.name] = function(userOverride) {
561+
const hookTypes = originalShader.hookTypes(hookName);
562+
this[hookTypes.name] = function(userCallback) {
563+
// Create the initial nodes which are passed to the user callback
564+
// Also generate a string of the arguments for the code generation
555565
let argNodes = []
556-
557-
const argsArray = hookTypes.parameters.map((parameter) => {
558-
argNodes.push(
559-
new VariableNode(parameter.name, parameter.type.typeName, true)
560-
);
566+
let argsArray = [];
567+
hookTypes.parameters.forEach((parameter) => {
568+
if (!isGLSLNativeType(parameter.type.typeName)) {
569+
let structArg = {};
570+
parameter.type.properties.forEach((property) => {
571+
structArg[property.name] = new VariableNode(`${parameter.name}.${property.name}`, property.type.typeName, true);
572+
});
573+
argNodes.push(structArg);
574+
} else {
575+
argNodes.push(
576+
new VariableNode(parameter.name, parameter.type.typeName, true)
577+
);
578+
}
561579
const qualifiers = parameter.type.qualifiers.length > 0 ? parameter.type.qualifiers.join(' ') : '';
562-
return `${qualifiers} ${parameter.type.typeName} ${parameter.name}`.trim();
563-
});
564-
const argsString = `(${argsArray.join(', ')}) {`;
580+
argsArray.push(`${qualifiers} ${parameter.type.typeName} ${parameter.name}`.trim())
581+
})
565582

566-
let returnedValue = userOverride(...argNodes);
567-
if (!isShaderNode(returnedValue)) {
568-
const expectedReturnType = hookTypes.returnType;
583+
let returnedValue = userCallback(...argNodes);
584+
const expectedReturnType = hookTypes.returnType;
585+
const toGLSLResults = {};
586+
// If the expected return type is a struct we need to evaluate each of its properties
587+
if (!isGLSLNativeType(expectedReturnType.typeName)) {
588+
Object.entries(returnedValue).forEach(([propertyName, propertyNode]) => {
589+
toGLSLResults[propertyName] = propertyNode.toGLSLBase(this.context);
590+
})
591+
} else {
592+
// We can accept raw numbers or arrays otherwise
593+
if (!isShaderNode(returnedValue)) {
569594
returnedValue = nodeConstructors[expectedReturnType.typeName](returnedValue)
595+
}
596+
toGLSLResults['notAProperty'] = returnedValue.toGLSLBase(this.context);
570597
}
571-
const toGLSLResult = returnedValue.toGLSLBase(this.context);
572-
let codeLines = [ argsString, ...this.context.declarations ];
573-
codeLines.push(`\n${hookTypes.returnType.typeName} finalReturnValue = ${toGLSLResult};
574-
\nreturn finalReturnValue;
575-
\n}`);
598+
599+
// Build the final GLSL string:
600+
let codeLines = [ `(${argsArray.join(', ')}) {`, ...this.context.declarations ];
601+
codeLines.push(`${hookTypes.returnType.typeName} finalReturnValue;`);
602+
Object.entries(toGLSLResults).forEach(([propertyName, result]) => {
603+
const propString = expectedReturnType.properties ? `.${propertyName}` : '';
604+
codeLines.push(`finalReturnValue${propString} = ${result};`)
605+
})
606+
codeLines.push('return finalReturnValue;', '}');
576607
this.output[hookName] = codeLines.join('\n');
577608
this.resetGLSLContext();
578609
}
@@ -619,7 +650,7 @@ function shadergen(p5, fn) {
619650

620651
// Generating uniformFloat, uniformVec, createFloat, etc functions
621652
// Maps a GLSL type to the name suffix for method names
622-
const GLSLTypesToSuffixes = {
653+
const GLSLTypesToIdentifiers = {
623654
int: 'Int',
624655
float: 'Float',
625656
vec2: 'Vector2',
@@ -636,9 +667,9 @@ function shadergen(p5, fn) {
636667
vec4: (value) => new VectorNode(value, 'vec4'),
637668
};
638669

639-
for (const glslType in GLSLTypesToSuffixes) {
670+
for (const glslType in GLSLTypesToIdentifiers) {
640671
// Generate uniform*() Methods for creating uniforms
641-
const typeIdentifier = GLSLTypesToSuffixes[glslType];
672+
const typeIdentifier = GLSLTypesToIdentifiers[glslType];
642673
const uniformMethodName = `uniform${typeIdentifier}`;
643674

644675
ShaderGenerator.prototype[uniformMethodName] = function(...args) {

0 commit comments

Comments
 (0)