Skip to content

Commit

Permalink
feat: fn/func in nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
miko3k committed Aug 20, 2022
1 parent 8951c37 commit ced6ed3
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 28 deletions.
3 changes: 2 additions & 1 deletion types/three/examples/jsm/nodes/Nodes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -118,6 +118,7 @@ export {
ExpressionNode,
FunctionCallNode,
FunctionNode,
FunctionNodeParameters,
InstanceIndexNode,
Node,
NodeAttribute,
Expand Down
4 changes: 2 additions & 2 deletions types/three/examples/jsm/nodes/core/CodeNode.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down
10 changes: 5 additions & 5 deletions types/three/examples/jsm/nodes/core/FunctionCallNode.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<P extends Node[] | { [name: string]: Node }> extends TempNode {
functionNode: FunctionNode<P>;
parameters: { [name: string]: Node };

constructor(functionNode?: FunctionNode, parameters?: { [name: string]: Node });
constructor(functionNode?: FunctionNode<P>, parameters?: P);

setParameters(parameters: { [name: string]: Node }): this;
getParameters(): { [name: string]: Node };
setParameters(parameters: P): this;
getParameters(): P;
}
10 changes: 6 additions & 4 deletions types/three/examples/jsm/nodes/core/FunctionNode.d.ts
Original file line number Diff line number Diff line change
@@ -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<P extends Node[] | { [name: string]: Node }> 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<P>;
}
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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;
18 changes: 10 additions & 8 deletions types/three/examples/jsm/nodes/shadernode/ShaderNode.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@ export type Swizzable<T extends Node = Node> = T &
};

/** anything that can be passed to {@link nodeObject} and returns a proxy */
export type NodeRepresentation = number | boolean | Node | Swizzable;
export type NodeRepresentation<T extends Node = Node> = number | boolean | Node | Swizzable<T>;

/** 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> = T extends Node ? Swizzable<T> : T extends number | boolean ? Swizzable<ConstNode> : T;

type MakeObjectOption<T> = T extends Node ? NodeRepresentation : T;
// opposite of NodeObject: node -> node|swizzable|boolean|number, otherwise do nothing
type Proxied<T> = T extends Node ? NodeRepresentation<T> : T;
// https://github.com/microsoft/TypeScript/issues/42435#issuecomment-765557874
type MakeObjectOptions<T extends readonly [...unknown[]]> = [...{ [index in keyof T]: MakeObjectOption<T[index]> }];
export type ProxiedTuple<T extends readonly [...unknown[]]> = [...{ [index in keyof T]: Proxied<T[index]> }];
export type ProxiedObject<T> = { [index in keyof T]: Proxied<T[index]> };
type RemoveTail<T extends readonly [...unknown[]]> = T extends [unknown, ...infer X] ? X : [];
type RemoveHeadAndTail<T extends readonly [...unknown[]]> = T extends [unknown, ...infer X, unknown] ? X : [];

Expand Down Expand Up @@ -121,22 +123,22 @@ export function nodeArray<T extends NodeObjectOption[]>(obj: readonly [...T]): N

export function nodeProxy<T>(
nodeClass: T,
): (...params: MakeObjectOptions<GetConstructors<T>>) => Swizzable<ConstructedNode<T>>;
): (...params: ProxiedTuple<GetConstructors<T>>) => Swizzable<ConstructedNode<T>>;

export function nodeProxy<T, S extends GetPossibleScopes<T>>(
nodeClass: T,
scope: S,
): (...params: MakeObjectOptions<RemoveTail<GetConstructorsByScope<T, S>>>) => Swizzable<ConstructedNode<T>>;
): (...params: ProxiedTuple<RemoveTail<GetConstructorsByScope<T, S>>>) => Swizzable<ConstructedNode<T>>;

export function nodeProxy<T, S extends GetPossibleScopes<T>>(
nodeClass: T,
scope: S,
factor: NodeObjectOption,
): (...params: MakeObjectOptions<RemoveHeadAndTail<GetConstructorsByScope<T, S>>>) => Swizzable<ConstructedNode<T>>;
): (...params: ProxiedTuple<RemoveHeadAndTail<GetConstructorsByScope<T, S>>>) => Swizzable<ConstructedNode<T>>;

export function nodeImmutable<T>(
nodeClass: T,
...params: MakeObjectOptions<GetConstructors<T>>
...params: ProxiedTuple<GetConstructors<T>>
): Swizzable<ConstructedNode<T>>;

export class ShaderNode<T = {}, R extends Node = Node> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -22,13 +25,14 @@ import {
BypassNode,
CameraNode,
CodeNode,
CodeNodeInclude,
ComputeNode,
ContextNode,
ConvertNode,
ExpressionNode,
FrontFacingNode,
FunctionCallNode,
FunctionNode,
FunctionNodeParameters,
InstanceIndexNode,
MaterialNode,
MaterialReferenceNode,
Expand Down Expand Up @@ -83,8 +87,6 @@ export const imat4: ConvertType;
export const umat4: ConvertType;
export const bmat4: ConvertType;

export function func(code: string): ShaderNode<FunctionNode>;

export function uniform(nodeOrType: Node | Swizzable | NodeValueOption): Swizzable;

export function attribute(attributeName: string, nodeType: NodeTypeOption): Swizzable;
Expand All @@ -95,10 +97,27 @@ export function code(code: string, nodeType?: NodeTypeOption): Swizzable<CodeNod
export function context(node: NodeRepresentation, context: NodeBuilderContext): Swizzable<ContextNode>;
export function expression(snipped?: string, nodeType?: NodeTypeOption): Swizzable<ExpressionNode>;

export function call(
functionNode?: NodeRepresentation,
parameters?: { [name: string]: Node },
): Swizzable<FunctionCallNode>;
// definition: const call = nodeProxy(FunctionCallNode);
export function call<P extends FunctionNodeParameters>(
functionNode?: FunctionNode<P>,
parameters?: ProxiedObject<P>,
): Swizzable<FunctionCallNode<P>>;

export type FnParameters<P extends FunctionNodeParameters> = P extends readonly [...unknown[]]
? ProxiedTuple<P>
: readonly [ProxiedObject<P>];

// tslint:disable:no-unnecessary-generics
export function func<P extends FunctionNodeParameters>(
code: string,
includes?: CodeNodeInclude[],
): { call: (...params: FnParameters<P>) => Swizzable };

export function fn<P extends FunctionNodeParameters>(
code: string,
includes?: CodeNodeInclude[],
): (...params: FnParameters<P>) => Swizzable;
// tslint:enable:no-unnecessary-generics

export const instanceIndex: Swizzable<InstanceIndexNode>;
export function label(node: NodeRepresentation, name?: string): Swizzable<VarNode>;
Expand Down
57 changes: 57 additions & 0 deletions types/three/test/nodes/nodes-FunctionNode.ts
Original file line number Diff line number Diff line change
@@ -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<T extends Node>(_s: Swizzable<T>) {}

type a = ProxiedObject<readonly [Node]>;

assertSwizzable<FunctionCallNode<[Node]>>(call(someFunc1, [1]));
assertSwizzable<FunctionCallNode<[Node]>>(call(someFunc1, [uv()]));
assertSwizzable<FunctionCallNode<[Node]>>(call(someFunc1, [uv().xy]));
assertSwizzable<FunctionCallNode<{ a: Node }>>(call(someFunc2, { a: 1 }));
assertSwizzable<FunctionCallNode<{ a: Node }>>(call(someFunc2, { a: uv() }));
assertSwizzable<FunctionCallNode<{ a: Node }>>(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<Node>(mx_cell_noise_float_call.call(uv()));
assertSwizzable<Node>(mx_worley_noise_float_call.call(uv(), 1, 1));
assertSwizzable<Node>(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<Node>(mx_cell_noise_float(uv()));
assertSwizzable<Node>(mx_worley_noise_float(uv(), 1, 1));
assertSwizzable<Node>(ab({ a: 1, b: uv() }));
1 change: 0 additions & 1 deletion types/three/test/nodes/nodes-ShaderNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T extends Node>(_s: Swizzable<T>) {}
function assertNode(_s: Node) {}

export const color = new ConvertType('color');
const s = color(1);
Expand Down
15 changes: 15 additions & 0 deletions types/three/test/nodes/nodes-materialx.ts
Original file line number Diff line number Diff line change
@@ -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);
2 changes: 2 additions & 0 deletions types/three/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit ced6ed3

Please sign in to comment.