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.

849 lines
23 KiB

2 years ago
import * as THREE from 'three';
import { UIPanel, UIRow, UIInput, UIButton, UIColor, UICheckbox, UIInteger, UITextArea, UIText, UINumber } from './libs/ui.js';
import { UIBoolean } from './libs/ui.three.js';
import { SetUuidCommand } from './commands/SetUuidCommand.js';
import { SetValueCommand } from './commands/SetValueCommand.js';
import { SetPositionCommand } from './commands/SetPositionCommand.js';
import { SetRotationCommand } from './commands/SetRotationCommand.js';
import { SetScaleCommand } from './commands/SetScaleCommand.js';
import { SetColorCommand } from './commands/SetColorCommand.js';
function SidebarObject( editor ) {
const strings = editor.strings;
const signals = editor.signals;
const container = new UIPanel();
container.setBorderTop( '0' );
container.setPaddingTop( '20px' );
container.setDisplay( 'none' );
// Actions
/*
let objectActions = new UI.Select().setPosition( 'absolute' ).setRight( '8px' ).setFontSize( '11px' );
objectActions.setOptions( {
'Actions': 'Actions',
'Reset Position': 'Reset Position',
'Reset Rotation': 'Reset Rotation',
'Reset Scale': 'Reset Scale'
} );
objectActions.onClick( function ( event ) {
event.stopPropagation(); // Avoid panel collapsing
} );
objectActions.onChange( function ( event ) {
let object = editor.selected;
switch ( this.getValue() ) {
case 'Reset Position':
editor.execute( new SetPositionCommand( editor, object, new Vector3( 0, 0, 0 ) ) );
break;
case 'Reset Rotation':
editor.execute( new SetRotationCommand( editor, object, new Euler( 0, 0, 0 ) ) );
break;
case 'Reset Scale':
editor.execute( new SetScaleCommand( editor, object, new Vector3( 1, 1, 1 ) ) );
break;
}
this.setValue( 'Actions' );
} );
container.addStatic( objectActions );
*/
// type
const objectTypeRow = new UIRow();
const objectType = new UIText();
objectTypeRow.add( new UIText( strings.getKey( 'sidebar/object/type' ) ).setWidth( '90px' ) );
objectTypeRow.add( objectType );
container.add( objectTypeRow );
// uuid
const objectUUIDRow = new UIRow();
const objectUUID = new UIInput().setWidth( '102px' ).setFontSize( '12px' ).setDisabled( true );
const objectUUIDRenew = new UIButton( strings.getKey( 'sidebar/object/new' ) ).setMarginLeft( '7px' ).onClick( function () {
objectUUID.setValue( THREE.MathUtils.generateUUID() );
editor.execute( new SetUuidCommand( editor, editor.selected, objectUUID.getValue() ) );
} );
objectUUIDRow.add( new UIText( strings.getKey( 'sidebar/object/uuid' ) ).setWidth( '90px' ) );
objectUUIDRow.add( objectUUID );
objectUUIDRow.add( objectUUIDRenew );
container.add( objectUUIDRow );
// name
const objectNameRow = new UIRow();
const objectName = new UIInput().setWidth( '150px' ).setFontSize( '12px' ).onChange( function () {
editor.execute( new SetValueCommand( editor, editor.selected, 'name', objectName.getValue() ) );
} );
objectNameRow.add( new UIText( strings.getKey( 'sidebar/object/name' ) ).setWidth( '90px' ) );
objectNameRow.add( objectName );
container.add( objectNameRow );
// position
const objectPositionRow = new UIRow();
const objectPositionX = new UINumber().setPrecision( 3 ).setWidth( '50px' ).onChange( update );
const objectPositionY = new UINumber().setPrecision( 3 ).setWidth( '50px' ).onChange( update );
const objectPositionZ = new UINumber().setPrecision( 3 ).setWidth( '50px' ).onChange( update );
objectPositionRow.add( new UIText( strings.getKey( 'sidebar/object/position' ) ).setWidth( '90px' ) );
objectPositionRow.add( objectPositionX, objectPositionY, objectPositionZ );
container.add( objectPositionRow );
// rotation
const objectRotationRow = new UIRow();
const objectRotationX = new UINumber().setStep( 10 ).setNudge( 0.1 ).setUnit( '°' ).setWidth( '50px' ).onChange( update );
const objectRotationY = new UINumber().setStep( 10 ).setNudge( 0.1 ).setUnit( '°' ).setWidth( '50px' ).onChange( update );
const objectRotationZ = new UINumber().setStep( 10 ).setNudge( 0.1 ).setUnit( '°' ).setWidth( '50px' ).onChange( update );
objectRotationRow.add( new UIText( strings.getKey( 'sidebar/object/rotation' ) ).setWidth( '90px' ) );
objectRotationRow.add( objectRotationX, objectRotationY, objectRotationZ );
container.add( objectRotationRow );
// scale
const objectScaleRow = new UIRow();
const objectScaleX = new UINumber( 1 ).setPrecision( 3 ).setWidth( '50px' ).onChange( update );
const objectScaleY = new UINumber( 1 ).setPrecision( 3 ).setWidth( '50px' ).onChange( update );
const objectScaleZ = new UINumber( 1 ).setPrecision( 3 ).setWidth( '50px' ).onChange( update );
objectScaleRow.add( new UIText( strings.getKey( 'sidebar/object/scale' ) ).setWidth( '90px' ) );
objectScaleRow.add( objectScaleX, objectScaleY, objectScaleZ );
container.add( objectScaleRow );
// fov
const objectFovRow = new UIRow();
const objectFov = new UINumber().onChange( update );
objectFovRow.add( new UIText( strings.getKey( 'sidebar/object/fov' ) ).setWidth( '90px' ) );
objectFovRow.add( objectFov );
container.add( objectFovRow );
// left
const objectLeftRow = new UIRow();
const objectLeft = new UINumber().onChange( update );
objectLeftRow.add( new UIText( strings.getKey( 'sidebar/object/left' ) ).setWidth( '90px' ) );
objectLeftRow.add( objectLeft );
container.add( objectLeftRow );
// right
const objectRightRow = new UIRow();
const objectRight = new UINumber().onChange( update );
objectRightRow.add( new UIText( strings.getKey( 'sidebar/object/right' ) ).setWidth( '90px' ) );
objectRightRow.add( objectRight );
container.add( objectRightRow );
// top
const objectTopRow = new UIRow();
const objectTop = new UINumber().onChange( update );
objectTopRow.add( new UIText( strings.getKey( 'sidebar/object/top' ) ).setWidth( '90px' ) );
objectTopRow.add( objectTop );
container.add( objectTopRow );
// bottom
const objectBottomRow = new UIRow();
const objectBottom = new UINumber().onChange( update );
objectBottomRow.add( new UIText( strings.getKey( 'sidebar/object/bottom' ) ).setWidth( '90px' ) );
objectBottomRow.add( objectBottom );
container.add( objectBottomRow );
// near
const objectNearRow = new UIRow();
const objectNear = new UINumber().onChange( update );
objectNearRow.add( new UIText( strings.getKey( 'sidebar/object/near' ) ).setWidth( '90px' ) );
objectNearRow.add( objectNear );
container.add( objectNearRow );
// far
const objectFarRow = new UIRow();
const objectFar = new UINumber().onChange( update );
objectFarRow.add( new UIText( strings.getKey( 'sidebar/object/far' ) ).setWidth( '90px' ) );
objectFarRow.add( objectFar );
container.add( objectFarRow );
// intensity
const objectIntensityRow = new UIRow();
const objectIntensity = new UINumber().onChange( update );
objectIntensityRow.add( new UIText( strings.getKey( 'sidebar/object/intensity' ) ).setWidth( '90px' ) );
objectIntensityRow.add( objectIntensity );
container.add( objectIntensityRow );
// color
const objectColorRow = new UIRow();
const objectColor = new UIColor().onInput( update );
objectColorRow.add( new UIText( strings.getKey( 'sidebar/object/color' ) ).setWidth( '90px' ) );
objectColorRow.add( objectColor );
container.add( objectColorRow );
// ground color
const objectGroundColorRow = new UIRow();
const objectGroundColor = new UIColor().onInput( update );
objectGroundColorRow.add( new UIText( strings.getKey( 'sidebar/object/groundcolor' ) ).setWidth( '90px' ) );
objectGroundColorRow.add( objectGroundColor );
container.add( objectGroundColorRow );
// distance
const objectDistanceRow = new UIRow();
const objectDistance = new UINumber().setRange( 0, Infinity ).onChange( update );
objectDistanceRow.add( new UIText( strings.getKey( 'sidebar/object/distance' ) ).setWidth( '90px' ) );
objectDistanceRow.add( objectDistance );
container.add( objectDistanceRow );
// angle
const objectAngleRow = new UIRow();
const objectAngle = new UINumber().setPrecision( 3 ).setRange( 0, Math.PI / 2 ).onChange( update );
objectAngleRow.add( new UIText( strings.getKey( 'sidebar/object/angle' ) ).setWidth( '90px' ) );
objectAngleRow.add( objectAngle );
container.add( objectAngleRow );
// penumbra
const objectPenumbraRow = new UIRow();
const objectPenumbra = new UINumber().setRange( 0, 1 ).onChange( update );
objectPenumbraRow.add( new UIText( strings.getKey( 'sidebar/object/penumbra' ) ).setWidth( '90px' ) );
objectPenumbraRow.add( objectPenumbra );
container.add( objectPenumbraRow );
// decay
const objectDecayRow = new UIRow();
const objectDecay = new UINumber().setRange( 0, Infinity ).onChange( update );
objectDecayRow.add( new UIText( strings.getKey( 'sidebar/object/decay' ) ).setWidth( '90px' ) );
objectDecayRow.add( objectDecay );
container.add( objectDecayRow );
// shadow
const objectShadowRow = new UIRow();
objectShadowRow.add( new UIText( strings.getKey( 'sidebar/object/shadow' ) ).setWidth( '90px' ) );
const objectCastShadow = new UIBoolean( false, strings.getKey( 'sidebar/object/cast' ) ).onChange( update );
objectShadowRow.add( objectCastShadow );
const objectReceiveShadow = new UIBoolean( false, strings.getKey( 'sidebar/object/receive' ) ).onChange( update );
objectShadowRow.add( objectReceiveShadow );
container.add( objectShadowRow );
// shadow bias
const objectShadowBiasRow = new UIRow();
objectShadowBiasRow.add( new UIText( strings.getKey( 'sidebar/object/shadowBias' ) ).setWidth( '90px' ) );
const objectShadowBias = new UINumber( 0 ).setPrecision( 5 ).setStep( 0.0001 ).setNudge( 0.00001 ).onChange( update );
objectShadowBiasRow.add( objectShadowBias );
container.add( objectShadowBiasRow );
// shadow normal offset
const objectShadowNormalBiasRow = new UIRow();
objectShadowNormalBiasRow.add( new UIText( strings.getKey( 'sidebar/object/shadowNormalBias' ) ).setWidth( '90px' ) );
const objectShadowNormalBias = new UINumber( 0 ).onChange( update );
objectShadowNormalBiasRow.add( objectShadowNormalBias );
container.add( objectShadowNormalBiasRow );
// shadow radius
const objectShadowRadiusRow = new UIRow();
objectShadowRadiusRow.add( new UIText( strings.getKey( 'sidebar/object/shadowRadius' ) ).setWidth( '90px' ) );
const objectShadowRadius = new UINumber( 1 ).onChange( update );
objectShadowRadiusRow.add( objectShadowRadius );
container.add( objectShadowRadiusRow );
// visible
const objectVisibleRow = new UIRow();
const objectVisible = new UICheckbox().onChange( update );
objectVisibleRow.add( new UIText( strings.getKey( 'sidebar/object/visible' ) ).setWidth( '90px' ) );
objectVisibleRow.add( objectVisible );
container.add( objectVisibleRow );
// frustumCulled
const objectFrustumCulledRow = new UIRow();
const objectFrustumCulled = new UICheckbox().onChange( update );
objectFrustumCulledRow.add( new UIText( strings.getKey( 'sidebar/object/frustumcull' ) ).setWidth( '90px' ) );
objectFrustumCulledRow.add( objectFrustumCulled );
container.add( objectFrustumCulledRow );
// renderOrder
const objectRenderOrderRow = new UIRow();
const objectRenderOrder = new UIInteger().setWidth( '50px' ).onChange( update );
objectRenderOrderRow.add( new UIText( strings.getKey( 'sidebar/object/renderorder' ) ).setWidth( '90px' ) );
objectRenderOrderRow.add( objectRenderOrder );
container.add( objectRenderOrderRow );
// user data
const objectUserDataRow = new UIRow();
const objectUserData = new UITextArea().setWidth( '150px' ).setHeight( '40px' ).setFontSize( '12px' ).onChange( update );
objectUserData.onKeyUp( function () {
try {
JSON.parse( objectUserData.getValue() );
objectUserData.dom.classList.add( 'success' );
objectUserData.dom.classList.remove( 'fail' );
} catch ( error ) {
objectUserData.dom.classList.remove( 'success' );
objectUserData.dom.classList.add( 'fail' );
}
} );
objectUserDataRow.add( new UIText( strings.getKey( 'sidebar/object/userdata' ) ).setWidth( '90px' ) );
objectUserDataRow.add( objectUserData );
container.add( objectUserDataRow );
//
function update() {
const object = editor.selected;
if ( object !== null ) {
const newPosition = new THREE.Vector3( objectPositionX.getValue(), objectPositionY.getValue(), objectPositionZ.getValue() );
if ( object.position.distanceTo( newPosition ) >= 0.01 ) {
editor.execute( new SetPositionCommand( editor, object, newPosition ) );
}
const newRotation = new THREE.Euler( objectRotationX.getValue() * THREE.MathUtils.DEG2RAD, objectRotationY.getValue() * THREE.MathUtils.DEG2RAD, objectRotationZ.getValue() * THREE.MathUtils.DEG2RAD );
if ( new THREE.Vector3().setFromEuler( object.rotation ).distanceTo( new THREE.Vector3().setFromEuler( newRotation ) ) >= 0.01 ) {
editor.execute( new SetRotationCommand( editor, object, newRotation ) );
}
const newScale = new THREE.Vector3( objectScaleX.getValue(), objectScaleY.getValue(), objectScaleZ.getValue() );
if ( object.scale.distanceTo( newScale ) >= 0.01 ) {
editor.execute( new SetScaleCommand( editor, object, newScale ) );
}
if ( object.fov !== undefined && Math.abs( object.fov - objectFov.getValue() ) >= 0.01 ) {
editor.execute( new SetValueCommand( editor, object, 'fov', objectFov.getValue() ) );
object.updateProjectionMatrix();
}
if ( object.left !== undefined && Math.abs( object.left - objectLeft.getValue() ) >= 0.01 ) {
editor.execute( new SetValueCommand( editor, object, 'left', objectLeft.getValue() ) );
object.updateProjectionMatrix();
}
if ( object.right !== undefined && Math.abs( object.right - objectRight.getValue() ) >= 0.01 ) {
editor.execute( new SetValueCommand( editor, object, 'right', objectRight.getValue() ) );
object.updateProjectionMatrix();
}
if ( object.top !== undefined && Math.abs( object.top - objectTop.getValue() ) >= 0.01 ) {
editor.execute( new SetValueCommand( editor, object, 'top', objectTop.getValue() ) );
object.updateProjectionMatrix();
}
if ( object.bottom !== undefined && Math.abs( object.bottom - objectBottom.getValue() ) >= 0.01 ) {
editor.execute( new SetValueCommand( editor, object, 'bottom', objectBottom.getValue() ) );
object.updateProjectionMatrix();
}
if ( object.near !== undefined && Math.abs( object.near - objectNear.getValue() ) >= 0.01 ) {
editor.execute( new SetValueCommand( editor, object, 'near', objectNear.getValue() ) );
if ( object.isOrthographicCamera ) {
object.updateProjectionMatrix();
}
}
if ( object.far !== undefined && Math.abs( object.far - objectFar.getValue() ) >= 0.01 ) {
editor.execute( new SetValueCommand( editor, object, 'far', objectFar.getValue() ) );
if ( object.isOrthographicCamera ) {
object.updateProjectionMatrix();
}
}
if ( object.intensity !== undefined && Math.abs( object.intensity - objectIntensity.getValue() ) >= 0.01 ) {
editor.execute( new SetValueCommand( editor, object, 'intensity', objectIntensity.getValue() ) );
}
if ( object.color !== undefined && object.color.getHex() !== objectColor.getHexValue() ) {
editor.execute( new SetColorCommand( editor, object, 'color', objectColor.getHexValue() ) );
}
if ( object.groundColor !== undefined && object.groundColor.getHex() !== objectGroundColor.getHexValue() ) {
editor.execute( new SetColorCommand( editor, object, 'groundColor', objectGroundColor.getHexValue() ) );
}
if ( object.distance !== undefined && Math.abs( object.distance - objectDistance.getValue() ) >= 0.01 ) {
editor.execute( new SetValueCommand( editor, object, 'distance', objectDistance.getValue() ) );
}
if ( object.angle !== undefined && Math.abs( object.angle - objectAngle.getValue() ) >= 0.01 ) {
editor.execute( new SetValueCommand( editor, object, 'angle', objectAngle.getValue() ) );
}
if ( object.penumbra !== undefined && Math.abs( object.penumbra - objectPenumbra.getValue() ) >= 0.01 ) {
editor.execute( new SetValueCommand( editor, object, 'penumbra', objectPenumbra.getValue() ) );
}
if ( object.decay !== undefined && Math.abs( object.decay - objectDecay.getValue() ) >= 0.01 ) {
editor.execute( new SetValueCommand( editor, object, 'decay', objectDecay.getValue() ) );
}
if ( object.visible !== objectVisible.getValue() ) {
editor.execute( new SetValueCommand( editor, object, 'visible', objectVisible.getValue() ) );
}
if ( object.frustumCulled !== objectFrustumCulled.getValue() ) {
editor.execute( new SetValueCommand( editor, object, 'frustumCulled', objectFrustumCulled.getValue() ) );
}
if ( object.renderOrder !== objectRenderOrder.getValue() ) {
editor.execute( new SetValueCommand( editor, object, 'renderOrder', objectRenderOrder.getValue() ) );
}
if ( object.castShadow !== undefined && object.castShadow !== objectCastShadow.getValue() ) {
editor.execute( new SetValueCommand( editor, object, 'castShadow', objectCastShadow.getValue() ) );
}
if ( object.receiveShadow !== objectReceiveShadow.getValue() ) {
if ( object.material !== undefined ) object.material.needsUpdate = true;
editor.execute( new SetValueCommand( editor, object, 'receiveShadow', objectReceiveShadow.getValue() ) );
}
if ( object.shadow !== undefined ) {
if ( object.shadow.bias !== objectShadowBias.getValue() ) {
editor.execute( new SetValueCommand( editor, object.shadow, 'bias', objectShadowBias.getValue() ) );
}
if ( object.shadow.normalBias !== objectShadowNormalBias.getValue() ) {
editor.execute( new SetValueCommand( editor, object.shadow, 'normalBias', objectShadowNormalBias.getValue() ) );
}
if ( object.shadow.radius !== objectShadowRadius.getValue() ) {
editor.execute( new SetValueCommand( editor, object.shadow, 'radius', objectShadowRadius.getValue() ) );
}
}
try {
const userData = JSON.parse( objectUserData.getValue() );
if ( JSON.stringify( object.userData ) != JSON.stringify( userData ) ) {
editor.execute( new SetValueCommand( editor, object, 'userData', userData ) );
}
} catch ( exception ) {
console.warn( exception );
}
}
}
function updateRows( object ) {
const properties = {
'fov': objectFovRow,
'left': objectLeftRow,
'right': objectRightRow,
'top': objectTopRow,
'bottom': objectBottomRow,
'near': objectNearRow,
'far': objectFarRow,
'intensity': objectIntensityRow,
'color': objectColorRow,
'groundColor': objectGroundColorRow,
'distance': objectDistanceRow,
'angle': objectAngleRow,
'penumbra': objectPenumbraRow,
'decay': objectDecayRow,
'castShadow': objectShadowRow,
'receiveShadow': objectReceiveShadow,
'shadow': [ objectShadowBiasRow, objectShadowNormalBiasRow, objectShadowRadiusRow ]
};
for ( const property in properties ) {
const uiElement = properties[ property ];
if ( Array.isArray( uiElement ) === true ) {
for ( let i = 0; i < uiElement.length; i ++ ) {
uiElement[ i ].setDisplay( object[ property ] !== undefined ? '' : 'none' );
}
} else {
uiElement.setDisplay( object[ property ] !== undefined ? '' : 'none' );
}
}
//
if ( object.isLight ) {
objectReceiveShadow.setDisplay( 'none' );
}
if ( object.isAmbientLight || object.isHemisphereLight ) {
objectShadowRow.setDisplay( 'none' );
}
}
function updateTransformRows( object ) {
if ( object.isLight ||
( object.isObject3D && object.userData.targetInverse ) ) {
objectRotationRow.setDisplay( 'none' );
objectScaleRow.setDisplay( 'none' );
} else {
objectRotationRow.setDisplay( '' );
objectScaleRow.setDisplay( '' );
}
}
// events
signals.objectSelected.add( function ( object ) {
if ( object !== null ) {
container.setDisplay( 'block' );
updateRows( object );
updateUI( object );
} else {
container.setDisplay( 'none' );
}
} );
signals.objectChanged.add( function ( object ) {
if ( object !== editor.selected ) return;
updateUI( object );
} );
signals.refreshSidebarObject3D.add( function ( object ) {
if ( object !== editor.selected ) return;
updateUI( object );
} );
function updateUI( object ) {
objectType.setValue( object.type );
objectUUID.setValue( object.uuid );
objectName.setValue( object.name );
objectPositionX.setValue( object.position.x );
objectPositionY.setValue( object.position.y );
objectPositionZ.setValue( object.position.z );
objectRotationX.setValue( object.rotation.x * THREE.MathUtils.RAD2DEG );
objectRotationY.setValue( object.rotation.y * THREE.MathUtils.RAD2DEG );
objectRotationZ.setValue( object.rotation.z * THREE.MathUtils.RAD2DEG );
objectScaleX.setValue( object.scale.x );
objectScaleY.setValue( object.scale.y );
objectScaleZ.setValue( object.scale.z );
if ( object.fov !== undefined ) {
objectFov.setValue( object.fov );
}
if ( object.left !== undefined ) {
objectLeft.setValue( object.left );
}
if ( object.right !== undefined ) {
objectRight.setValue( object.right );
}
if ( object.top !== undefined ) {
objectTop.setValue( object.top );
}
if ( object.bottom !== undefined ) {
objectBottom.setValue( object.bottom );
}
if ( object.near !== undefined ) {
objectNear.setValue( object.near );
}
if ( object.far !== undefined ) {
objectFar.setValue( object.far );
}
if ( object.intensity !== undefined ) {
objectIntensity.setValue( object.intensity );
}
if ( object.color !== undefined ) {
objectColor.setHexValue( object.color.getHexString() );
}
if ( object.groundColor !== undefined ) {
objectGroundColor.setHexValue( object.groundColor.getHexString() );
}
if ( object.distance !== undefined ) {
objectDistance.setValue( object.distance );
}
if ( object.angle !== undefined ) {
objectAngle.setValue( object.angle );
}
if ( object.penumbra !== undefined ) {
objectPenumbra.setValue( object.penumbra );
}
if ( object.decay !== undefined ) {
objectDecay.setValue( object.decay );
}
if ( object.castShadow !== undefined ) {
objectCastShadow.setValue( object.castShadow );
}
if ( object.receiveShadow !== undefined ) {
objectReceiveShadow.setValue( object.receiveShadow );
}
if ( object.shadow !== undefined ) {
objectShadowBias.setValue( object.shadow.bias );
objectShadowNormalBias.setValue( object.shadow.normalBias );
objectShadowRadius.setValue( object.shadow.radius );
}
objectVisible.setValue( object.visible );
objectFrustumCulled.setValue( object.frustumCulled );
objectRenderOrder.setValue( object.renderOrder );
try {
objectUserData.setValue( JSON.stringify( object.userData, null, ' ' ) );
} catch ( error ) {
console.log( error );
}
objectUserData.setBorderColor( 'transparent' );
objectUserData.setBackgroundColor( '' );
updateTransformRows( object );
}
return container;
}
export { SidebarObject };