| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 | 
							- import { Canvas, CircleMenu, ButtonInput, ContextMenu, Loader } from '../libs/flow.module.js';
 
- import { StandardMaterialEditor } from './materials/StandardMaterialEditor.js';
 
- import { OperatorEditor } from './math/OperatorEditor.js';
 
- import { NormalizeEditor } from './math/NormalizeEditor.js';
 
- import { InvertEditor } from './math/InvertEditor.js';
 
- import { LimiterEditor } from './math/LimiterEditor.js';
 
- import { DotEditor } from './math/DotEditor.js';
 
- import { PowerEditor } from './math/PowerEditor.js';
 
- import { TrigonometryEditor } from './math/TrigonometryEditor.js';
 
- import { FloatEditor } from './inputs/FloatEditor.js';
 
- import { Vector2Editor } from './inputs/Vector2Editor.js';
 
- import { Vector3Editor } from './inputs/Vector3Editor.js';
 
- import { Vector4Editor } from './inputs/Vector4Editor.js';
 
- import { SliderEditor } from './inputs/SliderEditor.js';
 
- import { ColorEditor } from './inputs/ColorEditor.js';
 
- import { BlendEditor } from './display/BlendEditor.js';
 
- import { UVEditor } from './accessors/UVEditor.js';
 
- import { PositionEditor } from './accessors/PositionEditor.js';
 
- import { NormalEditor } from './accessors/NormalEditor.js';
 
- import { TimerEditor } from './utils/TimerEditor.js';
 
- import { OscillatorEditor } from './utils/OscillatorEditor.js';
 
- import { CheckerEditor } from './procedural/CheckerEditor.js';
 
- import { EventDispatcher } from 'three';
 
- export const ClassLib = {
 
- 	'StandardMaterialEditor': StandardMaterialEditor,
 
- 	'OperatorEditor': OperatorEditor,
 
- 	'NormalizeEditor': NormalizeEditor,
 
- 	'InvertEditor': InvertEditor,
 
- 	'LimiterEditor': LimiterEditor,
 
- 	'DotEditor': DotEditor,
 
- 	'PowerEditor': PowerEditor,
 
- 	'TrigonometryEditor': TrigonometryEditor,
 
- 	'FloatEditor': FloatEditor,
 
- 	'Vector2Editor': Vector2Editor,
 
- 	'Vector3Editor': Vector3Editor,
 
- 	'Vector4Editor': Vector4Editor,
 
- 	'SliderEditor': SliderEditor,
 
- 	'ColorEditor': ColorEditor,
 
- 	'BlendEditor': BlendEditor,
 
- 	'UVEditor': UVEditor,
 
- 	'PositionEditor': PositionEditor,
 
- 	'NormalEditor': NormalEditor,
 
- 	'TimerEditor': TimerEditor,
 
- 	'OscillatorEditor': OscillatorEditor,
 
- 	'CheckerEditor': CheckerEditor
 
- };
 
- export class NodeEditor extends EventDispatcher {
 
- 	constructor() {
 
- 		super();
 
- 		const domElement = document.createElement( 'flow' );
 
- 		const canvas = new Canvas();
 
- 		domElement.appendChild( canvas.dom );
 
- 		this.canvas = canvas;
 
- 		this.domElement = domElement;
 
- 		this.nodesContext = null;
 
- 		this.examplesContext = null;
 
- 		this._initMenu();
 
- 		this._initNodesContext();
 
- 		this._initExamplesContext();
 
- 	}
 
- 	add( node ) {
 
- 		this.canvas.add( node );
 
- 		return this;
 
- 	}
 
- 	get nodes() {
 
- 		return this.canvas.nodes;
 
- 	}
 
- 	newProject() {
 
- 		this.canvas.clear();
 
- 		this.dispatchEvent( { type: 'new' } );
 
- 	}
 
- 	loadJSON( json ) {
 
- 		this.canvas.clear();
 
- 		this.canvas.deserialize( json );
 
- 		this.dispatchEvent( { type: 'load' } );
 
- 	}
 
- 	_initMenu() {
 
- 		const menu = new CircleMenu();
 
- 		const menuButton = new ButtonInput().setIcon( 'ti ti-menu-2' );
 
- 		const examplesButton = new ButtonInput().setIcon( 'ti ti-file-symlink' ).setToolTip( 'Examples' );
 
- 		const newButton = new ButtonInput().setIcon( 'ti ti-file' ).setToolTip( 'New' );
 
- 		const openButton = new ButtonInput().setIcon( 'ti ti-upload' ).setToolTip( 'Open' );
 
- 		const saveButton = new ButtonInput().setIcon( 'ti ti-download' ).setToolTip( 'Save' );
 
- 		const hideContext = () => {
 
- 			this.examplesContext.hide();
 
- 			this.nodesContext.hide();
 
- 		};
 
- 		menuButton.onClick( () => {
 
- 			this.nodesContext.show( 60, 50 );
 
- 		} );
 
- 		examplesButton.onClick( () => {
 
- 			this.examplesContext.show( 60, 175 );
 
- 		} );
 
- 		newButton.onClick( () => {
 
- 			hideContext();
 
- 			this.newProject();
 
- 		} );
 
- 		openButton.onClick( () => {
 
- 			hideContext();
 
- 			const input = document.createElement( 'input' );
 
- 			input.type = 'file';
 
- 			input.onchange = e => {
 
- 				const file = e.target.files[ 0 ];
 
- 				const reader = new FileReader();
 
- 				reader.readAsText( file, 'UTF-8' );
 
- 				reader.onload = readerEvent => {
 
- 					const loader = new Loader( Loader.OBJECTS );
 
- 					const json = loader.parse( JSON.parse( readerEvent.target.result ), ClassLib );
 
- 					this.loadJSON( json );
 
- 				};
 
- 			};
 
- 			input.click();
 
- 		} );
 
- 		saveButton.onClick( () => {
 
- 			hideContext();
 
- 			const json = JSON.stringify( this.canvas.toJSON() );
 
- 			const a = document.createElement( 'a' );
 
- 			const file = new Blob( [ json ], { type: 'text/plain' } );
 
- 			a.href = URL.createObjectURL( file );
 
- 			a.download = 'node_editor.json';
 
- 			a.click();
 
- 		} );
 
- 		menu.add( menuButton )
 
- 			.add( newButton )
 
- 			.add( examplesButton )
 
- 			.add( openButton )
 
- 			.add( saveButton );
 
- 		this.domElement.appendChild( menu.dom );
 
- 		this.menu = menu;
 
- 	}
 
- 	_initExamplesContext() {
 
- 		const context = new ContextMenu();
 
- 		//**************//
 
- 		// MAIN
 
- 		//**************//
 
- 		const onClickExample = async ( button ) => {
 
- 			this.examplesContext.hide();
 
- 			const filename = button.getExtra();
 
- 			const loader = new Loader( Loader.OBJECTS );
 
- 			const json = await loader.load( `./jsm/node-editor/examples/${filename}.json`, ClassLib );
 
- 			this.loadJSON( json );
 
- 		};
 
- 		const addExample = ( context, name, filename = null ) => {
 
- 			filename = filename || name.replaceAll( ' ', '-' ).toLowerCase();
 
- 			context.add( new ButtonInput( name )
 
- 				.setIcon( 'ti ti-file-symlink' )
 
- 				.onClick( onClickExample )
 
- 				.setExtra( filename )
 
- 			);
 
- 		};
 
- 		//**************//
 
- 		// EXAMPLES
 
- 		//**************//
 
- 		const basicContext = new ContextMenu();
 
- 		const advancedContext = new ContextMenu();
 
- 		addExample( basicContext, 'Animate UV' );
 
- 		addExample( basicContext, 'Fake top light' );
 
- 		addExample( basicContext, 'Oscillator color' );
 
- 		addExample( advancedContext, 'Rim' );
 
- 		//**************//
 
- 		// MAIN
 
- 		//**************//
 
- 		context.add( new ButtonInput( 'Basic' ), basicContext );
 
- 		context.add( new ButtonInput( 'Advanced' ), advancedContext );
 
- 		this.domElement.appendChild( context.dom );
 
- 		this.examplesContext = context;
 
- 	}
 
- 	_initNodesContext() {
 
- 		const context = new ContextMenu( this.domElement );
 
- 		let isContext = false;
 
- 		let contextPosition = {};
 
- 		const add = ( node ) => {
 
- 			const canvas = this.canvas;
 
- 			const canvasRect = canvas.rect;
 
- 			if ( isContext ) {
 
- 				node.setPosition(
 
- 					contextPosition.x,
 
- 					contextPosition.y
 
- 				);
 
- 			} else {
 
- 				const defaultOffsetX = 350 / 2;
 
- 				const defaultOffsetY = 20;
 
- 				node.setPosition(
 
- 					( canvas.relativeX + ( canvasRect.width / 2 ) ) - defaultOffsetX,
 
- 					( canvas.relativeY + ( canvasRect.height / 2 ) ) - defaultOffsetY
 
- 				);
 
- 			}
 
- 			context.hide();
 
- 			this.add( node );
 
- 			this.canvas.select( node );
 
- 			isContext = false;
 
- 		};
 
- 		context.onContext( () => {
 
- 			isContext = true;
 
- 			const { relativeClientX, relativeClientY } = this.canvas;
 
- 			contextPosition.x = relativeClientX;
 
- 			contextPosition.y = relativeClientY;
 
- 		} );
 
- 		//**************//
 
- 		// INPUTS
 
- 		//**************//
 
- 		const inputsContext = new ContextMenu();
 
- 		const sliderInput = new ButtonInput( 'Slider' ).setIcon( 'ti ti-adjustments-horizontal' )
 
- 			.onClick( () => add( new SliderEditor() ) );
 
- 		const floatInput = new ButtonInput( 'Float' ).setIcon( 'ti ti-box-multiple-1' )
 
- 			.onClick( () => add( new FloatEditor() ) );
 
- 		const vector2Input = new ButtonInput( 'Vector 2' ).setIcon( 'ti ti-box-multiple-2' )
 
- 			.onClick( () => add( new Vector2Editor() ) );
 
- 		const vector3Input = new ButtonInput( 'Vector 3' ).setIcon( 'ti ti-box-multiple-3' )
 
- 			.onClick( () => add( new Vector3Editor() ) );
 
- 		const vector4Input = new ButtonInput( 'Vector 4' ).setIcon( 'ti ti-box-multiple-4' )
 
- 			.onClick( () => add( new Vector4Editor() ) );
 
- 		const colorInput = new ButtonInput( 'Color' ).setIcon( 'ti ti-palette' )
 
- 			.onClick( () => add( new ColorEditor() ) );
 
- 		//const mapInput = new ButtonInput( 'Map' ).setIcon( 'ti ti-photo' );
 
- 		//const cubeMapInput = new ButtonInput( 'Cube Map' ).setIcon( 'ti ti-box' );
 
- 		//const integerInput = new ButtonInput( 'Integer' ).setIcon( 'ti ti-list-numbers' );
 
- 		inputsContext
 
- 			.add( sliderInput )
 
- 			.add( floatInput )
 
- 			.add( vector2Input )
 
- 			.add( vector3Input )
 
- 			.add( vector4Input )
 
- 			.add( colorInput );
 
- 		//**************//
 
- 		// MATH
 
- 		//**************//
 
- 		const mathContext = new ContextMenu();
 
- 		const operatorsNode = new ButtonInput( 'Operator' ).setIcon( 'ti ti-math-symbols' )
 
- 			.onClick( () => add( new OperatorEditor() ) );
 
- 		const normalizeNode = new ButtonInput( 'Normalize' ).setIcon( 'ti ti-fold' )
 
- 			.onClick( () => add( new NormalizeEditor() ) );
 
- 		const invertNode = new ButtonInput( 'Invert' ).setToolTip( 'Negate' ).setIcon( 'ti ti-flip-vertical' )
 
- 			.onClick( () => add( new InvertEditor() ) );
 
- 		const limiterNode = new ButtonInput( 'Limiter' ).setToolTip( 'Min / Max' ).setIcon( 'ti ti-arrow-bar-to-up' )
 
- 			.onClick( () => add( new LimiterEditor() ) );
 
- 		const dotNode = new ButtonInput( 'Dot Product' ).setIcon( 'ti ti-arrows-up-left' )
 
- 			.onClick( () => add( new DotEditor() ) );
 
- 		const powNode = new ButtonInput( 'Power' ).setIcon( 'ti ti-arrow-up-right' )
 
- 			.onClick( () => add( new PowerEditor() ) );
 
- 		const triNode = new ButtonInput( 'Trigonometry' ).setToolTip( 'Sin / Cos / Tan' ).setIcon( 'ti ti-wave-sine' )
 
- 			.onClick( () => add( new TrigonometryEditor() ) );
 
- 		mathContext
 
- 			.add( operatorsNode )
 
- 			.add( invertNode )
 
- 			.add( limiterNode )
 
- 			.add( dotNode )
 
- 			.add( powNode )
 
- 			.add( triNode )
 
- 			.add( normalizeNode );
 
- 		//**************//
 
- 		// ACCESSORS
 
- 		//**************//
 
- 		const accessorsContext = new ContextMenu();
 
- 		const uvNode = new ButtonInput( 'UV' ).setIcon( 'ti ti-details' )
 
- 			.onClick( () => add( new UVEditor() ) );
 
- 		const positionNode = new ButtonInput( 'Position' ).setIcon( 'ti ti-hierarchy' )
 
- 			.onClick( () => add( new PositionEditor() ) );
 
- 		const normalNode = new ButtonInput( 'Normal' ).setIcon( 'ti ti-fold-up' )
 
- 			.onClick( () => add( new NormalEditor() ) );
 
- 		accessorsContext
 
- 			.add( uvNode )
 
- 			.add( positionNode )
 
- 			.add( normalNode );
 
- 		//**************//
 
- 		// PROCEDURAL
 
- 		//**************//
 
- 		const proceduralContext = new ContextMenu();
 
- 		const checkerNode = new ButtonInput( 'Checker' ).setIcon( 'ti ti-border-outer' )
 
- 			.onClick( () => add( new CheckerEditor() ) );
 
- 		proceduralContext
 
- 			.add( checkerNode );
 
- 		//**************//
 
- 		// DISPLAY
 
- 		//**************//
 
- 		const displayContext = new ContextMenu();
 
- 		const blendNode = new ButtonInput( 'Blend' ).setIcon( 'ti ti-layers-subtract' )
 
- 			.onClick( () => add( new BlendEditor() ) );
 
- 		displayContext
 
- 			.add( blendNode );
 
- 		//**************//
 
- 		// UTILS
 
- 		//**************//
 
- 		const utilsContext = new ContextMenu();
 
- 		const timerNode = new ButtonInput( 'Timer' ).setIcon( 'ti ti-clock' )
 
- 			.onClick( () => add( new TimerEditor() ) );
 
- 		const oscNode = new ButtonInput( 'Oscillator' ).setIcon( 'ti ti-wave-sine' )
 
- 			.onClick( () => add( new OscillatorEditor() ) );
 
- 		utilsContext
 
- 			.add( timerNode )
 
- 			.add( oscNode );
 
- 		//**************//
 
- 		// MAIN
 
- 		//**************//
 
- 		context.add( new ButtonInput( 'Inputs' ).setIcon( 'ti ti-forms' ), inputsContext );
 
- 		context.add( new ButtonInput( 'Accessors' ).setIcon( 'ti ti-vector-triangle' ), accessorsContext );
 
- 		context.add( new ButtonInput( 'Display' ).setIcon( 'ti ti-brightness' ), displayContext );
 
- 		context.add( new ButtonInput( 'Math' ).setIcon( 'ti ti-calculator' ), mathContext );
 
- 		context.add( new ButtonInput( 'Procedural' ).setIcon( 'ti ti-infinity' ), proceduralContext );
 
- 		context.add( new ButtonInput( 'Utils' ).setIcon( 'ti ti-apps' ), utilsContext );
 
- 		this.nodesContext = context;
 
- 	}
 
- }
 
 
  |