From 4e9491cecc3ab31bbfdfbf4a7efa1732c9576a14 Mon Sep 17 00:00:00 2001 From: Nathan Bierema Date: Wed, 29 May 2024 09:35:58 -0400 Subject: [PATCH] Use more built declarations (#997) * Add examples * Update patch * Update * Update patch * Update patch * Add CubeRenderTarget * Update patch * Add more * Update patch * Add more * Update patch * Add NodeFunction * Update patch * Delete examples * Update * Use built NodeBuilder * Add examples * Add ContextNode * Update patch * Delete examples * Use built ContextNode * Add examples * Delete examples * Add CubeRenderTarget * Add examples * Update patch * Update patch * Update patch * Add StructTypeNode * Update patch * Delete examples * Add GLSLNodeBuilder * Add BufferAttributeNode * Update patch * Add isInterleavedBuffer * Update patch * Update patch * Update patch * Delete examples * Update * Add examples * Update patch * Delete examples * Update * Add examples * Update patch * Del * Not quite ready yet * Not ready * Add examples * Update patch * Delete examples * Update --- examples-jsm/changes.patch | 1830 ++++++++++++++++- examples-jsm/create-examples.js | 11 + examples-jsm/declarations.js | 3 + .../nodes/accessors/BufferAttributeNode.d.ts | 49 + .../examples/jsm/nodes/core/NodeCache.d.ts | 2 + .../examples/jsm/nodes/core/NodeParser.d.ts | 5 +- .../jsm/nodes/core/StructTypeNode.d.ts | 8 + .../examples/jsm/nodes/core/UniformNode.d.ts | 5 +- .../renderers/common/CubeRenderTarget.d.ts | 7 + .../common/nodes/NodeBuilderState.d.ts | 1 + types/three/src/core/InterleavedBuffer.d.ts | 2 + types/three/src/math/Matrix3.d.ts | 2 + types/three/src/math/Matrix4.d.ts | 2 + 13 files changed, 1825 insertions(+), 102 deletions(-) create mode 100644 types/three/examples/jsm/nodes/accessors/BufferAttributeNode.d.ts create mode 100644 types/three/examples/jsm/nodes/core/StructTypeNode.d.ts create mode 100644 types/three/examples/jsm/renderers/common/CubeRenderTarget.d.ts diff --git a/examples-jsm/changes.patch b/examples-jsm/changes.patch index 2a038b599..7454379b0 100644 --- a/examples-jsm/changes.patch +++ b/examples-jsm/changes.patch @@ -1,5 +1,166 @@ +diff --git a/examples-jsm/examples/nodes/accessors/BufferAttributeNode.ts b/examples-jsm/examples/nodes/accessors/BufferAttributeNode.ts +index 4f7bbae4..88c9a245 100644 +--- a/examples-jsm/examples/nodes/accessors/BufferAttributeNode.ts ++++ b/examples-jsm/examples/nodes/accessors/BufferAttributeNode.ts +@@ -2,10 +2,36 @@ import InputNode from '../core/InputNode.js'; + import { addNodeClass } from '../core/Node.js'; + import { varying } from '../core/VaryingNode.js'; + import { nodeObject, addNodeElement } from '../shadernode/ShaderNode.js'; +-import { InterleavedBufferAttribute, InterleavedBuffer, StaticDrawUsage, DynamicDrawUsage } from 'three'; +- +-class BufferAttributeNode extends InputNode { +- constructor(value, bufferType = null, bufferStride = 0, bufferOffset = 0) { ++import { ++ InterleavedBufferAttribute, ++ InterleavedBuffer, ++ StaticDrawUsage, ++ DynamicDrawUsage, ++ Usage, ++ BufferAttribute, ++ InstancedBufferAttribute, ++ TypedArray, ++} from 'three'; ++import NodeBuilder from '../core/NodeBuilder.js'; ++ ++class BufferAttributeNode extends InputNode { ++ readonly isBufferNode: true; ++ ++ bufferType: string | null; ++ bufferStride: number; ++ bufferOffset: number; ++ ++ usage: Usage; ++ instanced: boolean; ++ ++ attribute: BufferAttribute | InterleavedBufferAttribute | null; ++ ++ constructor( ++ value: TypedArray | InterleavedBuffer | BufferAttribute, ++ bufferType: string | null = null, ++ bufferStride = 0, ++ bufferOffset = 0, ++ ) { + super(value, bufferType); + + this.isBufferNode = true; +@@ -19,14 +45,14 @@ class BufferAttributeNode extends InputNode { + + this.attribute = null; + +- if (value && value.isBufferAttribute === true) { +- this.attribute = value; +- this.usage = value.usage; +- this.instanced = value.isInstancedBufferAttribute; ++ if (value && (value as BufferAttribute).isBufferAttribute === true) { ++ this.attribute = value as BufferAttribute; ++ this.usage = (value as BufferAttribute).usage; ++ this.instanced = (value as InstancedBufferAttribute).isInstancedBufferAttribute; + } + } + +- getNodeType(builder) { ++ getNodeType(builder: NodeBuilder) { + if (this.bufferType === null) { + this.bufferType = builder.getTypeFromAttribute(this.attribute); + } +@@ -34,16 +60,19 @@ class BufferAttributeNode extends InputNode { + return this.bufferType; + } + +- setup(builder) { ++ setup(builder: NodeBuilder) { + if (this.attribute !== null) return; + + const type = this.getNodeType(builder); +- const array = this.value; ++ const array = this.value as TypedArray | InterleavedBuffer; + const itemSize = builder.getTypeLength(type); + const stride = this.bufferStride || itemSize; + const offset = this.bufferOffset; + +- const buffer = array.isInterleavedBuffer === true ? array : new InterleavedBuffer(array, stride); ++ const buffer = ++ (array as InterleavedBuffer).isInterleavedBuffer === true ++ ? (array as InterleavedBuffer) ++ : new InterleavedBuffer(array as TypedArray, stride); + const bufferAttribute = new InterleavedBufferAttribute(buffer, itemSize, offset); + + buffer.setUsage(this.usage); +@@ -52,13 +81,13 @@ class BufferAttributeNode extends InputNode { + this.attribute.isInstancedBufferAttribute = this.instanced; // @TODO: Add a possible: InstancedInterleavedBufferAttribute + } + +- generate(builder) { ++ generate(builder: NodeBuilder) { + const nodeType = this.getNodeType(builder); + + const nodeAttribute = builder.getBufferAttributeFromNode(this, nodeType); + const propertyName = builder.getPropertyName(nodeAttribute); + +- let output = null; ++ let output: string | null | undefined = null; + + if (builder.shaderStage === 'vertex' || builder.shaderStage === 'compute') { + this.name = propertyName; +@@ -77,13 +106,13 @@ class BufferAttributeNode extends InputNode { + return 'bufferAttribute'; + } + +- setUsage(value) { ++ setUsage(value: Usage) { + this.usage = value; + + return this; + } + +- setInstanced(value) { ++ setInstanced(value: boolean) { + this.instanced = value; + + return this; +@@ -92,15 +121,31 @@ class BufferAttributeNode extends InputNode { + + export default BufferAttributeNode; + +-export const bufferAttribute = (array, type, stride, offset) => +- nodeObject(new BufferAttributeNode(array, type, stride, offset)); +-export const dynamicBufferAttribute = (array, type, stride, offset) => +- bufferAttribute(array, type, stride, offset).setUsage(DynamicDrawUsage); +- +-export const instancedBufferAttribute = (array, type, stride, offset) => +- bufferAttribute(array, type, stride, offset).setInstanced(true); +-export const instancedDynamicBufferAttribute = (array, type, stride, offset) => +- dynamicBufferAttribute(array, type, stride, offset).setInstanced(true); ++export const bufferAttribute = ( ++ array: TypedArray | InterleavedBuffer | BufferAttribute, ++ type?: string | null, ++ stride?: number, ++ offset?: number, ++) => nodeObject(new BufferAttributeNode(array, type, stride, offset)); ++export const dynamicBufferAttribute = ( ++ array: TypedArray | InterleavedBuffer | BufferAttribute, ++ type?: string | null, ++ stride?: number, ++ offset?: number, ++) => bufferAttribute(array, type, stride, offset).setUsage(DynamicDrawUsage); ++ ++export const instancedBufferAttribute = ( ++ array: TypedArray | InterleavedBuffer | BufferAttribute, ++ type?: string | null, ++ stride?: number, ++ offset?: number, ++) => bufferAttribute(array, type, stride, offset).setInstanced(true); ++export const instancedDynamicBufferAttribute = ( ++ array: TypedArray | InterleavedBuffer | BufferAttribute, ++ type?: string | null, ++ stride?: number, ++ offset?: number, ++) => dynamicBufferAttribute(array, type, stride, offset).setInstanced(true); + + addNodeElement('toAttribute', bufferNode => bufferAttribute(bufferNode.value)); + diff --git a/examples-jsm/examples/nodes/accessors/TextureNode.ts b/examples-jsm/examples/nodes/accessors/TextureNode.ts -index 73a989fe..87b7a155 100644 +index 73a989fe..39012303 100644 --- a/examples-jsm/examples/nodes/accessors/TextureNode.ts +++ b/examples-jsm/examples/nodes/accessors/TextureNode.ts @@ -3,13 +3,34 @@ import { uv } from './UVNode.js'; @@ -90,19 +251,19 @@ index 73a989fe..87b7a155 100644 } - generateUV(builder, uvNode) { -+ generateUV(builder: NodeBuilder, uvNode) { ++ generateUV(builder: NodeBuilder, uvNode: Node) { return uvNode.build(builder, this.sampler === true ? 'vec2' : 'ivec2'); } - generateSnippet(builder, textureProperty, uvSnippet, levelSnippet, depthSnippet, compareSnippet, gradSnippet) { + generateSnippet( + builder: NodeBuilder, -+ textureProperty, -+ uvSnippet, -+ levelSnippet, -+ depthSnippet, -+ compareSnippet, -+ gradSnippet, ++ textureProperty: string, ++ uvSnippet: string | null, ++ levelSnippet: string | null, ++ depthSnippet: string | null, ++ compareSnippet: string | null, ++ gradSnippet: [string, string] | null, + ) { const texture = this.value; @@ -152,6 +313,151 @@ index 73a989fe..87b7a155 100644 const textureNode = this.clone(); textureNode.levelNode = levelNode; textureNode.referenceNode = this; +diff --git a/examples-jsm/examples/nodes/code/CodeNode.ts b/examples-jsm/examples/nodes/code/CodeNode.ts +index 06347564..1f81819b 100644 +--- a/examples-jsm/examples/nodes/code/CodeNode.ts ++++ b/examples-jsm/examples/nodes/code/CodeNode.ts +@@ -1,7 +1,13 @@ + import Node, { addNodeClass } from '../core/Node.js'; + import { nodeProxy } from '../shadernode/ShaderNode.js'; ++import NodeBuilder from '../core/NodeBuilder.js'; + + class CodeNode extends Node { ++ readonly isCodeNode: true; ++ ++ code: string; ++ language: string; ++ + constructor(code = '', includes = [], language = '') { + super('code'); + +@@ -23,11 +29,11 @@ class CodeNode extends Node { + return this; + } + +- getIncludes(/*builder*/) { ++ getIncludes(builder: NodeBuilder) { + return this.includes; + } + +- generate(builder) { ++ generate(builder: NodeBuilder) { + const includes = this.getIncludes(builder); + + for (const include of includes) { +diff --git a/examples-jsm/examples/nodes/code/FunctionNode.ts b/examples-jsm/examples/nodes/code/FunctionNode.ts +index feeb5a55..d16e2359 100644 +--- a/examples-jsm/examples/nodes/code/FunctionNode.ts ++++ b/examples-jsm/examples/nodes/code/FunctionNode.ts +@@ -1,6 +1,7 @@ + import CodeNode from './CodeNode.js'; + import { addNodeClass } from '../core/Node.js'; + import { nodeObject } from '../shadernode/ShaderNode.js'; ++import NodeBuilder from '../core/NodeBuilder.js'; + + class FunctionNode extends CodeNode { + constructor(code = '', includes = [], language = '') { +@@ -9,15 +10,15 @@ class FunctionNode extends CodeNode { + this.keywords = {}; + } + +- getNodeType(builder) { ++ getNodeType(builder: NodeBuilder) { + return this.getNodeFunction(builder).type; + } + +- getInputs(builder) { ++ getInputs(builder: NodeBuilder) { + return this.getNodeFunction(builder).inputs; + } + +- getNodeFunction(builder) { ++ getNodeFunction(builder: NodeBuilder) { + const nodeData = builder.getDataFromNode(this); + + let nodeFunction = nodeData.nodeFunction; +@@ -31,7 +32,7 @@ class FunctionNode extends CodeNode { + return nodeFunction; + } + +- generate(builder, output) { ++ generate(builder: NodeBuilder, output?: string | null) { + super.generate(builder); + + const nodeFunction = this.getNodeFunction(builder); +@@ -75,7 +76,7 @@ class FunctionNode extends CodeNode { + + export default FunctionNode; + +-const nativeFn = (code, includes = [], language = '') => { ++const nativeFn = (code: string, includes = [], language = '') => { + for (let i = 0; i < includes.length; i++) { + const include = includes[i]; + +@@ -94,7 +95,7 @@ const nativeFn = (code, includes = [], language = '') => { + return fn; + }; + +-export const glslFn = (code, includes) => nativeFn(code, includes, 'glsl'); +-export const wgslFn = (code, includes) => nativeFn(code, includes, 'wgsl'); ++export const glslFn = (code: string, includes) => nativeFn(code, includes, 'glsl'); ++export const wgslFn = (code: string, includes) => nativeFn(code, includes, 'wgsl'); + + addNodeClass('FunctionNode', FunctionNode); +diff --git a/examples-jsm/examples/nodes/core/ContextNode.ts b/examples-jsm/examples/nodes/core/ContextNode.ts +index 2ac1d499..b5d2c58c 100644 +--- a/examples-jsm/examples/nodes/core/ContextNode.ts ++++ b/examples-jsm/examples/nodes/core/ContextNode.ts +@@ -1,8 +1,14 @@ + import Node, { addNodeClass } from './Node.js'; +-import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js'; ++import { addNodeElement, nodeProxy, NodeRepresentation } from '../shadernode/ShaderNode.js'; ++import NodeBuilder from './NodeBuilder.js'; + +-class ContextNode extends Node { +- constructor(node, context = {}) { ++class ContextNode extends Node { ++ readonly isContextNode: true; ++ ++ node: Node; ++ context: TContext; ++ ++ constructor(node: Node, context: TContext = {} as TContext) { + super(); + + this.isContextNode = true; +@@ -11,11 +17,11 @@ class ContextNode extends Node { + this.context = context; + } + +- getNodeType(builder) { ++ getNodeType(builder: NodeBuilder) { + return this.node.getNodeType(builder); + } + +- setup(builder) { ++ setup(builder: NodeBuilder) { + const previousContext = builder.getContext(); + + builder.setContext({ ...builder.context, ...this.context }); +@@ -27,7 +33,7 @@ class ContextNode extends Node { + return node; + } + +- generate(builder, output) { ++ generate(builder: NodeBuilder, output?: string | null) { + const previousContext = builder.getContext(); + + builder.setContext({ ...builder.context, ...this.context }); +@@ -43,7 +49,7 @@ class ContextNode extends Node { + export default ContextNode; + + export const context = nodeProxy(ContextNode); +-export const label = (node, name) => context(node, { label: name }); ++export const label = (node: NodeRepresentation, name: string) => context(node, { label: name }); + + addNodeElement('context', context); + addNodeElement('label', label); diff --git a/examples-jsm/examples/nodes/core/InputNode.ts b/examples-jsm/examples/nodes/core/InputNode.ts index 4d52ec26..5987158d 100644 --- a/examples-jsm/examples/nodes/core/InputNode.ts @@ -674,7 +980,7 @@ index 190fe8c5..d873bb24 100644 this.name = name; diff --git a/examples-jsm/examples/nodes/core/NodeBuilder.ts b/examples-jsm/examples/nodes/core/NodeBuilder.ts -index ebdc13ff..664d5325 100644 +index ebdc13ff..c001676b 100644 --- a/examples-jsm/examples/nodes/core/NodeBuilder.ts +++ b/examples-jsm/examples/nodes/core/NodeBuilder.ts @@ -8,7 +8,7 @@ import NodeCache from './NodeCache.js'; @@ -686,7 +992,7 @@ index ebdc13ff..664d5325 100644 import { FloatNodeUniform, -@@ -30,6 +30,12 @@ import { +@@ -30,17 +30,41 @@ import { IntType, UnsignedIntType, Float16BufferAttribute, @@ -696,13 +1002,26 @@ index ebdc13ff..664d5325 100644 + BufferGeometry, + Scene, + RenderTargetOptions, ++ Texture, ++ DataTexture, ++ BufferAttribute, ++ InterleavedBufferAttribute, ++ TypedArray, ++ Matrix3, ++ Matrix4, } from 'three'; - import { stack } from './StackNode.js'; -@@ -39,6 +45,16 @@ import CubeRenderTarget from '../../renderers/common/CubeRenderTarget.js'; +-import { stack } from './StackNode.js'; +-import { getCurrentStack, setCurrentStack } from '../shadernode/ShaderNode.js'; ++import StackNode, { stack } from './StackNode.js'; ++import { getCurrentStack, setCurrentStack, ShaderNodeInternal, ShaderNodeObject } from '../shadernode/ShaderNode.js'; + + import CubeRenderTarget from '../../renderers/common/CubeRenderTarget.js'; import ChainMap from '../../renderers/common/ChainMap.js'; import PMREMGenerator from '../../renderers/common/extras/PMREMGenerator.js'; +- +-const uniformsGroupCache = new ChainMap(); +import Renderer from '../../renderers/common/Renderer.js'; +import NodeParser from './NodeParser.js'; +import Node from './Node.js'; @@ -713,14 +1032,57 @@ index ebdc13ff..664d5325 100644 +import Binding from '../../renderers/common/Binding.js'; +import NodeUniformsGroup from '../../renderers/common/nodes/NodeUniformsGroup.js'; +import UniformNode from './UniformNode.js'; - - const uniformsGroupCache = new ChainMap(); - -@@ -67,10 +83,77 @@ const toFloat = value => { ++import StructTypeNode from './StructTypeNode.js'; ++ ++const uniformsGroupCache = new ChainMap[], Binding>(); + + const typeFromLength = new Map([ + [2, 'vec2'], +@@ -50,7 +74,16 @@ const typeFromLength = new Map([ + [16, 'mat4'], + ]); + +-const typeFromArray = new Map([ ++type TypedArrayConstructor = ++ | typeof Int8Array ++ | typeof Int16Array ++ | typeof Int32Array ++ | typeof Uint8Array ++ | typeof Uint16Array ++ | typeof Uint32Array ++ | typeof Float32Array; ++ ++const typeFromArray = new Map([ + [Int8Array, 'int'], + [Int16Array, 'int'], + [Int32Array, 'int'], +@@ -60,17 +93,92 @@ const typeFromArray = new Map([ + [Float32Array, 'float'], + ]); + +-const toFloat = value => { ++const toFloat = (value: unknown) => { + value = Number(value); + +- return value + (value % 1 ? '' : '.0'); ++ return value + ((value as number) % 1 ? '' : '.0'); }; - class NodeBuilder { +-class NodeBuilder { - constructor(object, renderer, parser, scene = null, material = null) { ++interface Flow { ++ code: string; ++ result?: string | null | undefined; ++ vars?: string | undefined; ++} ++ ++interface Context { ++ keywords: NodeKeywords; ++ material: Material | Material[]; ++ tempRead?: boolean; ++} ++ ++abstract class NodeBuilder { + object: Object3D; + material: Material | Material[]; + geometry: BufferGeometry; @@ -744,40 +1106,36 @@ index ebdc13ff..664d5325 100644 + computeShader: string | null; + + flowNodes: { vertex: Node[]; fragment: Node[]; compute: Node[] }; -+ // TODO -+ // flowCode ++ flowCode: { vertex: string; fragment: string; compute: string }; + uniforms: { + vertex: NodeUniform[]; + fragment: NodeUniform[]; + compute: NodeUniform[]; + index: number; + }; -+ structs: { vertex: Node[]; fragment: Node[]; compute: Node[]; index: number }; ++ structs: { vertex: StructTypeNode[]; fragment: StructTypeNode[]; compute: StructTypeNode[]; index: number }; + bindings: { vertex: Binding[]; fragment: Binding[]; compute: Binding[] }; + bindingsOffset: { vertex: number; fragment: number; compute: number }; -+ bindingsArray: Binding[]; ++ bindingsArray: Binding[] | null; + attributes: NodeAttribute[]; + bufferAttributes: NodeAttribute[]; + varyings: NodeVarying[]; + codes: { vertex?: NodeCode[] | undefined; fragment?: NodeCode[] | undefined; compute?: NodeCode[] | undefined }; + vars: { vertex?: NodeVar[] | undefined; fragment?: NodeVar[] | undefined; compute?: NodeVar[] | undefined }; -+ flow: { code: string }; ++ flow: Flow; + chaining: Node[]; -+ // TODO -+ // stack -+ // stacks ++ stack: ShaderNodeObject; ++ stacks: ShaderNodeObject[]; + tab: string; + -+ // TODO -+ // currentFunctionNode ++ currentFunctionNode: FunctionNode | null; + -+ context: { keywords: NodeKeywords; material: Material | Material[]; tempRead?: boolean }; ++ context: Context; + + cache: NodeCache; + globalCache: NodeCache; + -+ // TODO -+ // flowsData ++ flowsData: WeakMap; + + shaderStage: NodeShaderStage | null; + buildStage: string | null; @@ -797,7 +1155,23 @@ index ebdc13ff..664d5325 100644 this.renderer = renderer; this.parser = parser; this.scene = scene; -@@ -124,7 +207,7 @@ class NodeBuilder { +@@ -91,7 +199,7 @@ class NodeBuilder { + this.computeShader = null; + + this.flowNodes = { vertex: [], fragment: [], compute: [] }; +- this.flowCode = { vertex: '', fragment: '', compute: [] }; ++ this.flowCode = { vertex: '', fragment: '', compute: '' }; + this.uniforms = { vertex: [], fragment: [], compute: [], index: 0 }; + this.structs = { vertex: [], fragment: [], compute: [], index: 0 }; + this.bindings = { vertex: [], fragment: [], compute: [] }; +@@ -118,17 +226,17 @@ class NodeBuilder { + this.cache = new NodeCache(); + this.globalCache = this.cache; + +- this.flowsData = new WeakMap(); ++ this.flowsData = new WeakMap(); + + this.shaderStage = null; this.buildStage = null; } @@ -806,7 +1180,12 @@ index ebdc13ff..664d5325 100644 return new RenderTarget(width, height, options); } -@@ -138,17 +221,17 @@ class NodeBuilder { +- createCubeRenderTarget(size, options) { ++ createCubeRenderTarget(size?: number, options?: RenderTargetOptions) { + return new CubeRenderTarget(size, options); + } + +@@ -138,17 +246,17 @@ class NodeBuilder { return new PMREMGenerator(this.renderer); } @@ -816,8 +1195,9 @@ index ebdc13ff..664d5325 100644 } - _getSharedBindings(bindings) { +- const shared = []; + _getSharedBindings(bindings: Binding[]) { - const shared = []; ++ const shared: Binding[] = []; for (const binding of bindings) { - if (binding.shared === true) { @@ -828,7 +1208,7 @@ index ebdc13ff..664d5325 100644 let sharedBinding = uniformsGroupCache.get(nodes); -@@ -181,11 +264,11 @@ class NodeBuilder { +@@ -181,11 +289,11 @@ class NodeBuilder { return bindingsArray; } @@ -842,7 +1222,7 @@ index ebdc13ff..664d5325 100644 if (this.nodes.includes(node) === false) { this.nodes.push(node); -@@ -212,7 +295,7 @@ class NodeBuilder { +@@ -212,7 +320,7 @@ class NodeBuilder { return this.chaining[this.chaining.length - 1]; } @@ -851,7 +1231,7 @@ index ebdc13ff..664d5325 100644 /* if ( this.chaining.indexOf( node ) !== - 1 ) { -@@ -224,7 +307,7 @@ class NodeBuilder { +@@ -224,7 +332,7 @@ class NodeBuilder { this.chaining.push(node); } @@ -860,7 +1240,7 @@ index ebdc13ff..664d5325 100644 const lastChain = this.chaining.pop(); if (lastChain !== node) { -@@ -232,15 +315,15 @@ class NodeBuilder { +@@ -232,21 +340,21 @@ class NodeBuilder { } } @@ -879,7 +1259,14 @@ index ebdc13ff..664d5325 100644 this.flowNodes[shaderStage].push(node); return node; -@@ -254,7 +337,7 @@ class NodeBuilder { + } + +- setContext(context) { ++ setContext(context: Context) { + this.context = context; + } + +@@ -254,7 +362,7 @@ class NodeBuilder { return this.context; } @@ -888,7 +1275,7 @@ index ebdc13ff..664d5325 100644 this.cache = cache; } -@@ -262,7 +345,7 @@ class NodeBuilder { +@@ -262,7 +370,7 @@ class NodeBuilder { return this.cache; } @@ -897,7 +1284,98 @@ index ebdc13ff..664d5325 100644 return false; } -@@ -332,7 +415,7 @@ class NodeBuilder { +@@ -286,15 +394,45 @@ class NodeBuilder { + return false; + } + +- generateTexture(/* texture, textureProperty, uvSnippet */) { +- console.warn('Abstract function.'); +- } +- +- generateTextureLod(/* texture, textureProperty, uvSnippet, levelSnippet */) { +- console.warn('Abstract function.'); +- } +- +- generateConst(type, value = null) { ++ abstract generateTexture( ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ depthSnippet: string | null, ++ ): string; ++ ++ abstract generateTextureLevel( ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ levelSnippet: string | null, ++ depthSnippet: string | null, ++ ): string; ++ ++ abstract generateTextureGrad( ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ gradSnippet: [string, string] | null, ++ depthSnippet: string | null, ++ ): string; ++ ++ abstract generateTextureCompare( ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ compareSnippet: string | null, ++ depthSnippet: string | null, ++ ): string; ++ ++ abstract generateTextureLoad( ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ depthSnippet: string | null, ++ ): string; ++ ++ generateConst(type: string | null, value: unknown = null): string { + if (value === null) { + if (type === 'float' || type === 'int' || type === 'uint') value = 0; + else if (type === 'bool') value = false; +@@ -305,26 +443,26 @@ class NodeBuilder { + } + + if (type === 'float') return toFloat(value); +- if (type === 'int') return `${Math.round(value)}`; +- if (type === 'uint') return value >= 0 ? `${Math.round(value)}u` : '0u'; ++ if (type === 'int') return `${Math.round(value as number)}`; ++ if (type === 'uint') return (value as number) >= 0 ? `${Math.round(value as number)}u` : '0u'; + if (type === 'bool') return value ? 'true' : 'false'; + if (type === 'color') +- return `${this.getType('vec3')}( ${toFloat(value.r)}, ${toFloat(value.g)}, ${toFloat(value.b)} )`; ++ return `${this.getType('vec3')}( ${toFloat((value as Color).r)}, ${toFloat((value as Color).g)}, ${toFloat((value as Color).b)} )`; + + const typeLength = this.getTypeLength(type); + + const componentType = this.getComponentType(type); + +- const generateConst = value => this.generateConst(componentType, value); ++ const generateConst = (value: unknown) => this.generateConst(componentType, value); + + if (typeLength === 2) { +- return `${this.getType(type)}( ${generateConst(value.x)}, ${generateConst(value.y)} )`; ++ return `${this.getType(type)}( ${generateConst((value as Vector2).x)}, ${generateConst((value as Vector2).y)} )`; + } else if (typeLength === 3) { +- return `${this.getType(type)}( ${generateConst(value.x)}, ${generateConst(value.y)}, ${generateConst(value.z)} )`; ++ return `${this.getType(type)}( ${generateConst((value as Vector3).x)}, ${generateConst((value as Vector3).y)}, ${generateConst((value as Vector3).z)} )`; + } else if (typeLength === 4) { +- return `${this.getType(type)}( ${generateConst(value.x)}, ${generateConst(value.y)}, ${generateConst(value.z)}, ${generateConst(value.w)} )`; +- } else if (typeLength > 4 && value && (value.isMatrix3 || value.isMatrix4)) { +- return `${this.getType(type)}( ${value.elements.map(generateConst).join(', ')} )`; ++ return `${this.getType(type)}( ${generateConst((value as Vector4).x)}, ${generateConst((value as Vector4).y)}, ${generateConst((value as Vector4).z)}, ${generateConst((value as Vector4).w)} )`; ++ } else if (typeLength > 4 && value && ((value as Matrix3).isMatrix3 || (value as Matrix4).isMatrix4)) { ++ return `${this.getType(type)}( ${(value as Matrix3 | Matrix4).elements.map(generateConst).join(', ')} )`; + } else if (typeLength > 4) { + return `${this.getType(type)}()`; + } +@@ -332,21 +470,17 @@ class NodeBuilder { throw new Error(`NodeBuilder: Type '${type}' not found in generate constant attempt.`); } @@ -906,8 +1384,42 @@ index ebdc13ff..664d5325 100644 if (type === 'color') return 'vec3'; return type; -@@ -378,7 +461,7 @@ class NodeBuilder { - return /mat\d/.test(type); + } + +- generateMethod(method) { +- return method; +- } +- +- hasGeometryAttribute(name) { ++ hasGeometryAttribute(name: string) { + return this.geometry && this.geometry.getAttribute(name) !== undefined; + } + +- getAttribute(name, type) { ++ getAttribute(name: string, type: string | null) { + const attributes = this.attributes; + + // find attribute +@@ -366,19 +500,19 @@ class NodeBuilder { + return attribute; + } + +- getPropertyName(node /*, shaderStage*/) { +- return node.name; ++ getPropertyName(node: unknown, shaderStage?: NodeShaderStage) { ++ return (node as { name?: string }).name; + } + +- isVector(type) { +- return /vec\d/.test(type); ++ isVector(type: string | null) { ++ return /vec\d/.test(type!); + } + +- isMatrix(type) { +- return /mat\d/.test(type); ++ isMatrix(type: string | null) { ++ return /mat\d/.test(type!); } - isReference(type) { @@ -915,16 +1427,29 @@ index ebdc13ff..664d5325 100644 return ( type === 'void' || type === 'property' || -@@ -405,7 +488,7 @@ class NodeBuilder { +@@ -394,10 +528,10 @@ class NodeBuilder { + return false; + } + +- getComponentTypeFromTexture(texture) { ++ getComponentTypeFromTexture(texture: Texture) { + const type = texture.type; + +- if (texture.isDataTexture) { ++ if ((texture as DataTexture).isDataTexture) { + if (type === IntType) return 'int'; + if (type === UnsignedIntType) return 'uint'; + } +@@ -405,7 +539,7 @@ class NodeBuilder { return 'float'; } - getElementType(type) { -+ getElementType(type: string | null) { ++ getElementType(type: string) { if (type === 'mat2') return 'vec2'; if (type === 'mat3') return 'vec3'; if (type === 'mat4') return 'vec4'; -@@ -413,7 +496,7 @@ class NodeBuilder { +@@ -413,7 +547,7 @@ class NodeBuilder { return this.getComponentType(type); } @@ -933,7 +1458,7 @@ index ebdc13ff..664d5325 100644 type = this.getVectorType(type); if (type === 'float' || type === 'bool' || type === 'int' || type === 'uint') return type; -@@ -429,7 +512,7 @@ class NodeBuilder { +@@ -429,7 +563,7 @@ class NodeBuilder { return 'float'; } @@ -942,16 +1467,76 @@ index ebdc13ff..664d5325 100644 if (type === 'color') return 'vec3'; if (type === 'texture' || type === 'cubeTexture' || type === 'storageTexture' || type === 'texture3D') return 'vec4'; -@@ -468,7 +551,7 @@ class NodeBuilder { +@@ -437,23 +571,23 @@ class NodeBuilder { + return type; + } + +- getTypeFromLength(length, componentType = 'float') { ++ getTypeFromLength(length: number, componentType: string | null = 'float') { + if (length === 1) return componentType; + + const baseType = typeFromLength.get(length); +- const prefix = componentType === 'float' ? '' : componentType[0]; ++ const prefix = componentType === 'float' ? '' : componentType![0]; + + return prefix + baseType; + } + +- getTypeFromArray(array) { +- return typeFromArray.get(array.constructor); ++ getTypeFromArray(array: TypedArray) { ++ return typeFromArray.get(array.constructor as TypedArrayConstructor); + } + +- getTypeFromAttribute(attribute) { +- let dataAttribute = attribute; +- +- if (attribute.isInterleavedBufferAttribute) dataAttribute = attribute.data; ++ getTypeFromAttribute(attribute: BufferAttribute | InterleavedBufferAttribute) { ++ const dataAttribute = (attribute as InterleavedBufferAttribute).isInterleavedBufferAttribute ++ ? (attribute as InterleavedBufferAttribute).data ++ : attribute; + + const array = dataAttribute.array; + const itemSize = attribute.itemSize; +@@ -468,28 +602,28 @@ class NodeBuilder { return this.getTypeFromLength(itemSize, arrayType); } - getTypeLength(type) { + getTypeLength(type: string | null) { const vecType = this.getVectorType(type); - const vecNum = /vec([2-4])/.exec(vecType); +- const vecNum = /vec([2-4])/.exec(vecType); ++ const vecNum = /vec([2-4])/.exec(vecType!); + + if (vecNum !== null) return Number(vecNum[1]); + if (vecType === 'float' || vecType === 'bool' || vecType === 'int' || vecType === 'uint') return 1; +- if (/mat2/.test(type) === true) return 4; +- if (/mat3/.test(type) === true) return 9; +- if (/mat4/.test(type) === true) return 16; ++ if (/mat2/.test(type!) === true) return 4; ++ if (/mat3/.test(type!) === true) return 9; ++ if (/mat4/.test(type!) === true) return 16; + + return 0; + } + +- getVectorFromMatrix(type) { ++ getVectorFromMatrix(type: string) { + return type.replace('mat', 'vec'); + } + +- changeComponentType(type, newComponentType) { ++ changeComponentType(type: string, newComponentType: string) { + return this.getTypeFromLength(this.getTypeLength(type), newComponentType); + } -@@ -515,7 +598,11 @@ class NodeBuilder { +- getIntegerType(type) { ++ getIntegerType(type: string) { + const componentType = this.getComponentType(type); + + if (componentType === 'int' || componentType === 'uint') return type; +@@ -515,7 +649,11 @@ class NodeBuilder { return lastStack; } @@ -964,7 +1549,7 @@ index ebdc13ff..664d5325 100644 cache = cache === null ? (node.isGlobal(this) ? this.globalCache : this.cache) : cache; let nodeData = cache.getNodeData(node); -@@ -528,16 +615,16 @@ class NodeBuilder { +@@ -528,16 +666,16 @@ class NodeBuilder { if (nodeData[shaderStage] === undefined) nodeData[shaderStage] = {}; @@ -984,16 +1569,16 @@ index ebdc13ff..664d5325 100644 const nodeData = this.getDataFromNode(node); let bufferAttribute = nodeData.bufferAttribute; -@@ -555,7 +642,7 @@ class NodeBuilder { +@@ -555,7 +693,7 @@ class NodeBuilder { return bufferAttribute; } - getStructTypeFromNode(node, shaderStage = this.shaderStage) { -+ getStructTypeFromNode(node: Node, shaderStage = this.shaderStage!) { ++ getStructTypeFromNode(node: StructTypeNode, shaderStage = this.shaderStage!) { const nodeData = this.getDataFromNode(node, shaderStage); if (nodeData.structType === undefined) { -@@ -570,7 +657,12 @@ class NodeBuilder { +@@ -570,7 +708,12 @@ class NodeBuilder { return node; } @@ -1007,7 +1592,7 @@ index ebdc13ff..664d5325 100644 const nodeData = this.getDataFromNode(node, shaderStage, this.globalCache); let nodeUniform = nodeData.uniform; -@@ -588,7 +680,12 @@ class NodeBuilder { +@@ -588,7 +731,12 @@ class NodeBuilder { return nodeUniform; } @@ -1021,7 +1606,7 @@ index ebdc13ff..664d5325 100644 const nodeData = this.getDataFromNode(node, shaderStage); let nodeVar = nodeData.variable; -@@ -608,7 +705,7 @@ class NodeBuilder { +@@ -608,7 +756,7 @@ class NodeBuilder { return nodeVar; } @@ -1030,7 +1615,7 @@ index ebdc13ff..664d5325 100644 const nodeData = this.getDataFromNode(node, 'any'); let nodeVarying = nodeData.varying; -@@ -629,7 +726,7 @@ class NodeBuilder { +@@ -629,7 +777,7 @@ class NodeBuilder { return nodeVarying; } @@ -1039,7 +1624,7 @@ index ebdc13ff..664d5325 100644 const nodeData = this.getDataFromNode(node); let nodeCode = nodeData.code; -@@ -648,7 +745,7 @@ class NodeBuilder { +@@ -648,7 +796,7 @@ class NodeBuilder { return nodeCode; } @@ -1048,7 +1633,7 @@ index ebdc13ff..664d5325 100644 if (code === '') return this; code = this.tab + code; -@@ -662,7 +759,7 @@ class NodeBuilder { +@@ -662,7 +810,7 @@ class NodeBuilder { return this; } @@ -1057,7 +1642,12 @@ index ebdc13ff..664d5325 100644 this.flow.code += code; return this; -@@ -684,7 +781,7 @@ class NodeBuilder { +@@ -680,11 +828,11 @@ class NodeBuilder { + return this; + } + +- getFlowData(node /*, shaderStage*/) { ++ getFlowData(node: Node /*, shaderStage*/) { return this.flowsData.get(node); } @@ -1066,7 +1656,163 @@ index ebdc13ff..664d5325 100644 const output = node.getNodeType(this); const flowData = this.flowChildNode(node, output); -@@ -940,7 +1037,7 @@ class NodeBuilder { +@@ -694,7 +842,9 @@ class NodeBuilder { + return flowData; + } + +- buildFunctionNode(shaderNode) { ++ abstract buildFunctionCode(shaderNode: ShaderNodeInternal): string; ++ ++ buildFunctionNode(shaderNode: ShaderNodeInternal) { + const fn = new FunctionNode(); + + const previous = this.currentFunctionNode; +@@ -708,7 +858,7 @@ class NodeBuilder { + return fn; + } + +- flowShaderNode(shaderNode) { ++ flowShaderNode(shaderNode: ShaderNodeInternal) { + const layout = shaderNode.layout; + + let inputs; +@@ -716,13 +866,13 @@ class NodeBuilder { + if (shaderNode.isArrayInput) { + inputs = []; + +- for (const input of layout.inputs) { ++ for (const input of layout!.inputs) { + inputs.push(new ParameterNode(input.type, input.name)); + } + } else { + inputs = {}; + +- for (const input of layout.inputs) { ++ for (const input of layout!.inputs) { + inputs[input.name] = new ParameterNode(input.type, input.name); + } + } +@@ -739,12 +889,12 @@ class NodeBuilder { + return flowData; + } + +- flowStagesNode(node, output = null) { ++ flowStagesNode(node: Node, output: string | null = null) { + const previousFlow = this.flow; + const previousVars = this.vars; + const previousBuildStage = this.buildStage; + +- const flow = { ++ const flow: Flow = { + code: '', + }; + +@@ -757,7 +907,7 @@ class NodeBuilder { + flow.result = node.build(this, output); + } + +- flow.vars = this.getVars(this.shaderStage); ++ flow.vars = this.getVars(this.shaderStage!); + + this.flow = previousFlow; + this.vars = previousVars; +@@ -770,10 +920,10 @@ class NodeBuilder { + return null; + } + +- flowChildNode(node, output = null) { ++ flowChildNode(node: Node, output: string | null = null) { + const previousFlow = this.flow; + +- const flow = { ++ const flow: Flow = { + code: '', + }; + +@@ -786,7 +936,12 @@ class NodeBuilder { + return flow; + } + +- flowNodeFromShaderStage(shaderStage, node, output = null, propertyName = null) { ++ flowNodeFromShaderStage( ++ shaderStage: 'vertex' | 'fragment' | 'compute', ++ node: Node, ++ output: string | null = null, ++ propertyName: string | null = null, ++ ) { + const previousShaderStage = this.shaderStage; + + this.setShaderStage(shaderStage); +@@ -808,19 +963,15 @@ class NodeBuilder { + return this.attributes.concat(this.bufferAttributes); + } + +- getAttributes(/*shaderStage*/) { +- console.warn('Abstract function.'); +- } ++ abstract getAttributes(shaderStage: NodeShaderStage): string; + +- getVaryings(/*shaderStage*/) { +- console.warn('Abstract function.'); +- } ++ abstract getVaryings(shaderStage: NodeShaderStage): string; + +- getVar(type, name) { ++ getVar(type: string | null, name: string) { + return `${this.getType(type)} ${name}`; + } + +- getVars(shaderStage) { ++ getVars(shaderStage: 'vertex' | 'fragment' | 'compute') { + let snippet = ''; + + const vars = this.vars[shaderStage]; +@@ -834,11 +985,9 @@ class NodeBuilder { + return snippet; + } + +- getUniforms(/*shaderStage*/) { +- console.warn('Abstract function.'); +- } ++ abstract getUniforms(shaderStage: NodeShaderStage): string; + +- getCodes(shaderStage) { ++ getCodes(shaderStage: 'vertex' | 'fragment' | 'compute') { + const codes = this.codes[shaderStage]; + + let code = ''; +@@ -853,10 +1002,10 @@ class NodeBuilder { + } + + getHash() { +- return this.vertexShader + this.fragmentShader + this.computeShader; ++ return this.vertexShader! + this.fragmentShader + this.computeShader; + } + +- setShaderStage(shaderStage) { ++ setShaderStage(shaderStage: NodeShaderStage | null) { + this.shaderStage = shaderStage; + } + +@@ -864,7 +1013,7 @@ class NodeBuilder { + return this.shaderStage; + } + +- setBuildStage(buildStage) { ++ setBuildStage(buildStage: string | null) { + this.buildStage = buildStage; + } + +@@ -922,7 +1071,7 @@ class NodeBuilder { + return this; + } + +- getNodeUniform(uniformNode, type) { ++ getNodeUniform(uniformNode: NodeUniform, type: string | null) { + if (type === 'float') return new FloatNodeUniform(uniformNode); + if (type === 'vec2') return new Vector2NodeUniform(uniformNode); + if (type === 'vec3') return new Vector3NodeUniform(uniformNode); +@@ -940,7 +1089,7 @@ class NodeBuilder { return createNodeMaterialFromType(type); } @@ -1076,10 +1822,10 @@ index ebdc13ff..664d5325 100644 toType = this.getVectorType(toType); diff --git a/examples-jsm/examples/nodes/core/NodeCache.ts b/examples-jsm/examples/nodes/core/NodeCache.ts -index 96a7e0c7..a8dfa1ff 100644 +index 96a7e0c7..dd0b8779 100644 --- a/examples-jsm/examples/nodes/core/NodeCache.ts +++ b/examples-jsm/examples/nodes/core/NodeCache.ts -@@ -1,16 +1,52 @@ +@@ -1,16 +1,54 @@ +import Node from './Node.js'; +import NodeAttribute from './NodeAttribute.js'; +import NodeUniform from './NodeUniform.js'; @@ -1106,6 +1852,8 @@ index 96a7e0c7..a8dfa1ff 100644 + code?: NodeCode | undefined; + usageCount?: number | undefined; + snippet?: string | undefined; ++ propertyName?: string | undefined; ++ propertySizeName?: string | undefined; +} + +interface NodeData { @@ -1134,6 +1882,21 @@ index 96a7e0c7..a8dfa1ff 100644 this.nodesData.set(node, data); } } +diff --git a/examples-jsm/examples/nodes/core/NodeCode.ts b/examples-jsm/examples/nodes/core/NodeCode.ts +index 2ee50903..0c0d8c87 100644 +--- a/examples-jsm/examples/nodes/core/NodeCode.ts ++++ b/examples-jsm/examples/nodes/core/NodeCode.ts +@@ -1,5 +1,9 @@ + class NodeCode { +- constructor(name, type, code = '') { ++ name: string; ++ type: string | null; ++ code: string; ++ ++ constructor(name: string, type: string | null, code = '') { + this.name = name; + this.type = type; + this.code = code; diff --git a/examples-jsm/examples/nodes/core/NodeFrame.ts b/examples-jsm/examples/nodes/core/NodeFrame.ts index b8e8d37b..d5c60178 100644 --- a/examples-jsm/examples/nodes/core/NodeFrame.ts @@ -1234,6 +1997,22 @@ index 53da9bf5..36bdcabe 100644 const keywordNodes = this.parse(code); for (const keywordNode of keywordNodes) { +diff --git a/examples-jsm/examples/nodes/core/NodeParser.ts b/examples-jsm/examples/nodes/core/NodeParser.ts +index 9849452f..76c5b9be 100644 +--- a/examples-jsm/examples/nodes/core/NodeParser.ts ++++ b/examples-jsm/examples/nodes/core/NodeParser.ts +@@ -1,7 +1,7 @@ +-class NodeParser { +- parseFunction(/*source*/) { +- console.warn('Abstract function.'); +- } ++import NodeFunction from './NodeFunction.js'; ++ ++abstract class NodeParser { ++ abstract parseFunction(source: string): NodeFunction; + } + + export default NodeParser; diff --git a/examples-jsm/examples/nodes/core/NodeUniform.ts b/examples-jsm/examples/nodes/core/NodeUniform.ts index 2918e219..b6ccba3a 100644 --- a/examples-jsm/examples/nodes/core/NodeUniform.ts @@ -1375,10 +2154,93 @@ index a1482362..0a62b23d 100644 + + readonly isNodeVarying: true; + -+ constructor(name: string, type: string | null) { - super(name, type); ++ constructor(name: string, type: string | null) { + super(name, type); + + this.needsInterpolation = false; +diff --git a/examples-jsm/examples/nodes/core/StackNode.ts b/examples-jsm/examples/nodes/core/StackNode.ts +index d9322607..4ec41a07 100644 +--- a/examples-jsm/examples/nodes/core/StackNode.ts ++++ b/examples-jsm/examples/nodes/core/StackNode.ts +@@ -1,8 +1,16 @@ + import Node, { addNodeClass } from './Node.js'; + import { cond } from '../math/CondNode.js'; +-import { ShaderNode, nodeProxy, getCurrentStack, setCurrentStack } from '../shadernode/ShaderNode.js'; ++import { ShaderNode, nodeProxy, getCurrentStack, setCurrentStack, ShaderNodeObject } from '../shadernode/ShaderNode.js'; ++import NodeBuilder from './NodeBuilder.js'; + + class StackNode extends Node { ++ nodes: Node[]; ++ outputNode: Node | null; ++ ++ parent: ShaderNodeObject | null; ++ ++ readonly isStackNode: true; ++ + constructor(parent = null) { + super(); + +@@ -16,24 +24,24 @@ class StackNode extends Node { + this.isStackNode = true; + } + +- getNodeType(builder) { ++ getNodeType(builder: NodeBuilder) { + return this.outputNode ? this.outputNode.getNodeType(builder) : 'void'; + } + +- add(node) { ++ add(node: Node) { + this.nodes.push(node); + + return this; + } + +- if(boolNode, method) { ++ if(boolNode: Node, method: () => void) { + const methodNode = new ShaderNode(method); + this._currentCond = cond(boolNode, methodNode); + + return this.add(this._currentCond); + } + +- elseif(boolNode, method) { ++ elseif(boolNode: Node, method: () => void) { + const methodNode = new ShaderNode(method); + const ifNode = cond(boolNode, methodNode); + +@@ -43,13 +51,13 @@ class StackNode extends Node { + return this; + } + +- else(method) { ++ else(method: () => void) { + this._currentCond.elseNode = new ShaderNode(method); + + return this; + } + +- build(builder, ...params) { ++ build(builder: NodeBuilder, ...params) { + const previousStack = getCurrentStack(); + + setCurrentStack(this); +diff --git a/examples-jsm/examples/nodes/core/StructTypeNode.ts b/examples-jsm/examples/nodes/core/StructTypeNode.ts +index 69718799..e7574a1c 100644 +--- a/examples-jsm/examples/nodes/core/StructTypeNode.ts ++++ b/examples-jsm/examples/nodes/core/StructTypeNode.ts +@@ -1,7 +1,10 @@ + import Node, { addNodeClass } from './Node.js'; + + class StructTypeNode extends Node { +- constructor(types) { ++ types: string[]; ++ readonly isStructTypeNode: true; ++ ++ constructor(types: string[]) { + super(); - this.needsInterpolation = false; + this.types = types; diff --git a/examples-jsm/examples/nodes/core/UniformGroupNode.ts b/examples-jsm/examples/nodes/core/UniformGroupNode.ts index f8bb2b37..cee70486 100644 --- a/examples-jsm/examples/nodes/core/UniformGroupNode.ts @@ -1407,7 +2269,7 @@ index f8bb2b37..cee70486 100644 } } diff --git a/examples-jsm/examples/nodes/core/UniformNode.ts b/examples-jsm/examples/nodes/core/UniformNode.ts -index 90e86648..0987ac55 100644 +index 90e86648..78a60c3b 100644 --- a/examples-jsm/examples/nodes/core/UniformNode.ts +++ b/examples-jsm/examples/nodes/core/UniformNode.ts @@ -1,10 +1,17 @@ @@ -1489,7 +2351,7 @@ index 90e86648..0987ac55 100644 // @TODO: get ConstNode from .traverse() in the future - const value = arg1 && arg1.isNode === true ? (arg1.node && arg1.node.value) || arg1.value : arg1; -+ const value = ++ const value: TValue = + arg1 && (arg1 as Node).isNode === true + ? (arg1.node && arg1.node.value) || (arg1 as InputNode).value + : arg1; @@ -1554,6 +2416,64 @@ index 9417df5a..43761555 100644 let viewZ; const getViewZ = builder.context.getViewZ; +diff --git a/examples-jsm/examples/nodes/lighting/LightingContextNode.ts b/examples-jsm/examples/nodes/lighting/LightingContextNode.ts +index 02a8b51f..1d11c859 100644 +--- a/examples-jsm/examples/nodes/lighting/LightingContextNode.ts ++++ b/examples-jsm/examples/nodes/lighting/LightingContextNode.ts +@@ -1,9 +1,31 @@ + import ContextNode from '../core/ContextNode.js'; +-import { addNodeClass } from '../core/Node.js'; +-import { addNodeElement, nodeProxy, float, vec3 } from '../shadernode/ShaderNode.js'; ++import Node, { addNodeClass } from '../core/Node.js'; ++import { addNodeElement, nodeProxy, float, vec3, ShaderNodeObject } from '../shadernode/ShaderNode.js'; ++import NodeBuilder from '../core/NodeBuilder.js'; + +-class LightingContextNode extends ContextNode { +- constructor(node, lightingModel = null, backdropNode = null, backdropAlphaNode = null) { ++interface LightingContext { ++ radiance: ShaderNodeObject; ++ irradiance: ShaderNodeObject; ++ iblIrradiance: ShaderNodeObject; ++ ambientOcclusion: ShaderNodeObject; ++ reflectedLight: { ++ directDiffuse: ShaderNodeObject; ++ directSpecular: ShaderNodeObject; ++ indirectDiffuse: ShaderNodeObject; ++ indirectSpecular: ShaderNodeObject; ++ }; ++ backdrop: Node | null; ++ backdropAlpha: Node | null; ++} ++ ++class LightingContextNode extends ContextNode { ++ // lightingModel; ++ backdropNode: Node | null; ++ backdropAlphaNode: Node | null; ++ ++ _context: LightingContext | null; ++ ++ constructor(node: Node, lightingModel = null, backdropNode = null, backdropAlphaNode = null) { + super(node); + + this.lightingModel = lightingModel; +@@ -28,7 +50,7 @@ class LightingContextNode extends ContextNode { + indirectSpecular, + }; + +- const context = { ++ const context: LightingContext = { + radiance: vec3().temp('radiance'), + irradiance: vec3().temp('irradiance'), + iblIrradiance: vec3().temp('iblIrradiance'), +@@ -41,7 +63,7 @@ class LightingContextNode extends ContextNode { + return context; + } + +- setup(builder) { ++ setup(builder: NodeBuilder) { + this.context = this._context || (this._context = this.getContext()); + this.context.lightingModel = this.lightingModel || builder.context.lightingModel; + diff --git a/examples-jsm/examples/nodes/lighting/LightsNode.ts b/examples-jsm/examples/nodes/lighting/LightsNode.ts index b3695ea8..603a4520 100644 --- a/examples-jsm/examples/nodes/lighting/LightsNode.ts @@ -1575,11 +2495,48 @@ index b3695ea8..603a4520 100644 const lightNodes = []; lights = sortLights(lights); +diff --git a/examples-jsm/examples/nodes/materials/NodeMaterial.ts b/examples-jsm/examples/nodes/materials/NodeMaterial.ts +index 78937411..ecb01aef 100644 +--- a/examples-jsm/examples/nodes/materials/NodeMaterial.ts ++++ b/examples-jsm/examples/nodes/materials/NodeMaterial.ts +@@ -31,7 +31,7 @@ import { cameraLogDepth } from '../accessors/CameraNode.js'; + import { clipping, clippingAlpha } from '../accessors/ClippingNode.js'; + import { faceDirection } from '../display/FrontFacingNode.js'; + +-const NodeMaterials = new Map(); ++const NodeMaterials = new Map(); + + class NodeMaterial extends Material { + constructor() { +@@ -490,7 +490,7 @@ class NodeMaterial extends Material { + + export default NodeMaterial; + +-export function addNodeMaterial(type, nodeMaterial) { ++export function addNodeMaterial(type: string, nodeMaterial: typeof NodeMaterial) { + if (typeof nodeMaterial !== 'function' || !type) throw new Error(`Node material ${type} is not a class`); + if (NodeMaterials.has(type)) { + console.warn(`Redefinition of node material ${type}`); +@@ -501,7 +501,7 @@ export function addNodeMaterial(type, nodeMaterial) { + nodeMaterial.type = type; + } + +-export function createNodeMaterialFromType(type) { ++export function createNodeMaterialFromType(type: string) { + const Material = NodeMaterials.get(type); + + if (Material !== undefined) { diff --git a/examples-jsm/examples/nodes/shadernode/ShaderNode.ts b/examples-jsm/examples/nodes/shadernode/ShaderNode.ts -index d0dca242..dd91e4fc 100644 +index d0dca242..65ab4ec5 100644 --- a/examples-jsm/examples/nodes/shadernode/ShaderNode.ts +++ b/examples-jsm/examples/nodes/shadernode/ShaderNode.ts -@@ -11,6 +11,43 @@ import { getValueFromType, getValueType } from '../core/NodeUtils.js'; +@@ -6,11 +6,49 @@ import SplitNode from '../utils/SplitNode.js'; + import SetNode from '../utils/SetNode.js'; + import ConstNode from '../core/ConstNode.js'; + import { getValueFromType, getValueType } from '../core/NodeUtils.js'; ++import NodeBuilder from '../core/NodeBuilder.js'; + + // let currentStack = null; @@ -1623,7 +2580,7 @@ index d0dca242..dd91e4fc 100644 const NodeElements = new Map(); // @TODO: Currently only a few nodes are added, probably also add others export function addNodeElement(name, nodeElement) { -@@ -24,6 +61,141 @@ export function addNodeElement(name, nodeElement) { +@@ -24,6 +62,141 @@ export function addNodeElement(name, nodeElement) { NodeElements.set(name, nodeElement); } @@ -1765,8 +2722,76 @@ index d0dca242..dd91e4fc 100644 const parseSwizzle = props => props.replace(/r|s/g, 'x').replace(/g|t/g, 'y').replace(/b|p/g, 'z').replace(/a|q/g, 'w'); const shaderNodeHandler = { -@@ -385,7 +557,23 @@ export function ShaderNode(jsFunc) { - export const nodeObject = (val, altType = null) => /* new */ ShaderNodeObject(val, altType); +@@ -113,7 +286,7 @@ const shaderNodeHandler = { + const nodeObjectsCacheMap = new WeakMap(); + const nodeBuilderFunctionsCacheMap = new WeakMap(); + +-const ShaderNodeObject = function (obj, altType = null) { ++const ShaderNodeObject = function (obj: T, altType: string | null = null) { + const type = getValueType(obj); + + if (type === 'node') { +@@ -182,7 +355,9 @@ const ShaderNodeImmutable = function (NodeClass, ...params) { + }; + + class ShaderCallNodeInternal extends Node { +- constructor(shaderNode, inputNodes) { ++ shaderNode: ShaderNodeInternal; ++ ++ constructor(shaderNode: ShaderNodeInternal, inputNodes) { + super(); + + this.shaderNode = shaderNode; +@@ -199,7 +374,7 @@ class ShaderCallNodeInternal extends Node { + return properties.outputNode.getNodeType(builder); + } + +- call(builder) { ++ call(builder: NodeBuilder) { + const { shaderNode, inputNodes } = this; + + if (shaderNode.layout) { +@@ -260,7 +435,15 @@ class ShaderCallNodeInternal extends Node { + } + } + ++interface Layout { ++ name: string; ++ type: string; ++ inputs: { name: string; type: string }[]; ++} ++ + class ShaderNodeInternal extends Node { ++ layout: Layout | null; ++ + constructor(jsFunc) { + super(); + +@@ -272,7 +455,7 @@ class ShaderNodeInternal extends Node { + return /^\((\s+)?\[/.test(this.jsFunc.toString()); + } + +- setLayout(layout) { ++ setLayout(layout: Layout | null) { + this.layout = layout; + + return this; +@@ -289,6 +472,8 @@ class ShaderNodeInternal extends Node { + } + } + ++export type { ShaderNodeInternal }; ++ + const bools = [false, true]; + const uints = [0, 1, 2, 3]; + const ints = [-1, -2]; +@@ -382,10 +567,27 @@ export function ShaderNode(jsFunc) { + return new Proxy(new ShaderNodeInternal(jsFunc), shaderNodeHandler); + } + +-export const nodeObject = (val, altType = null) => /* new */ ShaderNodeObject(val, altType); ++export const nodeObject = (val: T, altType: string | null = null): NodeObject => ++ /* new */ ShaderNodeObject(val, altType); export const nodeObjects = (val, altType = null) => new ShaderNodeObjects(val, altType); export const nodeArray = (val, altType = null) => new ShaderNodeArray(val, altType); -export const nodeProxy = (...params) => new ShaderNodeProxy(...params); @@ -2568,6 +3593,38 @@ index 0d0c35a2..f5a186e1 100644 // size of a chunk in bytes (STD140 layout) +diff --git a/examples-jsm/examples/renderers/common/CubeRenderTarget.ts b/examples-jsm/examples/renderers/common/CubeRenderTarget.ts +index 74d04912..9b6b716a 100644 +--- a/examples-jsm/examples/renderers/common/CubeRenderTarget.ts ++++ b/examples-jsm/examples/renderers/common/CubeRenderTarget.ts +@@ -8,6 +8,9 @@ import { + NoBlending, + LinearFilter, + LinearMipmapLinearFilter, ++ RenderTargetOptions, ++ WebGLRenderer, ++ Texture, + } from 'three'; + import { equirectUV } from '../../nodes/utils/EquirectUVNode.js'; + import { texture as TSL_Texture } from '../../nodes/accessors/TextureNode.js'; +@@ -17,13 +20,15 @@ import { createNodeMaterialFromType } from '../../nodes/materials/NodeMaterial.j + // @TODO: Consider rename WebGLCubeRenderTarget to just CubeRenderTarget + + class CubeRenderTarget extends WebGLCubeRenderTarget { +- constructor(size = 1, options = {}) { ++ readonly isCubeRenderTarget: true; ++ ++ constructor(size = 1, options: RenderTargetOptions = {}) { + super(size, options); + + this.isCubeRenderTarget = true; + } + +- fromEquirectangularTexture(renderer, texture) { ++ fromEquirectangularTexture(renderer: WebGLRenderer, texture: Texture) { + const currentMinFilter = texture.minFilter; + const currentGenerateMipmaps = texture.generateMipmaps; + diff --git a/examples-jsm/examples/renderers/common/DataMap.ts b/examples-jsm/examples/renderers/common/DataMap.ts index 006bc295..eb39fca8 100644 --- a/examples-jsm/examples/renderers/common/DataMap.ts @@ -5214,10 +6271,10 @@ index beb35347..c264d777 100644 if (a[offset + i] !== b[i]) return false; } diff --git a/examples-jsm/examples/renderers/common/nodes/NodeBuilderState.ts b/examples-jsm/examples/renderers/common/nodes/NodeBuilderState.ts -index 5553bd2d..4c4a4cde 100644 +index 5553bd2d..3d871cc6 100644 --- a/examples-jsm/examples/renderers/common/nodes/NodeBuilderState.ts +++ b/examples-jsm/examples/renderers/common/nodes/NodeBuilderState.ts -@@ -1,12 +1,29 @@ +@@ -1,13 +1,30 @@ +import Node from '../../../nodes/core/Node.js'; +import NodeAttribute from '../../../nodes/core/NodeAttribute.js'; +import Binding from '../Binding.js'; @@ -5226,7 +6283,7 @@ index 5553bd2d..4c4a4cde 100644 + vertexShader: string | null; + fragmentShader: string | null; + computeShader: string | null; -+ // TODO transforms ++ transforms: never[]; + + nodeAttributes: NodeAttribute[]; + bindings: Binding[]; @@ -5244,6 +6301,7 @@ index 5553bd2d..4c4a4cde 100644 - bindings, - updateNodes, - updateBeforeNodes, +- transforms = [], + vertexShader: string | null, + fragmentShader: string | null, + computeShader: string | null, @@ -5251,9 +6309,10 @@ index 5553bd2d..4c4a4cde 100644 + bindings: Binding[], + updateNodes: Node[], + updateBeforeNodes: Node[], - transforms = [], ++ transforms: never[] = [], ) { this.vertexShader = vertexShader; + this.fragmentShader = fragmentShader; diff --git a/examples-jsm/examples/renderers/common/nodes/NodeUniform.ts b/examples-jsm/examples/renderers/common/nodes/NodeUniform.ts index f85a638a..748c530d 100644 --- a/examples-jsm/examples/renderers/common/nodes/NodeUniform.ts @@ -5383,7 +6442,7 @@ index 0bbc1add..570a79ac 100644 for (const uniform of this.uniforms) { const node = uniform.nodeUniform.node; diff --git a/examples-jsm/examples/renderers/common/nodes/Nodes.ts b/examples-jsm/examples/renderers/common/nodes/Nodes.ts -index 86df5654..b2b73dbb 100644 +index 86df5654..ec898ce4 100644 --- a/examples-jsm/examples/renderers/common/nodes/Nodes.ts +++ b/examples-jsm/examples/renderers/common/nodes/Nodes.ts @@ -2,10 +2,20 @@ import DataMap from '../DataMap.js'; @@ -5407,7 +6466,7 @@ index 86df5654..b2b73dbb 100644 } from 'three'; import { NodeFrame, -@@ -22,21 +32,65 @@ import { +@@ -22,21 +32,66 @@ import { normalWorld, pmremTexture, viewportTopLeft, @@ -5422,6 +6481,7 @@ index 86df5654..b2b73dbb 100644 +import ComputeNode from '../../../nodes/gpgpu/ComputeNode.js'; +import Node from '../../../nodes/core/Node.js'; +import UniformGroupNode from '../../../nodes/core/UniformGroupNode.js'; ++import GLSLNodeBuilder, { Transform } from '../../webgl/nodes/GLSLNodeBuilder.js'; + +interface NodeUniformsGroupData { + renderId?: number | undefined; @@ -5477,7 +6537,7 @@ index 86df5654..b2b73dbb 100644 const groupNode = nodeUniformsGroup.groupNode; const name = groupNode.name; -@@ -76,7 +130,7 @@ class Nodes extends DataMap { +@@ -76,7 +131,7 @@ class Nodes extends DataMap { // other groups are updated just when groupNode.needsUpdate is true @@ -5486,7 +6546,7 @@ index 86df5654..b2b73dbb 100644 let groupData = this.groupsData.get(groupChain); if (groupData === undefined) this.groupsData.set(groupChain, (groupData = {})); -@@ -90,11 +144,11 @@ class Nodes extends DataMap { +@@ -90,11 +145,11 @@ class Nodes extends DataMap { return false; } @@ -5500,7 +6560,7 @@ index 86df5654..b2b73dbb 100644 const renderObjectData = this.get(renderObject); let nodeBuilderState = renderObjectData.nodeBuilderState; -@@ -133,20 +187,20 @@ class Nodes extends DataMap { +@@ -133,20 +188,20 @@ class Nodes extends DataMap { return nodeBuilderState; } @@ -5526,7 +6586,7 @@ index 86df5654..b2b73dbb 100644 const computeData = this.get(computeNode); let nodeBuilderState = computeData.nodeBuilderState; -@@ -163,7 +217,7 @@ class Nodes extends DataMap { +@@ -163,7 +218,7 @@ class Nodes extends DataMap { return nodeBuilderState; } @@ -5535,7 +6595,12 @@ index 86df5654..b2b73dbb 100644 return new NodeBuilderState( nodeBuilder.vertexShader, nodeBuilder.fragmentShader, -@@ -176,20 +230,28 @@ class Nodes extends DataMap { +@@ -172,24 +227,32 @@ class Nodes extends DataMap { + nodeBuilder.getBindings(), + nodeBuilder.updateNodes, + nodeBuilder.updateBeforeNodes, +- nodeBuilder.transforms, ++ (nodeBuilder as GLSLNodeBuilder | { transforms?: Transform[] }).transforms, ); } @@ -5572,7 +6637,7 @@ index 86df5654..b2b73dbb 100644 const callId = this.renderer.info.calls; let cacheKeyData = this.callHashCache.get(chain); -@@ -215,7 +277,7 @@ class Nodes extends DataMap { +@@ -215,7 +278,7 @@ class Nodes extends DataMap { return cacheKeyData.cacheKey; } @@ -5581,7 +6646,7 @@ index 86df5654..b2b73dbb 100644 this.updateEnvironment(scene); this.updateFog(scene); this.updateBackground(scene); -@@ -225,7 +287,7 @@ class Nodes extends DataMap { +@@ -225,7 +288,7 @@ class Nodes extends DataMap { return this.renderer.getRenderTarget() ? false : true; } @@ -5590,7 +6655,7 @@ index 86df5654..b2b73dbb 100644 const sceneData = this.get(scene); const background = scene.background; -@@ -234,15 +296,15 @@ class Nodes extends DataMap { +@@ -234,15 +297,15 @@ class Nodes extends DataMap { let backgroundNode = null; if ( @@ -5613,7 +6678,7 @@ index 86df5654..b2b73dbb 100644 } sceneData.backgroundNode = backgroundNode; -@@ -254,7 +316,7 @@ class Nodes extends DataMap { +@@ -254,7 +317,7 @@ class Nodes extends DataMap { } } @@ -5622,7 +6687,7 @@ index 86df5654..b2b73dbb 100644 const sceneData = this.get(scene); const fog = scene.fog; -@@ -262,9 +324,9 @@ class Nodes extends DataMap { +@@ -262,9 +325,9 @@ class Nodes extends DataMap { if (sceneData.fog !== fog) { let fogNode = null; @@ -5634,7 +6699,7 @@ index 86df5654..b2b73dbb 100644 fogNode = rangeFog( reference('color', 'color', fog), reference('near', 'float', fog), -@@ -283,7 +345,7 @@ class Nodes extends DataMap { +@@ -283,7 +346,7 @@ class Nodes extends DataMap { } } @@ -5643,7 +6708,7 @@ index 86df5654..b2b73dbb 100644 const sceneData = this.get(scene); const environment = scene.environment; -@@ -291,7 +353,7 @@ class Nodes extends DataMap { +@@ -291,7 +354,7 @@ class Nodes extends DataMap { if (sceneData.environment !== environment) { let environmentNode = null; @@ -5652,7 +6717,7 @@ index 86df5654..b2b73dbb 100644 environmentNode = cubeTexture(environment); } else if (environment.isTexture === true) { environmentNode = texture(environment); -@@ -308,7 +370,13 @@ class Nodes extends DataMap { +@@ -308,7 +371,13 @@ class Nodes extends DataMap { } } @@ -5667,7 +6732,7 @@ index 86df5654..b2b73dbb 100644 const nodeFrame = this.nodeFrame; nodeFrame.renderer = renderer; nodeFrame.scene = scene; -@@ -319,7 +387,7 @@ class Nodes extends DataMap { +@@ -319,7 +388,7 @@ class Nodes extends DataMap { return nodeFrame; } @@ -5676,7 +6741,7 @@ index 86df5654..b2b73dbb 100644 return this.getNodeFrame( renderObject.renderer, renderObject.scene, -@@ -329,8 +397,8 @@ class Nodes extends DataMap { +@@ -329,8 +398,8 @@ class Nodes extends DataMap { ); } @@ -5687,7 +6752,7 @@ index 86df5654..b2b73dbb 100644 if (this.isToneMappingState) { if (this.renderer.toneMappingNode) { -@@ -347,7 +415,7 @@ class Nodes extends DataMap { +@@ -347,7 +416,7 @@ class Nodes extends DataMap { return output; } @@ -5696,7 +6761,7 @@ index 86df5654..b2b73dbb 100644 const nodeFrame = this.getNodeFrameForRender(renderObject); const nodeBuilder = renderObject.getNodeBuilderState(); -@@ -356,7 +424,7 @@ class Nodes extends DataMap { +@@ -356,7 +425,7 @@ class Nodes extends DataMap { } } @@ -5705,7 +6770,7 @@ index 86df5654..b2b73dbb 100644 const nodeFrame = this.getNodeFrame(); const nodeBuilder = this.getForCompute(computeNode); -@@ -365,7 +433,7 @@ class Nodes extends DataMap { +@@ -365,7 +434,7 @@ class Nodes extends DataMap { } } @@ -5734,15 +6799,373 @@ index b9a999f1..2ed970b6 100644 } diff --git a/examples-jsm/examples/renderers/webgl/nodes/GLSLNodeBuilder.ts b/examples-jsm/examples/renderers/webgl/nodes/GLSLNodeBuilder.ts -index 4910f51f..34e51ee8 100644 +index 4910f51f..23bd0b09 100644 --- a/examples-jsm/examples/renderers/webgl/nodes/GLSLNodeBuilder.ts +++ b/examples-jsm/examples/renderers/webgl/nodes/GLSLNodeBuilder.ts -@@ -595,7 +595,7 @@ void main() { +@@ -1,4 +1,15 @@ +-import { MathNode, GLSLNodeParser, NodeBuilder, UniformNode, vectorComponents } from '../../../nodes/Nodes.js'; ++import { ++ MathNode, ++ GLSLNodeParser, ++ NodeBuilder, ++ UniformNode, ++ vectorComponents, ++ ShaderNodeObject, ++ ShaderNodeInternal, ++ NodeShaderStage, ++ StorageArrayElementNode, ++ StorageBufferNode, ++} from '../../../nodes/Nodes.js'; + + import NodeUniformBuffer from '../../common/nodes/NodeUniformBuffer.js'; + import NodeUniformsGroup from '../../common/nodes/NodeUniformsGroup.js'; +@@ -9,9 +20,25 @@ import { + NodeSampledTexture3D, + } from '../../common/nodes/NodeSampledTexture.js'; + +-import { RedFormat, RGFormat, IntType, DataTexture, RGBFormat, RGBAFormat, FloatType } from 'three'; +- +-const glslMethods = { ++import { ++ RedFormat, ++ RGFormat, ++ IntType, ++ DataTexture, ++ RGBFormat, ++ RGBAFormat, ++ FloatType, ++ Object3D, ++ Scene, ++ Texture, ++ BufferAttribute, ++ InterleavedBufferAttribute, ++} from 'three'; ++import Renderer from '../../common/Renderer.js'; ++import StructTypeNode from '../../../nodes/core/StructTypeNode.js'; ++import BufferAttributeNode from '../../../nodes/accessors/BufferAttributeNode.js'; ++ ++const glslMethods: { [method: string]: string } = { + [MathNode.ATAN2]: 'atan', + textureDimensions: 'textureSize', + equals: 'equal', +@@ -36,25 +63,48 @@ precision mediump sampler2DArray; + precision lowp sampler2DShadow; + `; + ++export interface Transform { ++ varyingName: string | null | undefined; ++ attributeNode: ShaderNodeObject; ++} ++ ++interface StageData { ++ uniforms?: string | undefined; ++ attributes?: string | undefined; ++ varyings?: string | undefined; ++ vars?: string | undefined; ++ structs?: string | undefined; ++ codes?: string | undefined; ++ transforms?: string | undefined; ++ flow?: string | undefined; ++} ++ + class GLSLNodeBuilder extends NodeBuilder { +- constructor(object, renderer, scene = null) { ++ uniformGroups: { ++ vertex?: { [groupName: string]: NodeUniformsGroup | undefined }; ++ fragment?: { [groupName: string]: NodeUniformsGroup | undefined }; ++ compute?: { [groupName: string]: NodeUniformsGroup | undefined }; ++ }; ++ transforms: Transform[]; ++ ++ constructor(object: Object3D, renderer: Renderer, scene: Scene | null = null) { + super(object, renderer, new GLSLNodeParser(), scene); + + this.uniformGroups = {}; + this.transforms = []; + } + +- getMethod(method) { ++ getMethod(method: string) { + return glslMethods[method] || method; + } + +- getPropertyName(node, shaderStage) { ++ getPropertyName(node: unknown, shaderStage?: NodeShaderStage) { + if (node.isOutputStructVar) return ''; + + return super.getPropertyName(node, shaderStage); + } + +- buildFunctionCode(shaderNode) { ++ buildFunctionCode(shaderNode: ShaderNodeInternal) { + const layout = shaderNode.layout; + const flowData = this.flowShaderNode(shaderNode); + +@@ -80,7 +130,7 @@ ${flowData.code} + return code; + } + +- setupPBO(storageBufferNode) { ++ setupPBO(storageBufferNode: StorageBufferNode) { + const attribute = storageBufferNode.value; + + if (attribute.pbo === undefined) { +@@ -124,7 +174,7 @@ ${flowData.code} + } + } + +- generatePBO(storageArrayElementNode) { ++ generatePBO(storageArrayElementNode: StorageArrayElementNode) { + const { node, indexNode } = storageArrayElementNode; + const attribute = node.value; + +@@ -185,7 +235,13 @@ ${flowData.code} + return propertyName; + } + +- generateTextureLoad(texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0') { ++ generateTextureLoad( ++ texture: Texture | null, ++ textureProperty: string | undefined, ++ uvIndexSnippet: string, ++ depthSnippet: string | null, ++ levelSnippet = '0', ++ ) { + if (depthSnippet) { + return `texelFetch( ${textureProperty}, ivec3( ${uvIndexSnippet}, ${depthSnippet} ), ${levelSnippet} )`; + } else { +@@ -193,7 +249,7 @@ ${flowData.code} + } + } + +- generateTexture(texture, textureProperty, uvSnippet, depthSnippet) { ++ generateTexture(texture: Texture, textureProperty: string, uvSnippet: string | null, depthSnippet: string | null) { + if (texture.isDepthTexture) { + return `texture( ${textureProperty}, ${uvSnippet} ).x`; + } else { +@@ -203,20 +259,30 @@ ${flowData.code} + } + } + +- generateTextureLevel(texture, textureProperty, uvSnippet, levelSnippet) { ++ generateTextureLevel( ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ levelSnippet: string | null, ++ ) { + return `textureLod( ${textureProperty}, ${uvSnippet}, ${levelSnippet} )`; + } + +- generateTextureGrad(texture, textureProperty, uvSnippet, gradSnippet) { ++ generateTextureGrad( ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ gradSnippet: [string, string] | null, ++ ) { + return `textureGrad( ${textureProperty}, ${uvSnippet}, ${gradSnippet[0]}, ${gradSnippet[1]} )`; + } + + generateTextureCompare( +- texture, +- textureProperty, +- uvSnippet, +- compareSnippet, +- depthSnippet, ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ compareSnippet: string | null, ++ depthSnippet: string | null, + shaderStage = this.shaderStage, + ) { + if (shaderStage === 'fragment') { +@@ -225,11 +291,12 @@ ${flowData.code} + console.error( + `WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${shaderStage} shader.`, + ); ++ return undefined as unknown as string; + } + } + +- getVars(shaderStage) { +- const snippets = []; ++ getVars(shaderStage: 'vertex' | 'fragment' | 'compute') { ++ const snippets: string[] = []; + + const vars = this.vars[shaderStage]; + +@@ -244,7 +311,7 @@ ${flowData.code} + return snippets.join('\n\t'); + } + +- getUniforms(shaderStage) { ++ getUniforms(shaderStage: 'vertex' | 'fragment' | 'compute') { + const uniforms = this.uniforms[shaderStage]; + + const bindingSnippets = []; +@@ -316,7 +383,7 @@ ${flowData.code} + return output; + } + +- getTypeFromAttribute(attribute) { ++ getTypeFromAttribute(attribute: BufferAttribute | InterleavedBufferAttribute) { + let nodeType = super.getTypeFromAttribute(attribute); + + if (/^[iu]/.test(nodeType) && attribute.gpuType !== IntType) { +@@ -339,7 +406,7 @@ ${flowData.code} + return nodeType; + } + +- getAttributes(shaderStage) { ++ getAttributes(shaderStage: NodeShaderStage) { + let snippet = ''; + + if (shaderStage === 'vertex' || shaderStage === 'compute') { +@@ -355,8 +422,8 @@ ${flowData.code} + return snippet; + } + +- getStructMembers(struct) { +- const snippets = []; ++ getStructMembers(struct: StructTypeNode) { ++ const snippets: string[] = []; + const members = struct.getMemberTypes(); + + for (let i = 0; i < members.length; i++) { +@@ -367,7 +434,7 @@ ${flowData.code} + return snippets.join('\n'); + } + +- getStructs(shaderStage) { ++ getStructs(shaderStage: NodeShaderStage) { + const snippets = []; + const structs = this.structs[shaderStage]; + +@@ -388,7 +455,7 @@ ${flowData.code} + return snippets.join('\n\n'); + } + +- getVaryings(shaderStage) { ++ getVaryings(shaderStage: NodeShaderStage) { + let snippet = ''; + + const varyings = this.varyings; +@@ -435,7 +502,7 @@ ${flowData.code} + return 'gl_FragDepth'; + } + +- isAvailable(name) { ++ isAvailable(name: string) { + return supports[name] === true; + } + +@@ -443,11 +510,11 @@ ${flowData.code} + return true; + } + +- registerTransform(varyingName, attributeNode) { ++ registerTransform(varyingName: string | null | undefined, attributeNode: ShaderNodeObject) { + this.transforms.push({ varyingName, attributeNode }); + } + +- getTransforms(/* shaderStage */) { ++ getTransforms(shaderStage: NodeShaderStage) { + const transforms = this.transforms; + + let snippet = ''; +@@ -463,14 +530,14 @@ ${flowData.code} + return snippet; + } + +- _getGLSLUniformStruct(name, vars) { ++ _getGLSLUniformStruct(name: string, vars: string) { + return ` + layout( std140 ) uniform ${name} { + ${vars} + };`; + } + +- _getGLSLVertexCode(shaderData) { ++ _getGLSLVertexCode(shaderData: StageData) { + return `#version 300 es + + ${this.getSignature()} +@@ -507,7 +574,7 @@ void main() { + `; + } + +- _getGLSLFragmentCode(shaderData) { ++ _getGLSLFragmentCode(shaderData: StageData) { + return `#version 300 es + + ${this.getSignature()} +@@ -539,17 +606,18 @@ void main() { + } + + buildCode() { +- const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; ++ const shadersData: { fragment?: StageData; vertex?: StageData; compute?: StageData } = ++ this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; + + for (const shaderStage in shadersData) { + let flow = '// code\n\n'; +- flow += this.flowCode[shaderStage]; ++ flow += this.flowCode[shaderStage as NodeShaderStage]; + +- const flowNodes = this.flowNodes[shaderStage]; ++ const flowNodes = this.flowNodes[shaderStage as NodeShaderStage]; + const mainNode = flowNodes[flowNodes.length - 1]; + + for (const node of flowNodes) { +- const flowSlotData = this.getFlowData(node /*, shaderStage*/); ++ const flowSlotData = this.getFlowData(node /*, shaderStage*/)!; + const slotName = node.name; + + if (slotName) { +@@ -575,27 +643,32 @@ void main() { + } + } + +- const stageData = shadersData[shaderStage]; ++ const stageData = shadersData[shaderStage as NodeShaderStage]!; + +- stageData.uniforms = this.getUniforms(shaderStage); +- stageData.attributes = this.getAttributes(shaderStage); +- stageData.varyings = this.getVaryings(shaderStage); +- stageData.vars = this.getVars(shaderStage); +- stageData.structs = this.getStructs(shaderStage); +- stageData.codes = this.getCodes(shaderStage); +- stageData.transforms = this.getTransforms(shaderStage); ++ stageData.uniforms = this.getUniforms(shaderStage as NodeShaderStage); ++ stageData.attributes = this.getAttributes(shaderStage as NodeShaderStage); ++ stageData.varyings = this.getVaryings(shaderStage as NodeShaderStage); ++ stageData.vars = this.getVars(shaderStage as NodeShaderStage); ++ stageData.structs = this.getStructs(shaderStage as NodeShaderStage); ++ stageData.codes = this.getCodes(shaderStage as NodeShaderStage); ++ stageData.transforms = this.getTransforms(shaderStage as NodeShaderStage); + stageData.flow = flow; + } + + if (this.material !== null) { +- this.vertexShader = this._getGLSLVertexCode(shadersData.vertex); +- this.fragmentShader = this._getGLSLFragmentCode(shadersData.fragment); ++ this.vertexShader = this._getGLSLVertexCode(shadersData.vertex!); ++ this.fragmentShader = this._getGLSLFragmentCode(shadersData.fragment!); + } else { +- this.computeShader = this._getGLSLVertexCode(shadersData.compute); ++ this.computeShader = this._getGLSLVertexCode(shadersData.compute!); } } - getUniformFromNode(node, type, shaderStage, name = null) { -+ getUniformFromNode(node, type, shaderStage: 'vertex' | 'fragment' | 'compute', name = null) { ++ getUniformFromNode( ++ node: UniformNode, ++ type: string | null, ++ shaderStage: 'vertex' | 'fragment' | 'compute', ++ name: string | null = null, ++ ) { const uniformNode = super.getUniformFromNode(node, type, shaderStage, name); const nodeData = this.getDataFromNode(node, shaderStage, this.globalCache); @@ -5768,3 +7191,212 @@ index 97a42577..4491def1 100644 return this.textureUtils.copyTextureToBuffer(texture, x, y, width, height); } +diff --git a/examples-jsm/examples/renderers/webgpu/nodes/WGSLNodeBuilder.ts b/examples-jsm/examples/renderers/webgpu/nodes/WGSLNodeBuilder.ts +index ed6e38f9..41493460 100644 +--- a/examples-jsm/examples/renderers/webgpu/nodes/WGSLNodeBuilder.ts ++++ b/examples-jsm/examples/renderers/webgpu/nodes/WGSLNodeBuilder.ts +@@ -1,4 +1,4 @@ +-import { NoColorSpace, FloatType } from 'three'; ++import { NoColorSpace, FloatType, Texture } from 'three'; + + import NodeUniformsGroup from '../../common/nodes/NodeUniformsGroup.js'; + +@@ -12,11 +12,13 @@ import { + import NodeUniformBuffer from '../../common/nodes/NodeUniformBuffer.js'; + import NodeStorageBuffer from '../../common/nodes/NodeStorageBuffer.js'; + +-import { NodeBuilder, CodeNode } from '../../../nodes/Nodes.js'; ++import { NodeBuilder, CodeNode, NodeShaderStage, ShaderNodeInternal } from '../../../nodes/Nodes.js'; + + import { getFormat } from '../utils/WebGPUTextureUtils.js'; + + import WGSLNodeParser from './WGSLNodeParser.js'; ++import UniformNode from '../../../nodes/core/UniformNode.js'; ++import Node from '../../../nodes/core/Node.js'; + + // GPUShaderStage is not defined in browsers not supporting WebGPU + const GPUShaderStage = self.GPUShaderStage; +@@ -151,7 +153,13 @@ class WGSLNodeBuilder extends NodeBuilder { + return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace; + } + +- _generateTextureSample(texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage) { ++ _generateTextureSample( ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ depthSnippet: string | null, ++ shaderStage = this.shaderStage, ++ ) { + if (shaderStage === 'fragment') { + if (depthSnippet) { + return `textureSample( ${textureProperty}, ${textureProperty}_sampler, ${uvSnippet}, ${depthSnippet} )`; +@@ -186,7 +194,12 @@ class WGSLNodeBuilder extends NodeBuilder { + } + } + +- generateTextureLod(texture, textureProperty, uvSnippet, levelSnippet = '0') { ++ generateTextureLod( ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ levelSnippet: string | null = '0', ++ ) { + this._include('repeatWrapping'); + + const dimension = `textureDimensions( ${textureProperty}, 0 )`; +@@ -194,7 +207,13 @@ class WGSLNodeBuilder extends NodeBuilder { + return `textureLoad( ${textureProperty}, threejs_repeatWrapping( ${uvSnippet}, ${dimension} ), i32( ${levelSnippet} ) )`; + } + +- generateTextureLoad(texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0u') { ++ generateTextureLoad( ++ texture: Texture, ++ textureProperty: string, ++ uvIndexSnippet: string | null, ++ depthSnippet: string | null, ++ levelSnippet = '0u', ++ ) { + if (depthSnippet) { + return `textureLoad( ${textureProperty}, ${uvIndexSnippet}, ${depthSnippet}, ${levelSnippet} )`; + } else { +@@ -228,11 +247,11 @@ class WGSLNodeBuilder extends NodeBuilder { + } + + generateTextureGrad( +- texture, +- textureProperty, +- uvSnippet, +- gradSnippet, +- depthSnippet, ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ gradSnippet: [string, string] | null, ++ depthSnippet: string | null, + shaderStage = this.shaderStage, + ) { + if (shaderStage === 'fragment') { +@@ -244,11 +263,11 @@ class WGSLNodeBuilder extends NodeBuilder { + } + + generateTextureCompare( +- texture, +- textureProperty, +- uvSnippet, +- compareSnippet, +- depthSnippet, ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ compareSnippet: string | null, ++ depthSnippet: string | null, + shaderStage = this.shaderStage, + ) { + if (shaderStage === 'fragment') { +@@ -261,11 +280,11 @@ class WGSLNodeBuilder extends NodeBuilder { + } + + generateTextureLevel( +- texture, +- textureProperty, +- uvSnippet, +- levelSnippet, +- depthSnippet, ++ texture: Texture, ++ textureProperty: string, ++ uvSnippet: string | null, ++ levelSnippet: string | null, ++ depthSnippet: string | null, + shaderStage = this.shaderStage, + ) { + let snippet = null; +@@ -286,7 +305,7 @@ class WGSLNodeBuilder extends NodeBuilder { + return snippet; + } + +- getPropertyName(node, shaderStage = this.shaderStage) { ++ getPropertyName(node: unknown, shaderStage = this.shaderStage) { + if (node.isNodeVarying === true && node.needsInterpolation === true) { + if (shaderStage === 'vertex') { + return `varyings.${node.name}`; +@@ -323,7 +342,12 @@ class WGSLNodeBuilder extends NodeBuilder { + return null; + } + +- getUniformFromNode(node, type, shaderStage, name = null) { ++ getUniformFromNode( ++ node: UniformNode, ++ type: string | null, ++ shaderStage: NodeShaderStage, ++ name: string | null = null, ++ ) { + const uniformNode = super.getUniformFromNode(node, type, shaderStage, name); + const nodeData = this.getDataFromNode(node, shaderStage, this.globalCache); + +@@ -435,7 +459,7 @@ class WGSLNodeBuilder extends NodeBuilder { + return 'vertexIndex'; + } + +- buildFunctionCode(shaderNode) { ++ buildFunctionCode(shaderNode: ShaderNodeInternal) { + const layout = shaderNode.layout; + const flowData = this.flowShaderNode(shaderNode); + +@@ -496,8 +520,8 @@ ${flowData.code} + return snippets.join(',\n\t'); + } + +- getAttributes(shaderStage) { +- const snippets = []; ++ getAttributes(shaderStage: NodeShaderStage) { ++ const snippets: string[] = []; + + if (shaderStage === 'compute') { + this.getBuiltin('global_invocation_id', 'id', 'vec3', 'attribute'); +@@ -569,8 +593,8 @@ ${flowData.code} + return `\n${snippets.join('\n')}\n`; + } + +- getVaryings(shaderStage) { +- const snippets = []; ++ getVaryings(shaderStage: NodeShaderStage) { ++ const snippets: string[] = []; + + if (shaderStage === 'vertex') { + this.getBuiltin('position', 'Vertex', 'vec4', 'vertex'); +@@ -606,7 +630,7 @@ ${flowData.code} + return shaderStage === 'vertex' ? this._getWGSLStruct('VaryingsStruct', '\t' + code) : code; + } + +- getUniforms(shaderStage) { ++ getUniforms(shaderStage: NodeShaderStage) { + const uniforms = this.uniforms[shaderStage]; + + const bindingSnippets = []; +diff --git a/examples-jsm/examples/renderers/webgpu/nodes/WGSLNodeFunction.ts b/examples-jsm/examples/renderers/webgpu/nodes/WGSLNodeFunction.ts +index 3abfc4ad..b68c95bb 100644 +--- a/examples-jsm/examples/renderers/webgpu/nodes/WGSLNodeFunction.ts ++++ b/examples-jsm/examples/renderers/webgpu/nodes/WGSLNodeFunction.ts +@@ -68,7 +68,7 @@ const parse = source => { + }; + + class WGSLNodeFunction extends NodeFunction { +- constructor(source) { ++ constructor(source: string) { + const { type, inputs, name, inputsCode, blockCode } = parse(source); + + super(type, inputs, name); +diff --git a/examples-jsm/examples/renderers/webgpu/nodes/WGSLNodeParser.ts b/examples-jsm/examples/renderers/webgpu/nodes/WGSLNodeParser.ts +index c32133df..8ac06078 100644 +--- a/examples-jsm/examples/renderers/webgpu/nodes/WGSLNodeParser.ts ++++ b/examples-jsm/examples/renderers/webgpu/nodes/WGSLNodeParser.ts +@@ -2,7 +2,7 @@ import NodeParser from '../../../nodes/core/NodeParser.js'; + import WGSLNodeFunction from './WGSLNodeFunction.js'; + + class WGSLNodeParser extends NodeParser { +- parseFunction(source) { ++ parseFunction(source: string) { + return new WGSLNodeFunction(source); + } + } diff --git a/examples-jsm/create-examples.js b/examples-jsm/create-examples.js index 483128cb6..ca60f49ff 100644 --- a/examples-jsm/create-examples.js +++ b/examples-jsm/create-examples.js @@ -4,8 +4,12 @@ import * as path from 'node:path'; import prettier from 'prettier'; const files = [ + 'nodes/accessors/BufferAttributeNode', 'nodes/accessors/TextureNode', + 'nodes/code/CodeNode', + 'nodes/code/FunctionNode', 'nodes/core/constants', + 'nodes/core/ContextNode', 'nodes/core/InputNode', 'nodes/core/Node', 'nodes/core/NodeAttribute', @@ -13,20 +17,26 @@ const files = [ 'nodes/core/NodeCache', 'nodes/core/NodeCode', 'nodes/core/NodeFrame', + 'nodes/core/NodeFunction', 'nodes/core/NodeKeywords', 'nodes/core/NodeParser', 'nodes/core/NodeUniform', 'nodes/core/NodeUtils', 'nodes/core/NodeVar', 'nodes/core/NodeVarying', + 'nodes/core/StackNode', + 'nodes/core/StructTypeNode', 'nodes/core/UniformGroupNode', 'nodes/core/UniformNode', 'nodes/fog/FogNode', 'nodes/gpgpu/ComputeNode', 'nodes/lighting/EnvironmentNode', + 'nodes/lighting/LightingContextNode', 'nodes/lighting/LightsNode', + 'nodes/materials/NodeMaterial', 'nodes/shadernode/ShaderNode', 'nodes/Nodes', + 'renderers/common/extras/PMREMGenerator', 'renderers/common/nodes/NodeBuilderState', 'renderers/common/nodes/NodeUniform', 'renderers/common/nodes/NodeUniformsGroup', @@ -44,6 +54,7 @@ const files = [ 'renderers/common/Color4', 'renderers/common/ComputePipeline', 'renderers/common/Constants', + 'renderers/common/CubeRenderTarget', 'renderers/common/DataMap', 'renderers/common/Geometries', 'renderers/common/Info', diff --git a/examples-jsm/declarations.js b/examples-jsm/declarations.js index b13c7bd8d..fce9b4116 100644 --- a/examples-jsm/declarations.js +++ b/examples-jsm/declarations.js @@ -3,6 +3,7 @@ import * as path from 'node:path'; import { argv } from 'node:process'; const files = [ + 'nodes/accessors/BufferAttributeNode', 'nodes/core/constants', 'nodes/core/Node', 'nodes/core/NodeAttribute', @@ -12,6 +13,7 @@ const files = [ 'nodes/core/NodeUniform', 'nodes/core/NodeVar', 'nodes/core/NodeVarying', + 'nodes/core/StructTypeNode', 'nodes/core/UniformNode', 'renderers/common/nodes/NodeBuilderState', 'renderers/common/nodes/Nodes', @@ -29,6 +31,7 @@ const files = [ 'renderers/common/Color4', 'renderers/common/ComputePipeline', 'renderers/common/Constants', + 'renderers/common/CubeRenderTarget', 'renderers/common/DataMap', 'renderers/common/Geometries', 'renderers/common/Info', diff --git a/types/three/examples/jsm/nodes/accessors/BufferAttributeNode.d.ts b/types/three/examples/jsm/nodes/accessors/BufferAttributeNode.d.ts new file mode 100644 index 000000000..7e2850059 --- /dev/null +++ b/types/three/examples/jsm/nodes/accessors/BufferAttributeNode.d.ts @@ -0,0 +1,49 @@ +import { BufferAttribute, InterleavedBuffer, InterleavedBufferAttribute, TypedArray, Usage } from "three"; +import InputNode from "../core/InputNode.js"; +import NodeBuilder from "../core/NodeBuilder.js"; +declare class BufferAttributeNode extends InputNode { + readonly isBufferNode: true; + bufferType: string | null; + bufferStride: number; + bufferOffset: number; + usage: Usage; + instanced: boolean; + attribute: BufferAttribute | InterleavedBufferAttribute | null; + constructor( + value: TypedArray | InterleavedBuffer | BufferAttribute, + bufferType?: string | null, + bufferStride?: number, + bufferOffset?: number, + ); + getNodeType(builder: NodeBuilder): string | null; + setup(builder: NodeBuilder): void; + generate(builder: NodeBuilder): string | null | undefined; + getInputType(): string; + setUsage(value: Usage): this; + setInstanced(value: boolean): this; +} +export default BufferAttributeNode; +export declare const bufferAttribute: ( + array: TypedArray | InterleavedBuffer | BufferAttribute, + type?: string | null, + stride?: number, + offset?: number, +) => import("../shadernode/ShaderNode.js").ShaderNodeObject; +export declare const dynamicBufferAttribute: ( + array: TypedArray | InterleavedBuffer | BufferAttribute, + type?: string | null, + stride?: number, + offset?: number, +) => import("../shadernode/ShaderNode.js").ShaderNodeObject; +export declare const instancedBufferAttribute: ( + array: TypedArray | InterleavedBuffer | BufferAttribute, + type?: string | null, + stride?: number, + offset?: number, +) => import("../shadernode/ShaderNode.js").ShaderNodeObject; +export declare const instancedDynamicBufferAttribute: ( + array: TypedArray | InterleavedBuffer | BufferAttribute, + type?: string | null, + stride?: number, + offset?: number, +) => import("../shadernode/ShaderNode.js").ShaderNodeObject; diff --git a/types/three/examples/jsm/nodes/core/NodeCache.d.ts b/types/three/examples/jsm/nodes/core/NodeCache.d.ts index e8625c365..3536d52cc 100644 --- a/types/three/examples/jsm/nodes/core/NodeCache.d.ts +++ b/types/three/examples/jsm/nodes/core/NodeCache.d.ts @@ -24,6 +24,8 @@ export interface ShaderStageNodeData { code?: NodeCode | undefined; usageCount?: number | undefined; snippet?: string | undefined; + propertyName?: string | undefined; + propertySizeName?: string | undefined; } interface NodeData { vertex?: ShaderStageNodeData | undefined; diff --git a/types/three/examples/jsm/nodes/core/NodeParser.d.ts b/types/three/examples/jsm/nodes/core/NodeParser.d.ts index fdffec703..2dbac5a28 100644 --- a/types/three/examples/jsm/nodes/core/NodeParser.d.ts +++ b/types/three/examples/jsm/nodes/core/NodeParser.d.ts @@ -1,4 +1,5 @@ -declare class NodeParser { - parseFunction(): void; +import NodeFunction from "./NodeFunction.js"; +declare abstract class NodeParser { + abstract parseFunction(source: string): NodeFunction; } export default NodeParser; diff --git a/types/three/examples/jsm/nodes/core/StructTypeNode.d.ts b/types/three/examples/jsm/nodes/core/StructTypeNode.d.ts new file mode 100644 index 000000000..03b09b7c8 --- /dev/null +++ b/types/three/examples/jsm/nodes/core/StructTypeNode.d.ts @@ -0,0 +1,8 @@ +import Node from "./Node.js"; +declare class StructTypeNode extends Node { + types: string[]; + readonly isStructTypeNode: true; + constructor(types: string[]); + getMemberTypes(): string[]; +} +export default StructTypeNode; diff --git a/types/three/examples/jsm/nodes/core/UniformNode.d.ts b/types/three/examples/jsm/nodes/core/UniformNode.d.ts index 521d6ec61..0f4334b84 100644 --- a/types/three/examples/jsm/nodes/core/UniformNode.d.ts +++ b/types/three/examples/jsm/nodes/core/UniformNode.d.ts @@ -15,4 +15,7 @@ declare class UniformNode extends InputNode { generate(builder: NodeBuilder, output: string | null): string; } export default UniformNode; -export declare const uniform: (arg1: InputNode | TValue, arg2?: Node | string) => any; +export declare const uniform: ( + arg1: InputNode | TValue, + arg2?: Node | string, +) => import("../shadernode/ShaderNode.js").ShaderNodeObject>; diff --git a/types/three/examples/jsm/renderers/common/CubeRenderTarget.d.ts b/types/three/examples/jsm/renderers/common/CubeRenderTarget.d.ts new file mode 100644 index 000000000..06771c7f6 --- /dev/null +++ b/types/three/examples/jsm/renderers/common/CubeRenderTarget.d.ts @@ -0,0 +1,7 @@ +import { RenderTargetOptions, Texture, WebGLCubeRenderTarget, WebGLRenderer } from "three"; +declare class CubeRenderTarget extends WebGLCubeRenderTarget { + readonly isCubeRenderTarget: true; + constructor(size?: number, options?: RenderTargetOptions); + fromEquirectangularTexture(renderer: WebGLRenderer, texture: Texture): this; +} +export default CubeRenderTarget; diff --git a/types/three/examples/jsm/renderers/common/nodes/NodeBuilderState.d.ts b/types/three/examples/jsm/renderers/common/nodes/NodeBuilderState.d.ts index 30229f73f..68a09a47e 100644 --- a/types/three/examples/jsm/renderers/common/nodes/NodeBuilderState.d.ts +++ b/types/three/examples/jsm/renderers/common/nodes/NodeBuilderState.d.ts @@ -5,6 +5,7 @@ declare class NodeBuilderState { vertexShader: string | null; fragmentShader: string | null; computeShader: string | null; + transforms: never[]; nodeAttributes: NodeAttribute[]; bindings: Binding[]; updateNodes: Node[]; diff --git a/types/three/src/core/InterleavedBuffer.d.ts b/types/three/src/core/InterleavedBuffer.d.ts index be08e1f4d..7b01ef5bf 100644 --- a/types/three/src/core/InterleavedBuffer.d.ts +++ b/types/three/src/core/InterleavedBuffer.d.ts @@ -10,6 +10,8 @@ import { InterleavedBufferAttribute } from "./InterleavedBufferAttribute.js"; * @see {@link https://github.com/mrdoob/three.js/blob/master/src/core/InterleavedBuffer.js | Source} */ export class InterleavedBuffer { + readonly isInterleavedBuffer: true; + /** * Create a new instance of {@link InterleavedBuffer} * @param array A {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray | TypedArray} with a shared buffer. Stores the geometry data. diff --git a/types/three/src/math/Matrix3.d.ts b/types/three/src/math/Matrix3.d.ts index 850265735..0d2a0448b 100644 --- a/types/three/src/math/Matrix3.d.ts +++ b/types/three/src/math/Matrix3.d.ts @@ -52,6 +52,8 @@ export interface Matrix { * ( class Matrix3 implements Matrix ) */ export class Matrix3 implements Matrix { + readonly isMatrix3: true; + /** * Creates an identity matrix. */ diff --git a/types/three/src/math/Matrix4.d.ts b/types/three/src/math/Matrix4.d.ts index 1e4a5c9ce..68490151b 100644 --- a/types/three/src/math/Matrix4.d.ts +++ b/types/three/src/math/Matrix4.d.ts @@ -42,6 +42,8 @@ export type Matrix4Tuple = [ * m.multiply( m3 ); */ export class Matrix4 implements Matrix { + readonly isMatrix4: true; + /** * Creates an identity matrix. */