@@ -112,7 +112,6 @@ function shadergen(p5, fn) {
112
112
arguments : [ node . left , node . right ]
113
113
}
114
114
node . left = leftReplacementNode ;
115
- console . log ( escodegen . generate ( leftReplacementNode ) )
116
115
}
117
116
118
117
// Replace the binary operator with a call expression
@@ -141,6 +140,7 @@ function shadergen(p5, fn) {
141
140
// Javascript Node API.
142
141
// These classes are for expressing GLSL functions in Javascript without
143
142
// needing to transpile the user's code.
143
+
144
144
class BaseNode {
145
145
constructor ( isInternal , type ) {
146
146
if ( new . target === BaseNode ) {
@@ -248,6 +248,9 @@ function shadergen(p5, fn) {
248
248
// Check that the types of the operands are compatible.
249
249
enforceType ( other ) {
250
250
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
+ }
251
254
if ( ( isFloatNode ( this ) || isVectorNode ( this ) ) && isIntNode ( other ) ) {
252
255
return new FloatNode ( other )
253
256
}
@@ -366,6 +369,7 @@ function shadergen(p5, fn) {
366
369
this . name = name ;
367
370
this . addVectorComponents ( ) ;
368
371
}
372
+
369
373
toGLSL ( context ) {
370
374
return `${ this . name } ` ;
371
375
}
@@ -519,13 +523,20 @@ function shadergen(p5, fn) {
519
523
return ( node instanceof VariableNode || node instanceof ComponentNode || typeof ( node . temporaryVariable ) != 'undefined' ) ;
520
524
}
521
525
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
+
522
533
// Shader Generator
523
534
// This class is responsible for converting the nodes into an object containing GLSL code, to be used by p5.Shader.modify
524
535
525
536
class ShaderGenerator {
526
- constructor ( modifyFunction , originalShader , srcLocations ) {
537
+ constructor ( userCallback , originalShader , srcLocations ) {
527
538
GLOBAL_SHADER = this ;
528
- this . modifyFunction = modifyFunction ;
539
+ this . userCallback = userCallback ;
529
540
this . srcLocations = srcLocations ;
530
541
this . generateHookOverrides ( originalShader ) ;
531
542
this . output = {
@@ -535,8 +546,7 @@ function shadergen(p5, fn) {
535
546
}
536
547
537
548
generate ( ) {
538
- this . modifyFunction ( ) ;
539
- console . log ( this . output ) ;
549
+ this . userCallback ( ) ;
540
550
return this . output ;
541
551
}
542
552
@@ -548,31 +558,61 @@ function shadergen(p5, fn) {
548
558
}
549
559
550
560
Object . keys ( availableHooks ) . forEach ( ( hookName ) => {
551
- const hookTypes = originalShader . hookTypes ( hookName )
552
- // console.log(hookTypes);
553
-
554
- this [ hookTypes . name ] = function ( userOverride ) {
555
- let argNodes = [ ]
556
-
557
- const argsArray = hookTypes . parameters . map ( ( parameter ) => {
558
- argNodes . push (
559
- new VariableNode ( parameter . name , parameter . type . typeName , true )
560
- ) ;
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
565
+ const argNodes = [ ]
566
+ const argsArray = [ ] ;
567
+
568
+ hookTypes . parameters . forEach ( ( parameter ) => {
569
+ // For hooks with structs as input we should pass an object populated with variable nodes
570
+ if ( ! isGLSLNativeType ( parameter . type . typeName ) ) {
571
+ const structArg = { } ;
572
+ parameter . type . properties . forEach ( ( property ) => {
573
+ structArg [ property . name ] = new VariableNode ( `${ parameter . name } .${ property . name } ` , property . type . typeName , true ) ;
574
+ } ) ;
575
+ argNodes . push ( structArg ) ;
576
+ } else {
577
+ argNodes . push (
578
+ new VariableNode ( parameter . name , parameter . type . typeName , true )
579
+ ) ;
580
+ }
561
581
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 ( ', ' ) } ) {` ;
582
+ argsArray . push ( `${ qualifiers } ${ parameter . type . typeName } ${ parameter . name } ` . trim ( ) )
583
+ } )
565
584
566
- let returnedValue = userOverride ( ...argNodes ) ;
567
- if ( ! isShaderNode ( returnedValue ) ) {
568
- const expectedReturnType = hookTypes . returnType ;
585
+ let returnedValue = userCallback ( ...argNodes ) ;
586
+ const expectedReturnType = hookTypes . returnType ;
587
+ const toGLSLResults = { } ;
588
+
589
+ // If the expected return type is a struct we need to evaluate each of its properties
590
+ if ( ! isGLSLNativeType ( expectedReturnType . typeName ) ) {
591
+ Object . entries ( returnedValue ) . forEach ( ( [ propertyName , propertyNode ] ) => {
592
+ toGLSLResults [ propertyName ] = propertyNode . toGLSLBase ( this . context ) ;
593
+ } )
594
+ } else {
595
+ // We can accept raw numbers or arrays otherwise
596
+ if ( ! isShaderNode ( returnedValue ) ) {
569
597
returnedValue = nodeConstructors [ expectedReturnType . typeName ] ( returnedValue )
598
+ }
599
+ toGLSLResults [ 'notAProperty' ] = returnedValue . toGLSLBase ( this . context ) ;
570
600
}
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}` ) ;
601
+
602
+ // Build the final GLSL string.
603
+ // The order of this code is a bit confusing, we need to call toGLSLBase
604
+ let codeLines = [
605
+ `(${ argsArray . join ( ', ' ) } ) {` ,
606
+ ...this . context . declarations ,
607
+ `${ hookTypes . returnType . typeName } finalReturnValue;`
608
+ ] ;
609
+
610
+ Object . entries ( toGLSLResults ) . forEach ( ( [ propertyName , result ] ) => {
611
+ const propString = expectedReturnType . properties ? `.${ propertyName } ` : '' ;
612
+ codeLines . push ( `finalReturnValue${ propString } = ${ result } ;` )
613
+ } )
614
+
615
+ codeLines . push ( 'return finalReturnValue;' , '}' ) ;
576
616
this . output [ hookName ] = codeLines . join ( '\n' ) ;
577
617
this . resetGLSLContext ( ) ;
578
618
}
@@ -619,7 +659,7 @@ function shadergen(p5, fn) {
619
659
620
660
// Generating uniformFloat, uniformVec, createFloat, etc functions
621
661
// Maps a GLSL type to the name suffix for method names
622
- const GLSLTypesToSuffixes = {
662
+ const GLSLTypesToIdentifiers = {
623
663
int : 'Int' ,
624
664
float : 'Float' ,
625
665
vec2 : 'Vector2' ,
@@ -636,9 +676,9 @@ function shadergen(p5, fn) {
636
676
vec4 : ( value ) => new VectorNode ( value , 'vec4' ) ,
637
677
} ;
638
678
639
- for ( const glslType in GLSLTypesToSuffixes ) {
679
+ for ( const glslType in GLSLTypesToIdentifiers ) {
640
680
// Generate uniform*() Methods for creating uniforms
641
- const typeIdentifier = GLSLTypesToSuffixes [ glslType ] ;
681
+ const typeIdentifier = GLSLTypesToIdentifiers [ glslType ] ;
642
682
const uniformMethodName = `uniform${ typeIdentifier } ` ;
643
683
644
684
ShaderGenerator . prototype [ uniformMethodName ] = function ( ...args ) {
0 commit comments