import { Loader, FileLoader } from 'three'; import * as Nodes from '../nodes/Nodes.js'; class NodeMaterialLoader extends Loader { constructor( manager, library = {} ) { super( manager ); this.nodes = {}; this.materials = {}; this.passes = {}; this.names = {}; this.library = library; } load( url, onLoad, onProgress, onError ) { const scope = this; const loader = new FileLoader( scope.manager ); loader.setPath( scope.path ); loader.load( url, function ( text ) { onLoad( scope.parse( JSON.parse( text ) ) ); }, onProgress, onError ); return this; } getObjectByName( uuid ) { return this.names[ uuid ]; } getObjectById( uuid ) { return this.library[ uuid ] || this.nodes[ uuid ] || this.materials[ uuid ] || this.passes[ uuid ] || this.names[ uuid ]; } getNode( uuid ) { const object = this.getObjectById( uuid ); if ( ! object ) { console.warn( 'Node "' + uuid + '" not found.' ); } return object; } resolve( json ) { switch ( typeof json ) { case 'boolean': case 'number': return json; case 'string': if ( /^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$/i.test( json ) || this.library[ json ] ) { return this.getNode( json ); } return json; default: if ( Array.isArray( json ) ) { for ( let i = 0; i < json.length; i ++ ) { json[ i ] = this.resolve( json[ i ] ); } } else { for ( const prop in json ) { if ( prop === 'uuid' ) continue; json[ prop ] = this.resolve( json[ prop ] ); } } } return json; } declare( json ) { let uuid, node, object; for ( uuid in json.nodes ) { node = json.nodes[ uuid ]; object = new Nodes[ node.nodeType + 'Node' ](); if ( node.name ) { object.name = node.name; this.names[ object.name ] = object; } this.nodes[ uuid ] = object; } for ( uuid in json.materials ) { node = json.materials[ uuid ]; object = new Nodes[ node.type ](); if ( node.name ) { object.name = node.name; this.names[ object.name ] = object; } this.materials[ uuid ] = object; } for ( uuid in json.passes ) { node = json.passes[ uuid ]; object = new Nodes[ node.type ](); if ( node.name ) { object.name = node.name; this.names[ object.name ] = object; } this.passes[ uuid ] = object; } if ( json.material ) this.material = this.materials[ json.material ]; if ( json.pass ) this.pass = this.passes[ json.pass ]; return json; } parse( json ) { let uuid; json = this.resolve( this.declare( json ) ); for ( uuid in json.nodes ) { this.nodes[ uuid ].copy( json.nodes[ uuid ] ); } for ( uuid in json.materials ) { this.materials[ uuid ].copy( json.materials[ uuid ] ); } for ( uuid in json.passes ) { this.passes[ uuid ].copy( json.passes[ uuid ] ); } return this.material || this.pass || this; } } class NodeMaterialLoaderUtils { static replaceUUIDObject( object, uuid, value, recursive ) { recursive = recursive !== undefined ? recursive : true; if ( typeof uuid === 'object' ) uuid = uuid.uuid; if ( typeof object === 'object' ) { const keys = Object.keys( object ); for ( let i = 0; i < keys.length; i ++ ) { const key = keys[ i ]; if ( recursive ) { object[ key ] = this.replaceUUIDObject( object[ key ], uuid, value ); } if ( key === uuid ) { object[ uuid ] = object[ key ]; delete object[ key ]; } } } return object === uuid ? value : object; } static replaceUUID( json, uuid, value ) { this.replaceUUIDObject( json, uuid, value, false ); this.replaceUUIDObject( json.nodes, uuid, value ); this.replaceUUIDObject( json.materials, uuid, value ); this.replaceUUIDObject( json.passes, uuid, value ); this.replaceUUIDObject( json.library, uuid, value, false ); return json; } } export { NodeMaterialLoader, NodeMaterialLoaderUtils };