UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

112 lines (105 loc) 3.42 kB
import CodeNode from './CodeNode.js'; import { nodeObject } from '../tsl/TSLBase.js'; /** * This class represents a native shader function. It can be used to implement * certain aspects of a node material with native shader code. There are two predefined * TSL functions for easier usage. * * - `wgslFn`: Creates a WGSL function node. * - `glslFn`: Creates a GLSL function node. * * A basic example with one include looks like so: * * ```js * const desaturateWGSLFn = wgslFn( ` * fn desaturate( color:vec3<f32> ) -> vec3<f32> { * let lum = vec3<f32>( 0.299, 0.587, 0.114 ); * return vec3<f32>( dot( lum, color ) ); * }` *); * const someWGSLFn = wgslFn( ` * fn someFn( color:vec3<f32> ) -> vec3<f32> { * return desaturate( color ); * } * `, [ desaturateWGSLFn ] ); * material.colorNode = someWGSLFn( { color: texture( map ) } ); *``` * @augments CodeNode */ class FunctionNode extends CodeNode { static get type() { return 'FunctionNode'; } /** * Constructs a new function node. * * @param {string} [code=''] - The native code. * @param {Array<Node>} [includes=[]] - An array of includes. * @param {('js'|'wgsl'|'glsl')} [language=''] - The used language. */ constructor(code = '', includes = [], language = '') { super(code, includes, language); } getNodeType(builder) { return this.getNodeFunction(builder).type; } /** * Returns the inputs of this function node. * * @param {NodeBuilder} builder - The current node builder. * @return {Array<NodeFunctionInput>} The inputs. */ getInputs(builder) { return this.getNodeFunction(builder).inputs; } /** * Returns the node function for this function node. * * @param {NodeBuilder} builder - The current node builder. * @return {NodeFunction} The node function. */ getNodeFunction(builder) { const nodeData = builder.getDataFromNode(this); let nodeFunction = nodeData.nodeFunction; if (nodeFunction === undefined) { nodeFunction = builder.parser.parseFunction(this.code); nodeData.nodeFunction = nodeFunction; } return nodeFunction; } generate(builder, output) { super.generate(builder); const nodeFunction = this.getNodeFunction(builder); const name = nodeFunction.name; const type = nodeFunction.type; const nodeCode = builder.getCodeFromNode(this, type); if (name !== '') { // use a custom property name nodeCode.name = name; } const propertyName = builder.getPropertyName(nodeCode); const code = this.getNodeFunction(builder).getCode(propertyName); nodeCode.code = code + '\n'; if (output === 'property') { return propertyName; } else { return builder.format(`${propertyName}()`, type, output); } } } export default FunctionNode; const nativeFn = (code, includes = [], language = '') => { for (let i = 0; i < includes.length; i++) { const include = includes[i]; // TSL Function: glslFn, wgslFn if (typeof include === 'function') { includes[i] = include.functionNode; } } const functionNode = nodeObject(new FunctionNode(code, includes, language)); const fn = (...params) => functionNode.call(...params); fn.functionNode = functionNode; return fn; }; export const glslFn = (code, includes) => nativeFn(code, includes, 'glsl'); export const wgslFn = (code, includes) => nativeFn(code, includes, 'wgsl');