diff --git a/src/nodes/accessors/Arrays.js b/src/nodes/accessors/Arrays.js index ebfa666340a5e0..99a6ec180a5837 100644 --- a/src/nodes/accessors/Arrays.js +++ b/src/nodes/accessors/Arrays.js @@ -16,9 +16,9 @@ export const attributeArray = ( count, type = 'float' ) => { let itemSize, typedArray; - if ( type.isStruct === true ) { + if ( type.isStructTypeNode === true ) { - itemSize = type.layout.getLength(); + itemSize = type.getLength(); typedArray = getTypedArrayFromType( 'float' ); } else { @@ -48,9 +48,9 @@ export const instancedArray = ( count, type = 'float' ) => { let itemSize, typedArray; - if ( type.isStruct === true ) { + if ( type.isStructTypeNode === true ) { - itemSize = type.layout.getLength(); + itemSize = type.getLength(); typedArray = getTypedArrayFromType( 'float' ); } else { diff --git a/src/nodes/accessors/StorageBufferNode.js b/src/nodes/accessors/StorageBufferNode.js index 785366c3124219..5d68605be06e98 100644 --- a/src/nodes/accessors/StorageBufferNode.js +++ b/src/nodes/accessors/StorageBufferNode.js @@ -55,10 +55,10 @@ class StorageBufferNode extends BufferNode { let nodeType, structTypeNode = null; - if ( bufferType && bufferType.isStruct ) { + if ( bufferType && bufferType.isStructTypeNode ) { nodeType = 'struct'; - structTypeNode = bufferType.layout; + structTypeNode = bufferType; if ( value.isStorageBufferAttribute || value.isStorageInstancedBufferAttribute ) { diff --git a/src/nodes/accessors/StorageTextureNode.js b/src/nodes/accessors/StorageTextureNode.js index 4e0a2219a01aac..c7d00f83fbea3a 100644 --- a/src/nodes/accessors/StorageTextureNode.js +++ b/src/nodes/accessors/StorageTextureNode.js @@ -99,6 +99,20 @@ class StorageTextureNode extends TextureNode { } + /** + * Overwrites the default implementation since storage texture + * coordinates are texel coordinates and should not be transformed + * by the texture uv matrix. + * + * @param {Node} uvNode - The uv node. + * @return {Node} The unmodified uv node. + */ + getTransformedUV( uvNode ) { + + return uvNode; + + } + setup( builder ) { super.setup( builder ); diff --git a/src/nodes/code/FunctionNode.js b/src/nodes/code/FunctionNode.js index 9331df54b780c6..3914f3e9a4efeb 100644 --- a/src/nodes/code/FunctionNode.js +++ b/src/nodes/code/FunctionNode.js @@ -1,4 +1,5 @@ import CodeNode from './CodeNode.js'; +import { nodeProxyConstructor } from '../tsl/TSLCore.js'; /** * This class represents a native shader function. It can be used to implement @@ -155,26 +156,11 @@ export default FunctionNode; const nativeFn = ( code, includes = [], language = '' ) => { - for ( let i = 0; i < includes.length; i ++ ) { - - const include = includes[ i ]; - - // TSL Function: glslFn, wgslFn - - if ( typeof include === 'function' ) { - - includes[ i ] = include.functionNode; - - } - - } - const functionNode = new FunctionNode( code, includes, language ); const fn = ( ...params ) => functionNode.call( ...params ); - fn.functionNode = functionNode; - return fn; + return nodeProxyConstructor( fn, functionNode ); }; diff --git a/src/nodes/core/NodeUtils.js b/src/nodes/core/NodeUtils.js index 3425af6316dbb6..73ab12f5a0a59e 100644 --- a/src/nodes/core/NodeUtils.js +++ b/src/nodes/core/NodeUtils.js @@ -148,7 +148,7 @@ export function getTypedArrayFromType( type ) { */ export function getLengthFromType( type ) { - if ( /float|int|uint/.test( type ) ) return 1; + if ( /float|int|uint|bool/.test( type ) ) return 1; if ( /vec2/.test( type ) ) return 2; if ( /vec3/.test( type ) ) return 3; if ( /vec4/.test( type ) ) return 4; @@ -161,16 +161,16 @@ export function getLengthFromType( type ) { } /** - * Returns the gpu memory length for the given data type. + * Returns the gpu memory length for the given data type in 4-byte elements. * * @private * @method * @param {string} type - The data type. - * @return {number} The length. + * @return {number} The memory length in 4-byte elements. */ export function getMemoryLengthFromType( type ) { - if ( /float|int|uint/.test( type ) ) return 1; + if ( /float|int|uint|bool/.test( type ) ) return 1; if ( /vec2/.test( type ) ) return 2; if ( /vec3/.test( type ) ) return 3; if ( /vec4/.test( type ) ) return 4; @@ -183,22 +183,22 @@ export function getMemoryLengthFromType( type ) { } /** - * Returns the alignment requirement for the given data type. + * Returns the alignment requirement for the given data type in 4-byte elements. * * @private * @method * @param {string} type - The data type. - * @return {number} The alignment requirement in bytes. + * @return {number} The alignment requirement in 4-byte elements. */ export function getAlignmentFromType( type ) { - if ( /float|int|uint/.test( type ) ) return 4; - if ( /vec2/.test( type ) ) return 8; - if ( /vec3/.test( type ) ) return 16; - if ( /vec4/.test( type ) ) return 16; - if ( /mat2/.test( type ) ) return 8; - if ( /mat3/.test( type ) ) return 16; - if ( /mat4/.test( type ) ) return 16; + if ( /float|int|uint|bool/.test( type ) ) return 1; + if ( /vec2/.test( type ) ) return 2; + if ( /vec3/.test( type ) ) return 4; + if ( /vec4/.test( type ) ) return 4; + if ( /mat2/.test( type ) ) return 2; + if ( /mat3/.test( type ) ) return 4; + if ( /mat4/.test( type ) ) return 4; error( `TSL: Unsupported type: ${ type }`, new StackTrace() ); diff --git a/src/nodes/core/StructNode.js b/src/nodes/core/StructNode.js index 646c6d1efce98d..45653cbffc8e61 100644 --- a/src/nodes/core/StructNode.js +++ b/src/nodes/core/StructNode.js @@ -1,5 +1,6 @@ import Node from './Node.js'; import StructTypeNode from './StructTypeNode.js'; +import { nodeProxyConstructor } from '../tsl/TSLCore.js'; /** * StructNode allows to create custom structures with multiple members. @@ -94,7 +95,7 @@ export default StructNode; */ export const struct = ( membersLayout, name = null ) => { - const structLayout = new StructTypeNode( membersLayout, name ); + const structType = new StructTypeNode( membersLayout, name ); const struct = ( ...params ) => { @@ -122,13 +123,10 @@ export const struct = ( membersLayout, name = null ) => { } - return new StructNode( structLayout, values ); + return new StructNode( structType, values ); }; - struct.layout = structLayout; - struct.isStruct = true; - - return struct; + return nodeProxyConstructor( struct, structType ); }; diff --git a/src/nodes/core/StructTypeNode.js b/src/nodes/core/StructTypeNode.js index 862b9594a44dbd..c42aeec88c6630 100644 --- a/src/nodes/core/StructTypeNode.js +++ b/src/nodes/core/StructTypeNode.js @@ -74,19 +74,19 @@ class StructTypeNode extends Node { * @readonly * @default true */ - this.isStructLayoutNode = true; + this.isStructTypeNode = true; } /** - * Returns the length of the struct. - * The length is calculated by summing the lengths of the struct's members. + * Returns the length of the struct in 4-byte elements (e.g. float or int components). + * The length is calculated by summing the lengths of the struct's members, accounting for memory alignment. + * To get the size in bytes, multiply the returned value by 4. * - * @returns {number} The length of the struct. + * @returns {number} The length of the struct in 4-byte elements. */ getLength() { - const BYTES_PER_ELEMENT = Float32Array.BYTES_PER_ELEMENT; let maxAlignment = 1; // maximum alignment value in this struct let offset = 0; // global buffer offset in 4 byte elements @@ -95,7 +95,7 @@ class StructTypeNode extends Node { const type = member.type; const itemSize = getMemoryLengthFromType( type ); - const alignment = getAlignmentFromType( type ) / BYTES_PER_ELEMENT; + const alignment = getAlignmentFromType( type ); maxAlignment = Math.max( maxAlignment, alignment ); const chunkOffset = offset % maxAlignment; // offset in the current chunk of maxAlignment elements diff --git a/src/nodes/tsl/TSLCore.js b/src/nodes/tsl/TSLCore.js index 1146029dd77939..291c84be4a781e 100644 --- a/src/nodes/tsl/TSLCore.js +++ b/src/nodes/tsl/TSLCore.js @@ -985,6 +985,26 @@ export const nodeProxy = ( NodeClass, scope = null, factor = null, settings = nu export const nodeImmutable = ( NodeClass, ...params ) => new ShaderNodeImmutable( NodeClass, ...params ); export const nodeProxyIntent = ( NodeClass, scope = null, factor = null, settings = {} ) => new ShaderNodeProxy( NodeClass, scope, factor, { ...settings, intent: true } ); +export const nodeProxyConstructor = ( constructorFunction, nodeInstance ) => { + + return new Proxy( constructorFunction, { + + get( target, prop, receiver ) { + + return Reflect.get( nodeInstance, prop, receiver ); + + }, + + set( target, prop, value ) { + + return Reflect.set( nodeInstance, prop, value ); + + } + + } ); + +}; + let fnId = 0; class FnNode extends Node {