MCP 3D Printer Server

by DMontgomery40
Verified
import Node from '../core/Node.js'; import { nodeObject, vec3 } from '../tsl/TSLBase.js'; import { hashArray } from '../core/NodeUtils.js'; /** @module LightsNode **/ const sortLights = ( lights ) => { return lights.sort( ( a, b ) => a.id - b.id ); }; const getLightNodeById = ( id, lightNodes ) => { for ( const lightNode of lightNodes ) { if ( lightNode.isAnalyticLightNode && lightNode.light.id === id ) { return lightNode; } } return null; }; const _lightsNodeRef = /*@__PURE__*/ new WeakMap(); /** * This node represents the scene's lighting and manages the lighting model's life cycle * for the current build 3D object. It is responsible for computing the total outgoing * light in a given lighting context. * * @augments Node */ class LightsNode extends Node { static get type() { return 'LightsNode'; } /** * Constructs a new lights node. */ constructor() { super( 'vec3' ); /** * A node representing the total diffuse light. * * @type {Node<vec3>} */ this.totalDiffuseNode = vec3().toVar( 'totalDiffuse' ); /** * A node representing the total specular light. * * @type {Node<vec3>} */ this.totalSpecularNode = vec3().toVar( 'totalSpecular' ); /** * A node representing the outgoing light. * * @type {Node<vec3>} */ this.outgoingLightNode = vec3().toVar( 'outgoingLight' ); /** * An array representing the lights in the scene. * * @private * @type {Array<Light>} */ this._lights = []; /** * For each light in the scene, this node will create a * corresponding light node. * * @private * @type {Array<LightingNode>?} * @default null */ this._lightNodes = null; /** * A hash for identifying the current light nodes setup. * * @private * @type {String?} * @default null */ this._lightNodesHash = null; /** * `LightsNode` sets this property to `true` by default. * * @type {Boolean} * @default true */ this.global = true; } /** * Overwrites the default {@link Node#customCacheKey} implementation by including the * light IDs into the cache key. * * @return {Number} The custom cache key. */ customCacheKey() { const lightIDs = []; const lights = this._lights; for ( let i = 0; i < lights.length; i ++ ) { lightIDs.push( lights[ i ].id ); } return hashArray( lightIDs ); } /** * Computes a hash value for identifying the current light nodes setup. * * @param {NodeBuilder} builder - A reference to the current node builder. * @return {String} The computed hash. */ getHash( builder ) { if ( this._lightNodesHash === null ) { if ( this._lightNodes === null ) this.setupLightsNode( builder ); const hash = []; for ( const lightNode of this._lightNodes ) { hash.push( lightNode.getSelf().getHash() ); } this._lightNodesHash = 'lights-' + hash.join( ',' ); } return this._lightNodesHash; } analyze( builder ) { const properties = builder.getDataFromNode( this ); for ( const node of properties.nodes ) { node.build( builder ); } } /** * Creates lighting nodes for each scene light. This makes it possible to further * process lights in the node system. * * @param {NodeBuilder} builder - A reference to the current node builder. */ setupLightsNode( builder ) { const lightNodes = []; const previousLightNodes = this._lightNodes; const lights = sortLights( this._lights ); const nodeLibrary = builder.renderer.library; for ( const light of lights ) { if ( light.isNode ) { lightNodes.push( nodeObject( light ) ); } else { let lightNode = null; if ( previousLightNodes !== null ) { lightNode = getLightNodeById( light.id, previousLightNodes ); // reuse existing light node } if ( lightNode === null ) { // find the corresponding node type for a given light const lightNodeClass = nodeLibrary.getLightNodeClass( light.constructor ); if ( lightNodeClass === null ) { console.warn( `LightsNode.setupNodeLights: Light node not found for ${ light.constructor.name }` ); continue; } let lightNode = null; if ( ! _lightsNodeRef.has( light ) ) { lightNode = nodeObject( new lightNodeClass( light ) ); _lightsNodeRef.set( light, lightNode ); } else { lightNode = _lightsNodeRef.get( light ); } lightNodes.push( lightNode ); } } } this._lightNodes = lightNodes; } /** * Setups the internal lights by building all respective * light nodes. * * @param {NodeBuilder} builder - A reference to the current node builder. * @param {Array<LightingNode>} lightNodes - An array of lighting nodes. */ setupLights( builder, lightNodes ) { for ( const lightNode of lightNodes ) { lightNode.build( builder ); } } /** * The implementation makes sure that for each light in the scene * there is a corresponding light node. By building the light nodes * and evaluating the lighting model the outgoing light is computed. * * @param {NodeBuilder} builder - A reference to the current node builder. * @return {Node<vec3>} A node representing the outgoing light. */ setup( builder ) { if ( this._lightNodes === null ) this.setupLightsNode( builder ); const context = builder.context; const lightingModel = context.lightingModel; let outgoingLightNode = this.outgoingLightNode; if ( lightingModel ) { const { _lightNodes, totalDiffuseNode, totalSpecularNode } = this; context.outgoingLight = outgoingLightNode; const stack = builder.addStack(); // const properties = builder.getDataFromNode( this ); properties.nodes = stack.nodes; // lightingModel.start( context, stack, builder ); // lights this.setupLights( builder, _lightNodes ); // lightingModel.indirect( context, stack, builder ); // const { backdrop, backdropAlpha } = context; const { directDiffuse, directSpecular, indirectDiffuse, indirectSpecular } = context.reflectedLight; let totalDiffuse = directDiffuse.add( indirectDiffuse ); if ( backdrop !== null ) { if ( backdropAlpha !== null ) { totalDiffuse = vec3( backdropAlpha.mix( totalDiffuse, backdrop ) ); } else { totalDiffuse = vec3( backdrop ); } context.material.transparent = true; } totalDiffuseNode.assign( totalDiffuse ); totalSpecularNode.assign( directSpecular.add( indirectSpecular ) ); outgoingLightNode.assign( totalDiffuseNode.add( totalSpecularNode ) ); // lightingModel.finish( context, stack, builder ); // outgoingLightNode = outgoingLightNode.bypass( builder.removeStack() ); } return outgoingLightNode; } /** * Configures this node with an array of lights. * * @param {Array<Light>} lights - An array of lights. * @return {LightsNode} A reference to this node. */ setLights( lights ) { this._lights = lights; this._lightNodes = null; this._lightNodesHash = null; return this; } /** * Returns an array of the scene's lights. * * @return {Array<Light>} The scene's lights. */ getLights() { return this._lights; } /** * Whether the scene has lights or not. * * @type {Boolean} */ get hasLights() { return this._lights.length > 0; } } export default LightsNode; /** * TSL function for creating an instance of `LightsNode` and configuring * it with the given array of lights. * * @function * @param {Array<Light>} lights - An array of lights. * @return {LightsNode} The created lights node. */ export const lights = ( lights = [] ) => nodeObject( new LightsNode() ).setLights( lights );