text: import * as THREE from '../../build/three.module.js';
  
  import { UIButton, UIInput, UIPanel, UIRow, UISelect, UIText } from './libs/ui.js';
  
  import { SetMaterialCommand } from './commands/SetMaterialCommand.js';
  import { SetMaterialValueCommand } from './commands/SetMaterialValueCommand.js';
  
  import { SidebarMaterialBooleanProperty } from './Sidebar.Material.BooleanProperty.js';
  import { SidebarMaterialColorProperty } from './Sidebar.Material.ColorProperty.js';
  import { SidebarMaterialConstantProperty } from './Sidebar.Material.ConstantProperty.js';
  import { SidebarMaterialMapProperty } from './Sidebar.Material.MapProperty.js';
  import { SidebarMaterialNumberProperty } from './Sidebar.Material.NumberProperty.js';
  import { SidebarMaterialProgram } from './Sidebar.Material.Program.js';
  
  function SidebarMaterial( editor ) {
  
  	const signals = editor.signals;
  	const strings = editor.strings;
  
  	let currentObject;
  
  	let currentMaterialSlot = 0;
  
  	const container = new UIPanel();
  	container.setBorderTop( '0' );
  	container.setDisplay( 'none' );
  	container.setPaddingTop( '20px' );
  
  	// Current material slot
  
  	const materialSlotRow = new UIRow();
  
  	materialSlotRow.add( new UIText( strings.getKey( 'sidebar/material/slot' ) ).setWidth( '90px' ) );
  
  	const materialSlotSelect = new UISelect().setWidth( '170px' ).setFontSize( '12px' ).onChange( update );
  	materialSlotSelect.setOptions( { 0: '' } ).setValue( 0 );
  	materialSlotRow.add( materialSlotSelect );
  
  	container.add( materialSlotRow );
  
  	// type
  
  	const materialClassRow = new UIRow();
  	const materialClass = new UISelect().setWidth( '150px' ).setFontSize( '12px' ).onChange( update );
  
  	materialClassRow.add( new UIText( strings.getKey( 'sidebar/material/type' ) ).setWidth( '90px' ) );
  	materialClassRow.add( materialClass );
  
  	container.add( materialClassRow );
  
  	// uuid
  
  	const materialUUIDRow = new UIRow();
  	const materialUUID = new UIInput().setWidth( '102px' ).setFontSize( '12px' ).setDisabled( true );
  	const materialUUIDRenew = new UIButton( strings.getKey( 'sidebar/material/new' ) ).setMarginLeft( '7px' );
  	materialUUIDRenew.onClick( function () {
  
  		materialUUID.setValue( THREE.MathUtils.generateUUID() );
  		update();
  
  	} );
  
  	materialUUIDRow.add( new UIText( strings.getKey( 'sidebar/material/uuid' ) ).setWidth( '90px' ) );
  	materialUUIDRow.add( materialUUID );
  	materialUUIDRow.add( materialUUIDRenew );
  
  	container.add( materialUUIDRow );
  
  	// name
  
  	const materialNameRow = new UIRow();
  	const materialName = new UIInput().setWidth( '150px' ).setFontSize( '12px' ).onChange( function () {
  
  		editor.execute( new SetMaterialValueCommand( editor, editor.selected, 'name', materialName.getValue(), currentMaterialSlot ) );
  
  	} );
  
  	materialNameRow.add( new UIText( strings.getKey( 'sidebar/material/name' ) ).setWidth( '90px' ) );
  	materialNameRow.add( materialName );
  
  	container.add( materialNameRow );
  
  	// program
  
  	const materialProgram = new SidebarMaterialProgram( editor, 'vertexShader' );
  	container.add( materialProgram );
  
  	// color
  
  	const materialColor = new SidebarMaterialColorProperty( editor, 'color', strings.getKey( 'sidebar/material/color' ) );
  	container.add( materialColor );
  
  	// specular
  
  	const materialSpecular = new SidebarMaterialColorProperty( editor, 'specular', strings.getKey( 'sidebar/material/specular' ) );
  	container.add( materialSpecular );
  
  	// shininess
  
  	const materialShininess = new SidebarMaterialNumberProperty( editor, 'shininess', strings.getKey( 'sidebar/material/shininess' ) );
  	container.add( materialShininess );
  
  	// emissive
  
  	const materialEmissive = new SidebarMaterialColorProperty( editor, 'emissive', strings.getKey( 'sidebar/material/emissive' ) );
  	container.add( materialEmissive );
  
  	// reflectivity
  
  	const materialReflectivity = new SidebarMaterialNumberProperty( editor, 'reflectivity', strings.getKey( 'sidebar/material/reflectivity' ) );
  	container.add( materialReflectivity );
  
  	// roughness
  
  	const materialRoughness = new SidebarMaterialNumberProperty( editor, 'roughness', strings.getKey( 'sidebar/material/roughness' ), [ 0, 1 ] );
  	container.add( materialRoughness );
  
  	// metalness
  
  	const materialMetalness = new SidebarMaterialNumberProperty( editor, 'metalness', strings.getKey( 'sidebar/material/metalness' ), [ 0, 1 ] );
  	container.add( materialMetalness );
  
  	// clearcoat
  
  	const materialClearcoat = new SidebarMaterialNumberProperty( editor, 'clearcoat', strings.getKey( 'sidebar/material/clearcoat' ), [ 0, 1 ] );
  	container.add( materialClearcoat );
  
  	// clearcoatRoughness
  
  	const materialClearcoatRoughness = new SidebarMaterialNumberProperty( editor, 'clearcoatRoughness', strings.getKey( 'sidebar/material/clearcoatroughness' ), [ 0, 1 ] );
  	container.add( materialClearcoatRoughness );
  
  	// transmission
  
  	const materialTransmission = new SidebarMaterialNumberProperty( editor, 'transmission', strings.getKey( 'sidebar/material/transmission' ), [ 0, 1 ] );
  	container.add( materialTransmission );
  
  	// attenuation distance
  
  	const materialAttenuationDistance = new SidebarMaterialNumberProperty( editor, 'attenuationDistance', strings.getKey( 'sidebar/material/attenuationDistance' ) );
  	container.add( materialAttenuationDistance );
  
  	// attenuation tint
  
  	const materialAttenuationColor = new SidebarMaterialColorProperty( editor, 'attenuationColor', strings.getKey( 'sidebar/material/attenuationColor' ) );
  	container.add( materialAttenuationColor );
  
  	// thickness
  
  	const materialThickness = new SidebarMaterialNumberProperty( editor, 'thickness', strings.getKey( 'sidebar/material/thickness' ) );
  	container.add( materialThickness );
  
  	// vertex colors
  
  	const materialVertexColors = new SidebarMaterialBooleanProperty( editor, 'vertexColors', strings.getKey( 'sidebar/material/vertexcolors' ) );
  	container.add( materialVertexColors );
  
  	// depth packing
  
  	const materialDepthPackingOptions = {
  		[ THREE.BasicDepthPacking ]: 'Basic',
  		[ THREE.RGBADepthPacking ]: 'RGBA'
  	};
  
  	const materialDepthPacking = new SidebarMaterialConstantProperty( editor, 'depthPacking', strings.getKey( 'sidebar/material/depthPacking' ), materialDepthPackingOptions );
  	container.add( materialDepthPacking );
  
  	// map
  
  	const materialMap = new SidebarMaterialMapProperty( editor, 'map', strings.getKey( 'sidebar/material/map' ) );
  	container.add( materialMap );
  
  	// specular map
  
  	const materialSpecularMap = new SidebarMaterialMapProperty( editor, 'specularMap', strings.getKey( 'sidebar/material/specularmap' ) );
  	container.add( materialSpecularMap );
  
  	// emissive map
  
  	const materialEmissiveMap = new SidebarMaterialMapProperty( editor, 'emissiveMap', strings.getKey( 'sidebar/material/emissivemap' ) );
  	container.add( materialEmissiveMap );
  
  	// matcap map
  
  	const materialMatcapMap = new SidebarMaterialMapProperty( editor, 'matcap', strings.getKey( 'sidebar/material/matcap' ) );
  	container.add( materialMatcapMap );
  
  	// alpha map
  
  	const materialAlphaMap = new SidebarMaterialMapProperty( editor, 'alphaMap', strings.getKey( 'sidebar/material/alphamap' ) );
  	container.add( materialAlphaMap );
  
  	// bump map
  
  	const materialBumpMap = new SidebarMaterialMapProperty( editor, 'bumpMap', strings.getKey( 'sidebar/material/bumpmap' ) );
  	container.add( materialBumpMap );
  
  	// normal map
  
  	const materialNormalMap = new SidebarMaterialMapProperty( editor, 'normalMap', strings.getKey( 'sidebar/material/normalmap' ) );
  	container.add( materialNormalMap );
  
  	// clearcoat normal map
  
  	const materialClearcoatNormalMap = new SidebarMaterialMapProperty( editor, 'clearcoatNormalMap', strings.getKey( 'sidebar/material/clearcoatnormalmap' ) );
  	container.add( materialClearcoatNormalMap );
  
  	// displacement map
  
  	const materialDisplacementMap = new SidebarMaterialMapProperty( editor, 'displacementMap', strings.getKey( 'sidebar/material/displacementmap' ) );
  	container.add( materialDisplacementMap );
  
  	// roughness map
  
  	const materialRoughnessMap = new SidebarMaterialMapProperty( editor, 'roughnessMap', strings.getKey( 'sidebar/material/roughnessmap' ) );
  	container.add( materialRoughnessMap );
  
  	// metalness map
  
  	const materialMetalnessMap = new SidebarMaterialMapProperty( editor, 'metalnessMap', strings.getKey( 'sidebar/material/metalnessmap' ) );
  	container.add( materialMetalnessMap );
  
  	// env map
  
  	const materialEnvMap = new SidebarMaterialMapProperty( editor, 'envMap', strings.getKey( 'sidebar/material/envmap' ) );
  	container.add( materialEnvMap );
  
  	// light map
  
  	const materialLightMap = new SidebarMaterialMapProperty( editor, 'lightMap', strings.getKey( 'sidebar/material/lightmap' ) );
  	container.add( materialLightMap );
  
  	// ambient occlusion map
  
  	const materialAOMap = new SidebarMaterialMapProperty( editor, 'aoMap', strings.getKey( 'sidebar/material/aomap' ) );
  	container.add( materialAOMap );
  
  	// gradient map
  
  	const materialGradientMap = new SidebarMaterialMapProperty( editor, 'gradientMap', strings.getKey( 'sidebar/material/gradientmap' ) );
  	container.add( materialGradientMap );
  
  	// side
  
  	const materialSideOptions = {
  		0: 'Front',
  		1: 'Back',
  		2: 'Double'
  	};
  
  	const materialSide = new SidebarMaterialConstantProperty( editor, 'side', strings.getKey( 'sidebar/material/side' ), materialSideOptions );
  	container.add( materialSide );
  
  	// size
  
  	const materialSize = new SidebarMaterialNumberProperty( editor, 'size', strings.getKey( 'sidebar/material/size' ), [ 0, Infinity ] );
  	container.add( materialSize );
  
  	// sizeAttenuation
  
  	const materialSizeAttenuation = new SidebarMaterialBooleanProperty( editor, 'sizeAttenuation', strings.getKey( 'sidebar/material/sizeAttenuation' ) );
  	container.add( materialSizeAttenuation );
  
  	// flatShading
  
  	const materialFlatShading = new SidebarMaterialBooleanProperty( editor, 'flatShading', strings.getKey( 'sidebar/material/flatShading' ) );
  	container.add( materialFlatShading );
  
  	// blending
  
  	const materialBlendingOptions = {
  		0: 'No',
  		1: 'Normal',
  		2: 'Additive',
  		3: 'Subtractive',
  		4: 'Multiply',
  		5: 'Custom'
  	};
  
  	const materialBlending = new SidebarMaterialConstantProperty( editor, 'blending', strings.getKey( 'sidebar/material/blending' ), materialBlendingOptions );
  	container.add( materialBlending );
  
  	// opacity
  
  	const materialOpacity = new SidebarMaterialNumberProperty( editor, 'opacity', strings.getKey( 'sidebar/material/opacity' ), [ 0, 1 ] );
  	container.add( materialOpacity );
  
  	// transparent
  
  	const materialTransparent = new SidebarMaterialBooleanProperty( editor, 'transparent', strings.getKey( 'sidebar/material/transparent' ) );
  	container.add( materialTransparent );
  
  	// alpha test
  
  	const materialAlphaTest = new SidebarMaterialNumberProperty( editor, 'alphaTest', strings.getKey( 'sidebar/material/alphatest' ), [ 0, 1 ] );
  	container.add( materialAlphaTest );
  
  	// depth test
  
  	const materialDepthTest = new SidebarMaterialBooleanProperty( editor, 'depthTest', strings.getKey( 'sidebar/material/depthtest' ) );
  	container.add( materialDepthTest );
  
  	// depth write
  
  	const materialDepthWrite = new SidebarMaterialBooleanProperty( editor, 'depthWrite', strings.getKey( 'sidebar/material/depthwrite' ) );
  	container.add( materialDepthWrite );
  
  	// wireframe
  
  	const materialWireframe = new SidebarMaterialBooleanProperty( editor, 'wireframe', strings.getKey( 'sidebar/material/wireframe' ) );
  	container.add( materialWireframe );
  
  	//
  
  	function update() {
  
  		const previousSelectedSlot = currentMaterialSlot;
  
  		currentMaterialSlot = parseInt( materialSlotSelect.getValue() );
  
  		if ( currentMaterialSlot !== previousSelectedSlot ) refreshUI();
  
  		let material = editor.getObjectMaterial( currentObject, currentMaterialSlot );
  
  		if ( material ) {
  
  			if ( material.uuid !== undefined && material.uuid !== materialUUID.getValue() ) {
  
  				editor.execute( new SetMaterialValueCommand( editor, currentObject, 'uuid', materialUUID.getValue(), currentMaterialSlot ) );
  
  			}
  
  			if ( material.type !== materialClass.getValue() ) {
  
  				material = new materialClasses[ materialClass.getValue() ]();
  
  				if ( material.type === 'RawShaderMaterial' ) {
  
  					material.vertexShader = vertexShaderVariables + material.vertexShader;
  
  				}
  
  				if ( Array.isArray( currentObject.material ) ) {
  
  					// don't remove the entire multi-material. just the material of the selected slot
  
  					editor.removeMaterial( currentObject.material[ currentMaterialSlot ] );
  
  				} else {
  
  					editor.removeMaterial( currentObject.material );
  
  				}
  
  				editor.execute( new SetMaterialCommand( editor, currentObject, material, currentMaterialSlot ), 'New Material: ' + materialClass.getValue() );
  				editor.addMaterial( material );
  				// TODO Copy other references in the scene graph
  				// keeping name and UUID then.
  				// Also there should be means to create a unique
  				// copy for the current object explicitly and to
  				// attach the current material to other objects.
  
  			}
  
  			refreshUI();
  
  		}
  
  	}
  
  	//
  
  	function setRowVisibility() {
  
  		const material = currentObject.material;
  
  		if ( Array.isArray( material ) ) {
  
  			materialSlotRow.setDisplay( '' );
  
  		} else {
  
  			materialSlotRow.setDisplay( 'none' );
  
  		}
  
  	}
  
  	function refreshUI() {
  
  		if ( ! currentObject ) return;
  
  		let material = currentObject.material;
  
  		if ( Array.isArray( material ) ) {
  
  			const slotOptions = {};
  
  			currentMaterialSlot = Math.max( 0, Math.min( material.length, currentMaterialSlot ) );
  
  			for ( let i = 0; i < material.length; i ++ ) {
  
  				slotOptions[ i ] = String( i + 1 ) + ': ' + material[ i ].name;
  
  			}
  
  			materialSlotSelect.setOptions( slotOptions ).setValue( currentMaterialSlot );
  
  		}
  
  		material = editor.getObjectMaterial( currentObject, currentMaterialSlot );
  
  		if ( material.uuid !== undefined ) {
  
  			materialUUID.setValue( material.uuid );
  
  		}
  
  		if ( material.name !== undefined ) {
  
  			materialName.setValue( material.name );
  
  		}
  
  		if ( currentObject.isMesh ) {
  
  			materialClass.setOptions( meshMaterialOptions );
  
  		} else if ( currentObject.isSprite ) {
  
  			materialClass.setOptions( spriteMaterialOptions );
  
  		} else if ( currentObject.isPoints ) {
  
  			materialClass.setOptions( pointsMaterialOptions );
  
  		} else if ( currentObject.isLine ) {
  
  			materialClass.setOptions( lineMaterialOptions );
  
  		}
  
  		materialClass.setValue( material.type );
  
  		setRowVisibility();
  
  	}
  
  	// events
  
  	signals.objectSelected.add( function ( object ) {
  
  		let hasMaterial = false;
  
  		if ( object && object.material ) {
  
  			hasMaterial = true;
  
  			if ( Array.isArray( object.material ) && object.material.length === 0 ) {
  
  				hasMaterial = false;
  
  			}
  
  		}
  
  		if ( hasMaterial ) {
  
  			currentObject = object;
  			refreshUI();
  			container.setDisplay( '' );
  
  		} else {
  
  			currentObject = null;
  			container.setDisplay( 'none' );
  
  		}
  
  	} );
  
  	signals.materialChanged.add( refreshUI );
  
  	return container;
  
  }
  
  const materialClasses = {
  	'LineBasicMaterial': THREE.LineBasicMaterial,
  	'LineDashedMaterial': THREE.LineDashedMaterial,
  	'MeshBasicMaterial': THREE.MeshBasicMaterial,
  	'MeshDepthMaterial': THREE.MeshDepthMaterial,
  	'MeshNormalMaterial': THREE.MeshNormalMaterial,
  	'MeshLambertMaterial': THREE.MeshLambertMaterial,
  	'MeshMatcapMaterial': THREE.MeshMatcapMaterial,
  	'MeshPhongMaterial': THREE.MeshPhongMaterial,
  	'MeshToonMaterial': THREE.MeshToonMaterial,
  	'MeshStandardMaterial': THREE.MeshStandardMaterial,
  	'MeshPhysicalMaterial': THREE.MeshPhysicalMaterial,
  	'RawShaderMaterial': THREE.RawShaderMaterial,
  	'ShaderMaterial': THREE.ShaderMaterial,
  	'ShadowMaterial': THREE.ShadowMaterial,
  	'SpriteMaterial': THREE.SpriteMaterial,
  	'PointsMaterial': THREE.PointsMaterial
  };
  
  const vertexShaderVariables = [
  	'uniform mat4 projectionMatrix;',
  	'uniform mat4 modelViewMatrix;\n',
  	'attribute vec3 position;\n\n',
  ].join( '\n' );
  
  const meshMaterialOptions = {
  	'MeshBasicMaterial': 'MeshBasicMaterial',
  	'MeshDepthMaterial': 'MeshDepthMaterial',
  	'MeshNormalMaterial': 'MeshNormalMaterial',
  	'MeshLambertMaterial': 'MeshLambertMaterial',
  	'MeshMatcapMaterial': 'MeshMatcapMaterial',
  	'MeshPhongMaterial': 'MeshPhongMaterial',
  	'MeshToonMaterial': 'MeshToonMaterial',
  	'MeshStandardMaterial': 'MeshStandardMaterial',
  	'MeshPhysicalMaterial': 'MeshPhysicalMaterial',
  	'RawShaderMaterial': 'RawShaderMaterial',
  	'ShaderMaterial': 'ShaderMaterial',
  	'ShadowMaterial': 'ShadowMaterial'
  };
  
  const lineMaterialOptions = {
  	'LineBasicMaterial': 'LineBasicMaterial',
  	'LineDashedMaterial': 'LineDashedMaterial',
  	'RawShaderMaterial': 'RawShaderMaterial',
  	'ShaderMaterial': 'ShaderMaterial'
  };
  
  const spriteMaterialOptions = {
  	'SpriteMaterial': 'SpriteMaterial',
  	'RawShaderMaterial': 'RawShaderMaterial',
  	'ShaderMaterial': 'ShaderMaterial'
  };
  
  const pointsMaterialOptions = {
  	'PointsMaterial': 'PointsMaterial',
  	'RawShaderMaterial': 'RawShaderMaterial',
  	'ShaderMaterial': 'ShaderMaterial'
  };
  
  export { SidebarMaterial };
  