You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							354 lines
						
					
					
						
							5.4 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							354 lines
						
					
					
						
							5.4 KiB
						
					
					
				| import { NodeUpdateType } from './constants.js'; | |
| import { getNodesKeys, getCacheKey } from './NodeUtils.js'; | |
| import { MathUtils } from 'three'; | |
| 
 | |
| let _nodeId = 0; | |
| 
 | |
| class Node { | |
| 
 | |
| 	constructor( nodeType = null ) { | |
| 
 | |
| 		this.isNode = true; | |
| 
 | |
| 		this.nodeType = nodeType; | |
| 
 | |
| 		this.updateType = NodeUpdateType.NONE; | |
| 
 | |
| 		this.uuid = MathUtils.generateUUID(); | |
| 
 | |
| 		Object.defineProperty( this, 'id', { value: _nodeId ++ } ); | |
| 
 | |
| 	} | |
| 
 | |
| 	get type() { | |
| 
 | |
| 		return this.constructor.name; | |
| 
 | |
| 	} | |
| 
 | |
| 	getChildren() { | |
| 
 | |
| 		const children = []; | |
| 
 | |
| 		for ( const property in this ) { | |
| 
 | |
| 			const object = this[ property ]; | |
| 
 | |
| 			if ( Array.isArray( object ) === true ) { | |
| 
 | |
| 				for ( const child of object ) { | |
| 
 | |
| 					if ( child?.isNode === true ) { | |
| 
 | |
| 						children.push( child ); | |
| 
 | |
| 					} | |
| 
 | |
| 				} | |
| 
 | |
| 			} else if ( object?.isNode === true ) { | |
| 
 | |
| 				children.push( object ); | |
| 
 | |
| 			} | |
| 
 | |
| 		} | |
| 
 | |
| 		return children; | |
| 
 | |
| 	} | |
| 
 | |
| 	getCacheKey() { | |
| 
 | |
| 		return getCacheKey( this ); | |
| 
 | |
| 	} | |
| 
 | |
| 	getHash( /*builder*/ ) { | |
| 
 | |
| 		return this.uuid; | |
| 
 | |
| 	} | |
| 
 | |
| 	getUpdateType( /*builder*/ ) { | |
| 
 | |
| 		return this.updateType; | |
| 
 | |
| 	} | |
| 
 | |
| 	getNodeType( /*builder*/ ) { | |
| 
 | |
| 		return this.nodeType; | |
| 
 | |
| 	} | |
| 
 | |
| 	getConstructHash( /*builder*/ ) { | |
| 
 | |
| 		return this.uuid; | |
| 
 | |
| 	} | |
| 
 | |
| 	getReference( builder ) { | |
| 
 | |
| 		const hash = this.getHash( builder ); | |
| 		const nodeFromHash = builder.getNodeFromHash( hash ); | |
| 
 | |
| 		return nodeFromHash || this; | |
| 
 | |
| 	} | |
| 
 | |
| 	construct( builder ) { | |
| 
 | |
| 		const nodeProperties = builder.getNodeProperties( this ); | |
| 
 | |
| 		for ( const childNode of this.getChildren() ) { | |
| 
 | |
| 			nodeProperties[ '_node' + childNode.id ] = childNode; | |
| 
 | |
| 		} | |
| 
 | |
| 		// return a outputNode if exists | |
| 		return null; | |
| 
 | |
| 	} | |
| 
 | |
| 	analyze( builder ) { | |
| 
 | |
| 		const nodeData = builder.getDataFromNode( this ); | |
| 		nodeData.dependenciesCount = nodeData.dependenciesCount === undefined ? 1 : nodeData.dependenciesCount + 1; | |
| 
 | |
| 		if ( nodeData.dependenciesCount === 1 ) { | |
| 
 | |
| 			// node flow children | |
|  | |
| 			const nodeProperties = builder.getNodeProperties( this ); | |
| 
 | |
| 			for ( const childNode of Object.values( nodeProperties ) ) { | |
| 
 | |
| 				if ( childNode?.isNode === true ) { | |
| 
 | |
| 					childNode.build( builder ); | |
| 
 | |
| 				} | |
| 
 | |
| 			} | |
| 
 | |
| 		} | |
| 
 | |
| 	} | |
| 
 | |
| 	generate( builder, output ) { | |
| 
 | |
| 		const { outputNode } = builder.getNodeProperties( this ); | |
| 
 | |
| 		if ( outputNode?.isNode === true ) { | |
| 
 | |
| 			return outputNode.build( builder, output ); | |
| 
 | |
| 		} | |
| 
 | |
| 	} | |
| 
 | |
| 	update( /*frame*/ ) { | |
| 
 | |
| 		console.warn( 'Abstract function.' ); | |
| 
 | |
| 	} | |
| 
 | |
| 	build( builder, output = null ) { | |
| 
 | |
| 		const refNode = this.getReference( builder ); | |
| 
 | |
| 		if ( this !== refNode ) { | |
| 
 | |
| 			return refNode.build( builder, output ); | |
| 
 | |
| 		} | |
| 
 | |
| 		builder.addNode( this ); | |
| 		builder.addStack( this ); | |
| 
 | |
| 		/* expected return: | |
| 			- "construct"	-> Node | |
| 			- "analyze"		-> null | |
| 			- "generate"	-> String | |
| 		*/ | |
| 		let result = null; | |
| 
 | |
| 		const buildStage = builder.getBuildStage(); | |
| 
 | |
| 		if ( buildStage === 'construct' ) { | |
| 
 | |
| 			const properties = builder.getNodeProperties( this ); | |
| 
 | |
| 			if ( properties.initialized !== true || builder.context.tempRead === false ) { | |
| 
 | |
| 				properties.initialized = true; | |
| 				properties.outputNode = this.construct( builder ); | |
| 
 | |
| 				for ( const childNode of Object.values( properties ) ) { | |
| 
 | |
| 					if ( childNode?.isNode === true ) { | |
| 
 | |
| 						childNode.build( builder ); | |
| 
 | |
| 					} | |
| 
 | |
| 				} | |
| 
 | |
| 			} | |
| 
 | |
| 		} else if ( buildStage === 'analyze' ) { | |
| 
 | |
| 			this.analyze( builder ); | |
| 
 | |
| 		} else if ( buildStage === 'generate' ) { | |
| 
 | |
| 			const isGenerateOnce = this.generate.length === 1; | |
| 
 | |
| 			if ( isGenerateOnce ) { | |
| 
 | |
| 				const type = this.getNodeType( builder ); | |
| 				const nodeData = builder.getDataFromNode( this ); | |
| 
 | |
| 				result = nodeData.snippet; | |
| 
 | |
| 				if ( result === undefined /*|| builder.context.tempRead === false*/ ) { | |
| 
 | |
| 					result = this.generate( builder ) || ''; | |
| 
 | |
| 					nodeData.snippet = result; | |
| 
 | |
| 				} | |
| 
 | |
| 				result = builder.format( result, type, output ); | |
| 
 | |
| 			} else { | |
| 
 | |
| 				result = this.generate( builder, output ) || ''; | |
| 
 | |
| 			} | |
| 
 | |
| 		} | |
| 
 | |
| 		builder.removeStack( this ); | |
| 
 | |
| 		return result; | |
| 
 | |
| 	} | |
| 
 | |
| 	serialize( json ) { | |
| 
 | |
| 		const nodeKeys = getNodesKeys( this ); | |
| 
 | |
| 		if ( nodeKeys.length > 0 ) { | |
| 
 | |
| 			const inputNodes = {}; | |
| 
 | |
| 			for ( const property of nodeKeys ) { | |
| 
 | |
| 				inputNodes[ property ] = this[ property ].toJSON( json.meta ).uuid; | |
| 
 | |
| 			} | |
| 
 | |
| 			json.inputNodes = inputNodes; | |
| 
 | |
| 		} | |
| 
 | |
| 	} | |
| 
 | |
| 	deserialize( json ) { | |
| 
 | |
| 		if ( json.inputNodes !== undefined ) { | |
| 
 | |
| 			const nodes = json.meta.nodes; | |
| 
 | |
| 			for ( const property in json.inputNodes ) { | |
| 
 | |
| 				const uuid = json.inputNodes[ property ]; | |
| 
 | |
| 				this[ property ] = nodes[ uuid ]; | |
| 
 | |
| 			} | |
| 
 | |
| 		} | |
| 
 | |
| 	} | |
| 
 | |
| 	toJSON( meta ) { | |
| 
 | |
| 		const { uuid, type } = this; | |
| 		const isRoot = ( meta === undefined || typeof meta === 'string' ); | |
| 
 | |
| 		if ( isRoot ) { | |
| 
 | |
| 			meta = { | |
| 				textures: {}, | |
| 				images: {}, | |
| 				nodes: {} | |
| 			}; | |
| 
 | |
| 		} | |
| 
 | |
| 		// serialize | |
|  | |
| 		let data = meta.nodes[ uuid ]; | |
| 
 | |
| 		if ( data === undefined ) { | |
| 
 | |
| 			data = { | |
| 				uuid, | |
| 				type, | |
| 				meta, | |
| 				metadata: { | |
| 					version: 4.5, | |
| 					type: 'Node', | |
| 					generator: 'Node.toJSON' | |
| 				} | |
| 			}; | |
| 
 | |
| 			meta.nodes[ data.uuid ] = data; | |
| 
 | |
| 			this.serialize( data ); | |
| 
 | |
| 			delete data.meta; | |
| 
 | |
| 		} | |
| 
 | |
| 		// TODO: Copied from Object3D.toJSON | |
|  | |
| 		function extractFromCache( cache ) { | |
| 
 | |
| 			const values = []; | |
| 
 | |
| 			for ( const key in cache ) { | |
| 
 | |
| 				const data = cache[ key ]; | |
| 				delete data.metadata; | |
| 				values.push( data ); | |
| 
 | |
| 			} | |
| 
 | |
| 			return values; | |
| 
 | |
| 		} | |
| 
 | |
| 		if ( isRoot ) { | |
| 
 | |
| 			const textures = extractFromCache( meta.textures ); | |
| 			const images = extractFromCache( meta.images ); | |
| 			const nodes = extractFromCache( meta.nodes ); | |
| 
 | |
| 			if ( textures.length > 0 ) data.textures = textures; | |
| 			if ( images.length > 0 ) data.images = images; | |
| 			if ( nodes.length > 0 ) data.nodes = nodes; | |
| 
 | |
| 		} | |
| 
 | |
| 		return data; | |
| 
 | |
| 	} | |
| 
 | |
| } | |
| 
 | |
| export default Node;
 | |
| 
 |