diff --git a/types/three/examples/jsm/nodes/Nodes.d.ts b/types/three/examples/jsm/nodes/Nodes.d.ts index d194de5ab..6ccf790b4 100644 --- a/types/three/examples/jsm/nodes/Nodes.d.ts +++ b/types/three/examples/jsm/nodes/Nodes.d.ts @@ -7,7 +7,7 @@ import ConstNode from './core/ConstNode'; import ContextNode from './core/ContextNode'; import ExpressionNode from './core/ExpressionNode'; import FunctionCallNode from './core/FunctionCallNode'; -import FunctionNode from './core/FunctionNode'; +import FunctionNode, { FunctionNodeParameters } from './core/FunctionNode'; import InstanceIndexNode from './core/InstanceIndexNode'; import Node from './core/Node'; import NodeAttribute from './core/NodeAttribute'; @@ -118,6 +118,7 @@ export { ExpressionNode, FunctionCallNode, FunctionNode, + FunctionNodeParameters, InstanceIndexNode, Node, NodeAttribute, diff --git a/types/three/examples/jsm/nodes/core/CodeNode.d.ts b/types/three/examples/jsm/nodes/core/CodeNode.d.ts index c24c0e805..7ac8b841b 100644 --- a/types/three/examples/jsm/nodes/core/CodeNode.d.ts +++ b/types/three/examples/jsm/nodes/core/CodeNode.d.ts @@ -3,13 +3,13 @@ import Node from './Node'; import NodeBuilder from './NodeBuilder'; export interface CodeNodeInclude { - build(): void; + build(builder: NodeBuilder): void; } export default class CodeNode extends Node { isCodeNode: true; code: string; - constructor(code: string, nodeType?: NodeTypeOption); + constructor(code?: string, includes?: CodeNodeInclude[]); setIncludes(includes: CodeNodeInclude[]): this; getIncludes(builder: NodeBuilder): CodeNodeInclude[]; diff --git a/types/three/examples/jsm/nodes/core/FunctionCallNode.d.ts b/types/three/examples/jsm/nodes/core/FunctionCallNode.d.ts index 4712e2dc9..6e62e28aa 100644 --- a/types/three/examples/jsm/nodes/core/FunctionCallNode.d.ts +++ b/types/three/examples/jsm/nodes/core/FunctionCallNode.d.ts @@ -2,12 +2,12 @@ import FunctionNode from './FunctionNode'; import TempNode from './TempNode'; import Node from './Node'; -export default class FunctionCallNode extends TempNode { - functionNode: FunctionNode; +export default class FunctionCallNode

extends TempNode { + functionNode: FunctionNode

; parameters: { [name: string]: Node }; - constructor(functionNode?: FunctionNode, parameters?: { [name: string]: Node }); + constructor(functionNode?: FunctionNode

, parameters?: P); - setParameters(parameters: { [name: string]: Node }): this; - getParameters(): { [name: string]: Node }; + setParameters(parameters: P): this; + getParameters(): P; } diff --git a/types/three/examples/jsm/nodes/core/FunctionNode.d.ts b/types/three/examples/jsm/nodes/core/FunctionNode.d.ts index 33ed738e2..e312df8af 100644 --- a/types/three/examples/jsm/nodes/core/FunctionNode.d.ts +++ b/types/three/examples/jsm/nodes/core/FunctionNode.d.ts @@ -1,15 +1,17 @@ -import CodeNode from './CodeNode'; +import CodeNode, { CodeNodeInclude } from './CodeNode'; import FunctionCallNode from './FunctionCallNode'; import NodeBuilder from './NodeBuilder'; import NodeFunction from './NodeFunction'; import NodeFunctionInput from './NodeFunctionInput'; import Node from './Node'; -export default class FunctionNode extends CodeNode { +export type FunctionNodeParameters = Node[] | { [name: string]: Node }; + +export default class FunctionNode

extends CodeNode { keywords: { [key: string]: Node }; - constructor(code?: string); + constructor(code?: string, includes?: CodeNodeInclude[]); getInputs(builder: NodeBuilder): NodeFunctionInput[]; getNodeFunction(builder: NodeBuilder): NodeFunction; - call(parameters: { [name: string]: Node }): FunctionCallNode; + call(parameters: P): FunctionCallNode

; } diff --git a/types/three/examples/jsm/nodes/materialx/functions/lib/mx_hsv.d.ts b/types/three/examples/jsm/nodes/materialx/functions/lib/mx_hsv.d.ts new file mode 100644 index 000000000..5dd4b8dab --- /dev/null +++ b/types/three/examples/jsm/nodes/materialx/functions/lib/mx_hsv.d.ts @@ -0,0 +1,4 @@ +import { FnParameters, Node, Swizzable } from '../../../Nodes'; + +export function mx_hsvtorgb(...params: FnParameters<[Node]>): Swizzable; +export function mx_rgbtohsv(...params: FnParameters<[Node]>): Swizzable; diff --git a/types/three/examples/jsm/nodes/materialx/functions/lib/mx_noise.d.ts b/types/three/examples/jsm/nodes/materialx/functions/lib/mx_noise.d.ts new file mode 100644 index 000000000..28187b33b --- /dev/null +++ b/types/three/examples/jsm/nodes/materialx/functions/lib/mx_noise.d.ts @@ -0,0 +1,6 @@ +import { FnParameters, Node, Swizzable } from '../../../Nodes'; + +export function mx_perlin_noise_float(...params: FnParameters<[Node]>): Swizzable; +export function mx_cell_noise_float(...params: FnParameters<[Node]>): Swizzable; +export function mx_worley_noise_float(...params: FnParameters<[Node]>): Swizzable; +export function mx_fractal_noise_float(...params: FnParameters<[Node, Node, Node, Node]>): Swizzable; diff --git a/types/three/examples/jsm/nodes/shadernode/ShaderNode.d.ts b/types/three/examples/jsm/nodes/shadernode/ShaderNode.d.ts index 900a3b3e5..849744a47 100644 --- a/types/three/examples/jsm/nodes/shadernode/ShaderNode.d.ts +++ b/types/three/examples/jsm/nodes/shadernode/ShaderNode.d.ts @@ -7,17 +7,19 @@ export type Swizzable = T & }; /** anything that can be passed to {@link nodeObject} and returns a proxy */ -export type NodeRepresentation = number | boolean | Node | Swizzable; +export type NodeRepresentation = number | boolean | Node | Swizzable; /** anything that can be passed to {@link nodeObject} */ export type NodeObjectOption = NodeRepresentation | string; -// same logic as in ShaderNodeObject +// same logic as in ShaderNodeObject: number,boolean,node->swizzable, otherwise do nothing export type NodeObject = T extends Node ? Swizzable : T extends number | boolean ? Swizzable : T; -type MakeObjectOption = T extends Node ? NodeRepresentation : T; +// opposite of NodeObject: node -> node|swizzable|boolean|number, otherwise do nothing +type Proxied = T extends Node ? NodeRepresentation : T; // https://github.com/microsoft/TypeScript/issues/42435#issuecomment-765557874 -type MakeObjectOptions = [...{ [index in keyof T]: MakeObjectOption }]; +export type ProxiedTuple = [...{ [index in keyof T]: Proxied }]; +export type ProxiedObject = { [index in keyof T]: Proxied }; type RemoveTail = T extends [unknown, ...infer X] ? X : []; type RemoveHeadAndTail = T extends [unknown, ...infer X, unknown] ? X : []; @@ -121,22 +123,22 @@ export function nodeArray(obj: readonly [...T]): N export function nodeProxy( nodeClass: T, -): (...params: MakeObjectOptions>) => Swizzable>; +): (...params: ProxiedTuple>) => Swizzable>; export function nodeProxy>( nodeClass: T, scope: S, -): (...params: MakeObjectOptions>>) => Swizzable>; +): (...params: ProxiedTuple>>) => Swizzable>; export function nodeProxy>( nodeClass: T, scope: S, factor: NodeObjectOption, -): (...params: MakeObjectOptions>>) => Swizzable>; +): (...params: ProxiedTuple>>) => Swizzable>; export function nodeImmutable( nodeClass: T, - ...params: MakeObjectOptions> + ...params: ProxiedTuple> ): Swizzable>; export class ShaderNode { diff --git a/types/three/examples/jsm/nodes/shadernode/ShaderNodeBaseElements.d.ts b/types/three/examples/jsm/nodes/shadernode/ShaderNodeBaseElements.d.ts index 3b74fe54e..3c499844e 100644 --- a/types/three/examples/jsm/nodes/shadernode/ShaderNodeBaseElements.d.ts +++ b/types/three/examples/jsm/nodes/shadernode/ShaderNodeBaseElements.d.ts @@ -13,6 +13,9 @@ import { Swizzable, NodeRepresentation, NodeOrType, + NodeObjects, + ProxiedObject, + ProxiedTuple, } from './ShaderNode'; import { Material, Texture } from '../../../../src/Three'; import { NodeTypeOption, NodeUserData, NodeValueOption } from '../core/constants'; @@ -22,13 +25,14 @@ import { BypassNode, CameraNode, CodeNode, + CodeNodeInclude, ComputeNode, ContextNode, - ConvertNode, ExpressionNode, FrontFacingNode, FunctionCallNode, FunctionNode, + FunctionNodeParameters, InstanceIndexNode, MaterialNode, MaterialReferenceNode, @@ -83,8 +87,6 @@ export const imat4: ConvertType; export const umat4: ConvertType; export const bmat4: ConvertType; -export function func(code: string): ShaderNode; - export function uniform(nodeOrType: Node | Swizzable | NodeValueOption): Swizzable; export function attribute(attributeName: string, nodeType: NodeTypeOption): Swizzable; @@ -95,10 +97,27 @@ export function code(code: string, nodeType?: NodeTypeOption): Swizzable; export function expression(snipped?: string, nodeType?: NodeTypeOption): Swizzable; -export function call( - functionNode?: NodeRepresentation, - parameters?: { [name: string]: Node }, -): Swizzable; +// definition: const call = nodeProxy(FunctionCallNode); +export function call

( + functionNode?: FunctionNode

, + parameters?: ProxiedObject

, +): Swizzable>; + +export type FnParameters

= P extends readonly [...unknown[]] + ? ProxiedTuple

+ : readonly [ProxiedObject

]; + +// tslint:disable:no-unnecessary-generics +export function func

( + code: string, + includes?: CodeNodeInclude[], +): { call: (...params: FnParameters

) => Swizzable }; + +export function fn

( + code: string, + includes?: CodeNodeInclude[], +): (...params: FnParameters

) => Swizzable; +// tslint:enable:no-unnecessary-generics export const instanceIndex: Swizzable; export function label(node: NodeRepresentation, name?: string): Swizzable; diff --git a/types/three/test/nodes/nodes-FunctionNode.ts b/types/three/test/nodes/nodes-FunctionNode.ts new file mode 100644 index 000000000..ea8e67a07 --- /dev/null +++ b/types/three/test/nodes/nodes-FunctionNode.ts @@ -0,0 +1,57 @@ +/** + * Various tests of func, fn and call + */ + +import { + code, + fn, + uv, + func, + Node, + FunctionNode, + call, + Swizzable, + FunctionCallNode, +} from 'three/examples/jsm/nodes/Nodes'; + +import { ProxiedObject } from 'three/examples/jsm/nodes/shadernode/ShaderNode'; + +export const mx_noise = code('whatever'); +const includes = [mx_noise]; + +const someFunc1 = new FunctionNode<[a: Node]>(); +const someFunc2 = new FunctionNode<{ a: Node }>(); + +// tslint:disable-next-line:no-unnecessary-generics +function assertSwizzable(_s: Swizzable) {} + +type a = ProxiedObject; + +assertSwizzable>(call(someFunc1, [1])); +assertSwizzable>(call(someFunc1, [uv()])); +assertSwizzable>(call(someFunc1, [uv().xy])); +assertSwizzable>(call(someFunc2, { a: 1 })); +assertSwizzable>(call(someFunc2, { a: uv() })); +assertSwizzable>(call(someFunc2, { a: uv().xy })); + +export const mx_cell_noise_float_call = func<[Node]>('float mx_cell_noise_float( vec3 p )', includes); +export const mx_worley_noise_float_call = func<[Node, Node, Node]>( + 'float mx_worley_noise_float( vec3 p, float jitter, int metric )', + includes, +); +export const ab_call = func<{ a: Node; b: Node }>('float mx_cell_noise_float( vec3 p )', includes); + +assertSwizzable(mx_cell_noise_float_call.call(uv())); +assertSwizzable(mx_worley_noise_float_call.call(uv(), 1, 1)); +assertSwizzable(ab_call.call({ a: 1, b: uv() })); + +export const mx_cell_noise_float = fn<[Node]>('float mx_cell_noise_float( vec3 p )', includes); +export const mx_worley_noise_float = fn<[Node, Node, Node]>( + 'float mx_worley_noise_float( vec3 p, float jitter, int metric )', + includes, +); +export const ab = fn<{ a: Node; b: Node }>('float mx_cell_noise_float( vec3 p )', includes); + +assertSwizzable(mx_cell_noise_float(uv())); +assertSwizzable(mx_worley_noise_float(uv(), 1, 1)); +assertSwizzable(ab({ a: 1, b: uv() })); diff --git a/types/three/test/nodes/nodes-ShaderNode.ts b/types/three/test/nodes/nodes-ShaderNode.ts index 47ea44467..0bb5fb9b5 100644 --- a/types/three/test/nodes/nodes-ShaderNode.ts +++ b/types/three/test/nodes/nodes-ShaderNode.ts @@ -22,7 +22,6 @@ import { ConvertType, Swizzable } from 'three/examples/jsm/nodes/shadernode/Shad // just to type check // tslint:disable-next-line:no-unnecessary-generics function assertSwizzable(_s: Swizzable) {} -function assertNode(_s: Node) {} export const color = new ConvertType('color'); const s = color(1); diff --git a/types/three/test/nodes/nodes-materialx.ts b/types/three/test/nodes/nodes-materialx.ts new file mode 100644 index 000000000..a1e6a87af --- /dev/null +++ b/types/three/test/nodes/nodes-materialx.ts @@ -0,0 +1,15 @@ +import { + mx_perlin_noise_float, + mx_cell_noise_float, + mx_worley_noise_float, + mx_fractal_noise_float, +} from 'three/examples/jsm/nodes/materialx/functions/lib/mx_noise'; + +import { mx_hsvtorgb, mx_rgbtohsv } from 'three/examples/jsm/nodes/materialx/functions/lib/mx_hsv'; + +mx_perlin_noise_float(1); +mx_cell_noise_float(1); +mx_worley_noise_float(1); +mx_fractal_noise_float(1, 1, 1, 1); +mx_hsvtorgb(1); +mx_rgbtohsv(1); diff --git a/types/three/tsconfig.json b/types/three/tsconfig.json index dac57dc63..4f63754b3 100644 --- a/types/three/tsconfig.json +++ b/types/three/tsconfig.json @@ -63,6 +63,8 @@ "test/misc/misc-gpucomputationrender.ts", "test/nodes/nodes-ColorAdjustmentNode.ts", "test/nodes/nodes-Iridescence.ts", + "test/nodes/nodes-FunctionNode.ts", + "test/nodes/nodes-materialx.ts", "test/nodes/nodes-ShaderNode.ts", "test/nodes/nodes-ShaderNodeBaseElements.ts", "test/nodes/nodes-ShaderNodeElements.ts",