|
@@ -0,0 +1,246 @@
|
|
|
+import { Canvas, CircleMenu, ButtonInput, ContextMenu, Loader } from '../libs/flow.module.js';
|
|
|
+import { StandardMaterialEditor } from './materials/StandardMaterialEditor.js';
|
|
|
+import { OperatorEditor } from './math/OperatorEditor.js';
|
|
|
+import { FloatEditor } from './inputs/FloatEditor.js';
|
|
|
+import { ColorEditor } from './inputs/ColorEditor.js';
|
|
|
+import { UVEditor } from './accessors/UVEditor.js';
|
|
|
+import { PositionEditor } from './accessors/PositionEditor.js';
|
|
|
+import { NormalEditor } from './accessors/NormalEditor.js';
|
|
|
+import { CheckerEditor } from './procedural/CheckerEditor.js';
|
|
|
+import { EventDispatcher } from 'three';
|
|
|
+
|
|
|
+export const ClassLib = {
|
|
|
+ 'StandardMaterialEditor': StandardMaterialEditor,
|
|
|
+ 'OperatorEditor': OperatorEditor,
|
|
|
+ 'FloatEditor': FloatEditor,
|
|
|
+ 'ColorEditor': ColorEditor,
|
|
|
+ 'UVEditor': UVEditor,
|
|
|
+ 'PositionEditor': PositionEditor,
|
|
|
+ 'NormalEditor': NormalEditor,
|
|
|
+ '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._initMenu();
|
|
|
+ this._initContextMenu();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ add( node ) {
|
|
|
+
|
|
|
+ this.canvas.add( node );
|
|
|
+
|
|
|
+ return this;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ get nodes() {
|
|
|
+
|
|
|
+ return this.canvas.nodes;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ _initMenu() {
|
|
|
+
|
|
|
+ const menu = new CircleMenu();
|
|
|
+
|
|
|
+ const menuButton = new ButtonInput().setIcon( 'ti ti-menu-2' );
|
|
|
+ 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' );
|
|
|
+
|
|
|
+ menuButton.onClick( () => {
|
|
|
+
|
|
|
+ this.context.show( 50, 50 );
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ newButton.onClick( () => {
|
|
|
+
|
|
|
+ this.canvas.clear();
|
|
|
+
|
|
|
+ this.dispatchEvent( { type: 'new' } );
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ openButton.onClick( () => {
|
|
|
+
|
|
|
+ this.context.hide();
|
|
|
+
|
|
|
+ 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 json = Loader.parseObjects( JSON.parse( readerEvent.target.result ), ClassLib );
|
|
|
+
|
|
|
+ this.canvas.clear();
|
|
|
+
|
|
|
+ this.canvas.deserialize( json );
|
|
|
+
|
|
|
+ this.dispatchEvent( { type: 'load' } );
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ input.click();
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ saveButton.onClick( () => {
|
|
|
+
|
|
|
+ this.context.hide();
|
|
|
+
|
|
|
+ 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 );
|
|
|
+ menu.add( newButton );
|
|
|
+ menu.add( openButton );
|
|
|
+ menu.add( saveButton );
|
|
|
+
|
|
|
+ this.domElement.appendChild( menu.dom );
|
|
|
+
|
|
|
+ this.menu = menu;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ _initContextMenu() {
|
|
|
+
|
|
|
+ const context = new ContextMenu( this.domElement );
|
|
|
+
|
|
|
+ const add = ( node ) => {
|
|
|
+
|
|
|
+ const canvas = this.canvas;
|
|
|
+ const canvasRect = canvas.rect;
|
|
|
+
|
|
|
+ node.setPosition(
|
|
|
+ ( canvas.relativeX + ( canvasRect.width / 2 ) ) - ( 350 / 2 ),
|
|
|
+ ( canvas.relativeY + ( canvasRect.height / 2 ) ) - 20
|
|
|
+ );
|
|
|
+
|
|
|
+ context.hide();
|
|
|
+
|
|
|
+ this.add( node );
|
|
|
+
|
|
|
+ this.canvas.select( node );
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ //**************//
|
|
|
+ //* INPUTS
|
|
|
+ //**************//
|
|
|
+
|
|
|
+ const inputsContext = new ContextMenu();
|
|
|
+
|
|
|
+ const floatInput = new ButtonInput( 'Float' ).setIcon( 'ti ti-box-multiple-1' )
|
|
|
+ .onClick( () => add( new FloatEditor() ) );
|
|
|
+
|
|
|
+ //const vec2Input = new ButtonInput( 'Vector 2' ).setIcon( 'ti ti-box-multiple-2' );
|
|
|
+ //const vec3Input = new ButtonInput( 'Vector 3' ).setIcon( 'ti ti-box-multiple-3' );
|
|
|
+ //const vec4Input = new ButtonInput( 'Vector 4' ).setIcon( 'ti ti-box-multiple-4' );
|
|
|
+
|
|
|
+ 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 sliderInput = new ButtonInput( 'Slider' ).setIcon( 'ti ti-adjustments-horizontal' );
|
|
|
+ //const integerInput = new ButtonInput( 'Integer' ).setIcon( 'ti ti-list-numbers' );
|
|
|
+
|
|
|
+ inputsContext
|
|
|
+ .add( floatInput )
|
|
|
+ //.add( vec2Input )
|
|
|
+ //.add( vec3Input )
|
|
|
+ //.add( vec4Input )
|
|
|
+ .add( colorInput );
|
|
|
+ //.add( sliderInput );
|
|
|
+
|
|
|
+ //**************//
|
|
|
+ //* MATH
|
|
|
+ //**************//
|
|
|
+
|
|
|
+ const mathContext = new ContextMenu();
|
|
|
+ const operatorsNode = new ButtonInput( 'Operators' ).setIcon( 'ti ti-math-symbols' )
|
|
|
+ .onClick( () => add( new OperatorEditor() ) );
|
|
|
+
|
|
|
+ mathContext
|
|
|
+ .add( operatorsNode );
|
|
|
+
|
|
|
+ //**************//
|
|
|
+ //* 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 );
|
|
|
+
|
|
|
+ //**************//
|
|
|
+ //* 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( 'Math' ).setIcon( 'ti ti-calculator' ), mathContext );
|
|
|
+ context.add( new ButtonInput( 'Procedural' ).setIcon( 'ti ti-infinity' ), proceduralContext );
|
|
|
+
|
|
|
+ this.domElement.appendChild( context.dom );
|
|
|
+
|
|
|
+ this.context = context;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|