From e608a998ab0a0033d6e8e5f79ceec7bc92802de7 Mon Sep 17 00:00:00 2001 From: ostatni5 <26521377+ostatni5@users.noreply.github.com> Date: Tue, 7 Sep 2021 13:56:12 +0200 Subject: [PATCH] add two layouts and cleanup code (#25) --- src/ThreeEditor/js/Editor.js | 4 +- src/ThreeEditor/js/Menubar.Layout.js | 49 ++ src/ThreeEditor/js/Menubar.js | 2 + src/ThreeEditor/js/ViewPanel.js | 435 -------------- src/ThreeEditor/js/Viewport copy.js | 795 -------------------------- src/ThreeEditor/js/Viewport.js | 660 +++++++++------------ src/ThreeEditor/js/ViewportManager.js | 254 ++++---- src/ThreeEditor/main.js | 8 +- 8 files changed, 433 insertions(+), 1774 deletions(-) create mode 100644 src/ThreeEditor/js/Menubar.Layout.js delete mode 100644 src/ThreeEditor/js/ViewPanel.js delete mode 100644 src/ThreeEditor/js/Viewport copy.js diff --git a/src/ThreeEditor/js/Editor.js b/src/ThreeEditor/js/Editor.js index fbf841eee..2d00733b1 100644 --- a/src/ThreeEditor/js/Editor.js +++ b/src/ThreeEditor/js/Editor.js @@ -86,7 +86,9 @@ function Editor() { viewportCameraChanged: new Signal(), - animationStopped: new Signal() + animationStopped: new Signal(), + + layoutChanged: new Signal() // Layout signal }; diff --git a/src/ThreeEditor/js/Menubar.Layout.js b/src/ThreeEditor/js/Menubar.Layout.js new file mode 100644 index 000000000..b85c78f96 --- /dev/null +++ b/src/ThreeEditor/js/Menubar.Layout.js @@ -0,0 +1,49 @@ +import { UIPanel, UIRow } from './libs/ui.js'; + +function MenubarLayout( editor ) { + + var strings = editor.strings; + + var container = new UIPanel(); + container.setClass( 'menu' ); + + var title = new UIPanel(); + title.setClass( 'title' ); + title.setTextContent( 'Layout' ); + container.add( title ); + + var options = new UIPanel(); + options.setClass( 'options' ); + container.add( options ); + + // Single view + + var option = new UIRow(); + option.setClass( 'option' ); + option.setTextContent( 'Single View' ); + option.onClick( function () { + + editor.signals.layoutChanged.dispatch('singleView'); + + } ); + options.add( option ); + + // Four view + + var option = new UIRow(); + option.setClass( 'option' ); + option.setTextContent( 'Four Views' ); + option.onClick( function () { + + editor.signals.layoutChanged.dispatch('fourViews'); + + } ); + options.add( option ); + + + + return container; + +} + +export { MenubarLayout }; diff --git a/src/ThreeEditor/js/Menubar.js b/src/ThreeEditor/js/Menubar.js index cf4544fde..98873d8dc 100644 --- a/src/ThreeEditor/js/Menubar.js +++ b/src/ThreeEditor/js/Menubar.js @@ -6,6 +6,7 @@ import { MenubarView } from './Menubar.View.js'; import { MenubarFile } from './Menubar.File.js'; import { MenubarHelp } from './Menubar.Help.js'; import { MenubarStatus } from './Menubar.Status.js'; +import { MenubarLayout } from './Menubar.Layout.js'; function Menubar( editor ) { @@ -17,6 +18,7 @@ function Menubar( editor ) { container.add( new MenubarAdd( editor ) ); container.add( new MenubarView( editor ) ); container.add( new MenubarHelp( editor ) ); + container.add( new MenubarLayout( editor ) ); container.add( new MenubarStatus( editor ) ); diff --git a/src/ThreeEditor/js/ViewPanel.js b/src/ThreeEditor/js/ViewPanel.js deleted file mode 100644 index ee5164543..000000000 --- a/src/ThreeEditor/js/ViewPanel.js +++ /dev/null @@ -1,435 +0,0 @@ -import * as THREE from 'three' -import { TransformControls } from 'three/examples/jsm/controls/TransformControls'; -import { SetPositionCommand } from './commands/SetPositionCommand'; -import { SetRotationCommand } from './commands/SetRotationCommand'; -import { SetScaleCommand } from './commands/SetScaleCommand'; -import { EditorControls } from './EditorControls'; - -import { ViewportCamera } from './Viewport.Camera.js'; -import { ViewportInfo } from './Viewport.Info.js'; - -import { UIPanel } from "./libs/ui"; -import { ViewHelper } from './Viewport.ViewHelper'; - -export function ViewPanel(name, editor, viewWidth, viewHeight, { objects, grid, cameraPosition, selectionBox }) { - let { scene, sceneHelpers, signals } = editor; - - let showSceneHelpers = true; - - let sceneViewHelpers = new THREE.Scene(); - - - let container = new UIPanel(); - container.setId('ViewPanel'); - container.setPosition('relative'); - container.setOverflow("hidden"); - container.dom.setAttribute('tabindex', '0'); - - - container.add(new ViewportCamera(editor)); - container.add(new ViewportInfo(editor)); - - let canvas = document.createElement('canvas'); - container.dom.appendChild(canvas); - canvas.width = viewWidth * window.devicePixelRatio; - canvas.height = viewHeight * window.devicePixelRatio; - - let context = canvas.getContext('2d'); - - let cameraPersp = new THREE.PerspectiveCamera(50, 1, 0.01, 1000); - cameraPersp.position.copy(cameraPosition ?? new THREE.Vector3(0,5,10)); - cameraPersp.lookAt( new THREE.Vector3() ); - let cameraOrtho = new THREE.OrthographicCamera(1 / - 2, 1 / 2, 1 / 2, 1 / - 2, 1, 1000); - cameraOrtho.position.copy(cameraPosition ?? new THREE.Vector3(0,5,10)); - cameraOrtho.lookAt( new THREE.Vector3() ); - - let camera = cameraPersp; - camera.name = name; - updateAspectRatio(); - - let viewHelper = new ViewHelper(camera, container); - - let cachedRenderer = null; - - function render(renderer = cachedRenderer) { - cachedRenderer = renderer; - - if (!renderer) return; - - scene.add(grid); - renderer.setSize(canvas.width, canvas.height); - renderer.render(scene, camera); - scene.remove(grid); - - renderer.autoClear = false; - if (showSceneHelpers) { - renderer.render(sceneHelpers, camera); - renderer.render(sceneViewHelpers, camera); - viewHelper.render(renderer); - } - renderer.autoClear = true; - - context.drawImage(renderer.domElement, 0, 0); - - }; - - function animate(delta) { - if (viewHelper.animating === true) { - - viewHelper.update(delta); - - return true; - } - - return false; - } - - - - var objectPositionOnDown = null; - var objectRotationOnDown = null; - var objectScaleOnDown = null; - - var transformControls = new TransformControls(camera, container.dom); - transformControls.addEventListener('change', function () { - - var object = transformControls.object; - - if (object !== undefined) { - - selectionBox.setFromObject(object); - - var helper = editor.helpers[object.id]; - - if (helper !== undefined && helper.isSkeletonHelper !== true) { - - helper.update(); - - } - - signals.refreshSidebarObject3D.dispatch(object); - - } - - render(); - - }); - - transformControls.addEventListener('mouseDown', function () { - - var object = transformControls.object; - - objectPositionOnDown = object.position.clone(); - objectRotationOnDown = object.rotation.clone(); - objectScaleOnDown = object.scale.clone(); - - controls.enabled = false; - - - }); - - transformControls.addEventListener('mouseUp', function () { - - var object = transformControls.object; - - if (object !== undefined) { - - switch (transformControls.getMode()) { - - case 'translate': - - if (!objectPositionOnDown.equals(object.position)) { - - editor.execute(new SetPositionCommand(editor, object, object.position, objectPositionOnDown)); - - } - - break; - - case 'rotate': - - if (!objectRotationOnDown.equals(object.rotation)) { - - editor.execute(new SetRotationCommand(editor, object, object.rotation, objectRotationOnDown)); - - } - - break; - - case 'scale': - - if (!objectScaleOnDown.equals(object.scale)) { - - editor.execute(new SetScaleCommand(editor, object, object.scale, objectScaleOnDown)); - - } - - break; - - default: - console.error(transformControls.getMode()); - } - - } - - controls.enabled = true; - - }); - - - sceneViewHelpers.add(transformControls); - - - - // object picking - - var raycaster = new THREE.Raycaster(); - var mouse = new THREE.Vector2(); - - function getIntersects(point, objects) { - - mouse.set((point.x * 2) - 1, - (point.y * 2) + 1); - - raycaster.setFromCamera(mouse, camera); - - return raycaster.intersectObjects(objects) - .filter(intersect => intersect.object.visible === true); - - } - - var onDownPosition = new THREE.Vector2(); - var onUpPosition = new THREE.Vector2(); - var onDoubleClickPosition = new THREE.Vector2(); - - function getMousePosition(dom, x, y) { - - var rect = dom.getBoundingClientRect(); - return [(x - rect.left) / rect.width, (y - rect.top) / rect.height]; - - } - - // events - - function updateAspectRatio() { - const aspect = container.dom.offsetWidth / container.dom.offsetHeight; - - cameraPersp.aspect = aspect; - cameraPersp.updateProjectionMatrix(); - - cameraOrtho.left = cameraOrtho.bottom * aspect; - cameraOrtho.right = cameraOrtho.top * aspect; - cameraOrtho.updateProjectionMatrix(); - - } - - function handleClick() { - - if (onDownPosition.distanceTo(onUpPosition) === 0) { - - var intersects = getIntersects(onUpPosition, objects); - - if (intersects.length > 0) { - - var object = intersects[0].object; - - if (object.userData.object !== undefined) { - - // helper - - editor.select(object.userData.object); - - } else { - - editor.select(object); - - } - - transformControls.camera = camera; - - } else { - - editor.select(null); - - } - - render(); - - } - - } - - function onMouseDown(event) { - - // event.preventDefault(); - - var array = getMousePosition(container.dom, event.clientX, event.clientY); - onDownPosition.fromArray(array); - - document.addEventListener('mouseup', onMouseUp, false); - - } - - function onMouseUp(event) { - - var array = getMousePosition(container.dom, event.clientX, event.clientY); - onUpPosition.fromArray(array); - - handleClick(); - - document.removeEventListener('mouseup', onMouseUp, false); - - } - - function onTouchStart(event) { - - var touch = event.changedTouches[0]; - - var array = getMousePosition(container.dom, touch.clientX, touch.clientY); - onDownPosition.fromArray(array); - - document.addEventListener('touchend', onTouchEnd, false); - - } - - function onTouchEnd(event) { - - var touch = event.changedTouches[0]; - - var array = getMousePosition(container.dom, touch.clientX, touch.clientY); - onUpPosition.fromArray(array); - - handleClick(); - - document.removeEventListener('touchend', onTouchEnd, false); - - } - - function onDoubleClick(event) { - - var array = getMousePosition(container.dom, event.clientX, event.clientY); - onDoubleClickPosition.fromArray(array); - - var intersects = getIntersects(onDoubleClickPosition, objects); - - if (intersects.length > 0) { - - var intersect = intersects[0]; - - signals.objectFocused.dispatch(intersect.object); - - } - - } - - container.dom.addEventListener( 'keydown', function ( event ) { - - switch ( event.code ) { - case 'KeyC': // C - const position = camera.position.clone(); - - camera = camera.isPerspectiveCamera ? cameraOrtho : cameraPersp; - camera.position.copy( position ); - - controls.object = camera; - transformControls.camera = camera; - viewHelper.editorCamera = camera; - - camera.lookAt( controls.center.x, controls.center.y, controls.center.z ); - updateAspectRatio(); - break; - - default: - - - } - - } ); - - container.dom.addEventListener('mousedown', onMouseDown, false); - container.dom.addEventListener('touchstart', onTouchStart, false); - container.dom.addEventListener('dblclick', onDoubleClick, false); - - // controls need to be added *after* main logic, - // otherwise controls.enabled doesn't work. - - var controls = new EditorControls(camera, container.dom); - controls.addEventListener('change', function () { - - signals.cameraChanged.dispatch(camera); - signals.refreshSidebarObject3D.dispatch(camera); - - }); - viewHelper.controls = controls; - - - signals.transformModeChanged.add(function (mode) { - - transformControls.setMode(mode); - - }); - - signals.snapChanged.add(function (dist) { - - transformControls.setTranslationSnap(dist); - - }); - - signals.spaceChanged.add(function (space) { - - transformControls.setSpace(space); - - }); - - signals.objectSelected.add(function (object) { - - - transformControls.detach(); - - if (object !== null && object !== scene && object !== camera) { - - transformControls.attach(object); - - } - - render(); - - }); - - signals.objectRemoved.add(function (object) { - - controls.enabled = true; - - if (object === transformControls.object) { - - transformControls.detach(); - - } - - }); - - - signals.showHelpersChanged.add(function (showHelpers) { - - transformControls.enabled = showHelpers; - - render(); - - }); - - - function setSize(viewWidth = container.dom.offsetWidth, viewHeight =container.dom.offsetHeight) { - canvas.width = viewWidth; - canvas.height = viewHeight; - updateAspectRatio(); - } - - return { - render, - container, - controls, - viewHelper, - animate, - setSize - } - -} \ No newline at end of file diff --git a/src/ThreeEditor/js/Viewport copy.js b/src/ThreeEditor/js/Viewport copy.js deleted file mode 100644 index 897e7a6e5..000000000 --- a/src/ThreeEditor/js/Viewport copy.js +++ /dev/null @@ -1,795 +0,0 @@ -import * as THREE from 'three' - - -import { TransformControls } from 'three/examples/jsm/controls/TransformControls'; - -import { UIPanel } from './libs/ui.js'; - -import { EditorControls } from './EditorControls.js'; - -import { ViewportCamera } from './Viewport.Camera.js'; -import { ViewportInfo } from './Viewport.Info.js'; -import { ViewHelper } from './Viewport.ViewHelper.js'; -import { VR } from './Viewport.VR.js'; - -import { SetPositionCommand } from './commands/SetPositionCommand.js'; -import { SetRotationCommand } from './commands/SetRotationCommand.js'; -import { SetScaleCommand } from './commands/SetScaleCommand.js'; - -import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js'; - -function Viewport(editor) { - - var signals = editor.signals; - - var container = new UIPanel(); - container.setId('viewport'); - container.setPosition('absolute'); - - container.add(new ViewportCamera(editor)); - container.add(new ViewportInfo(editor)); - - // - - var renderer = null; - var pmremGenerator = null; - - var camera = editor.camera; - var scene = editor.scene; - var sceneHelpers = editor.sceneHelpers; - var showSceneHelpers = true; - - var objects = []; - - // helpers - - var grid = new THREE.Group(); - - var grid1 = new THREE.GridHelper(30, 30, 0x888888); - grid1.material.color.setHex(0x888888); - grid1.material.vertexColors = false; - grid.add(grid1); - - var grid2 = new THREE.GridHelper(30, 6, 0x222222); - grid2.material.color.setHex(0x222222); - grid2.material.depthFunc = THREE.AlwaysDepth; - grid2.material.vertexColors = false; - grid.add(grid2); - - var viewHelper = new ViewHelper( camera, container ); - var vr = new VR( editor ); - - // - - var box = new THREE.Box3(); - - var selectionBox = new THREE.BoxHelper(); - selectionBox.material.depthTest = false; - selectionBox.material.transparent = true; - selectionBox.visible = false; - sceneHelpers.add(selectionBox); - - var objectPositionOnDown = null; - var objectRotationOnDown = null; - var objectScaleOnDown = null; - - var transformControls = new TransformControls(camera, container.dom); - transformControls.addEventListener('change', function () { - - var object = transformControls.object; - - if (object !== undefined) { - - selectionBox.setFromObject(object); - - var helper = editor.helpers[object.id]; - - if (helper !== undefined && helper.isSkeletonHelper !== true) { - - helper.update(); - - } - - signals.refreshSidebarObject3D.dispatch(object); - - } - - render(); - - }); - transformControls.addEventListener('mouseDown', function () { - - var object = transformControls.object; - - objectPositionOnDown = object.position.clone(); - objectRotationOnDown = object.rotation.clone(); - objectScaleOnDown = object.scale.clone(); - - controls.enabled = false; - - }); - transformControls.addEventListener('mouseUp', function () { - - var object = transformControls.object; - - if (object !== undefined) { - - switch (transformControls.getMode()) { - - case 'translate': - - if (!objectPositionOnDown.equals(object.position)) { - - editor.execute(new SetPositionCommand(editor, object, object.position, objectPositionOnDown)); - - } - - break; - - case 'rotate': - - if (!objectRotationOnDown.equals(object.rotation)) { - - editor.execute(new SetRotationCommand(editor, object, object.rotation, objectRotationOnDown)); - - } - - break; - - case 'scale': - - if (!objectScaleOnDown.equals(object.scale)) { - - editor.execute(new SetScaleCommand(editor, object, object.scale, objectScaleOnDown)); - - } - - break; - - } - - } - - controls.enabled = true; - - }); - - sceneHelpers.add(transformControls); - - // object picking - - var raycaster = new THREE.Raycaster(); - var mouse = new THREE.Vector2(); - - // events - - function updateAspectRatio() { - - camera.aspect = container.dom.offsetWidth / container.dom.offsetHeight; - camera.updateProjectionMatrix(); - - } - - function getIntersects(point, objects) { - - mouse.set((point.x * 2) - 1, - (point.y * 2) + 1); - - raycaster.setFromCamera(mouse, camera); - - return raycaster.intersectObjects(objects) - .filter(intersect => intersect.object.visible === true); - - } - - var onDownPosition = new THREE.Vector2(); - var onUpPosition = new THREE.Vector2(); - var onDoubleClickPosition = new THREE.Vector2(); - - function getMousePosition(dom, x, y) { - - var rect = dom.getBoundingClientRect(); - return [(x - rect.left) / rect.width, (y - rect.top) / rect.height]; - - } - - function handleClick() { - - if (onDownPosition.distanceTo(onUpPosition) === 0) { - - var intersects = getIntersects(onUpPosition, objects); - - if (intersects.length > 0) { - - var object = intersects[0].object; - - if (object.userData.object !== undefined) { - - // helper - - editor.select(object.userData.object); - - } else { - - editor.select(object); - - } - - } else { - - editor.select(null); - - } - - render(); - - } - - } - - function onMouseDown(event) { - - // event.preventDefault(); - - var array = getMousePosition(container.dom, event.clientX, event.clientY); - onDownPosition.fromArray(array); - - document.addEventListener('mouseup', onMouseUp, false); - - } - - function onMouseUp(event) { - - var array = getMousePosition(container.dom, event.clientX, event.clientY); - onUpPosition.fromArray(array); - - handleClick(); - - document.removeEventListener('mouseup', onMouseUp, false); - - } - - function onTouchStart(event) { - - var touch = event.changedTouches[0]; - - var array = getMousePosition(container.dom, touch.clientX, touch.clientY); - onDownPosition.fromArray(array); - - document.addEventListener('touchend', onTouchEnd, false); - - } - - function onTouchEnd(event) { - - var touch = event.changedTouches[0]; - - var array = getMousePosition(container.dom, touch.clientX, touch.clientY); - onUpPosition.fromArray(array); - - handleClick(); - - document.removeEventListener('touchend', onTouchEnd, false); - - } - - function onDoubleClick(event) { - - var array = getMousePosition(container.dom, event.clientX, event.clientY); - onDoubleClickPosition.fromArray(array); - - var intersects = getIntersects(onDoubleClickPosition, objects); - - if (intersects.length > 0) { - - var intersect = intersects[0]; - - signals.objectFocused.dispatch(intersect.object); - - } - - } - - container.dom.addEventListener('mousedown', onMouseDown, false); - container.dom.addEventListener('touchstart', onTouchStart, false); - container.dom.addEventListener('dblclick', onDoubleClick, false); - - // controls need to be added *after* main logic, - // otherwise controls.enabled doesn't work. - - var controls = new EditorControls(camera, container.dom); - controls.addEventListener('change', function () { - - signals.cameraChanged.dispatch(camera); - signals.refreshSidebarObject3D.dispatch(camera); - - }); - viewHelper.controls = controls; - - // signals - - signals.editorCleared.add(function () { - - controls.center.set(0, 0, 0); - render(); - - }); - - signals.transformModeChanged.add(function (mode) { - - transformControls.setMode(mode); - - }); - - signals.snapChanged.add(function (dist) { - - transformControls.setTranslationSnap(dist); - - }); - - signals.spaceChanged.add(function (space) { - - transformControls.setSpace(space); - - }); - - signals.rendererUpdated.add(function () { - - scene.traverse(function (child) { - - if (child.material !== undefined) { - - child.material.needsUpdate = true; - - } - - }); - - render(); - - }); - - signals.rendererCreated.add(function (newRenderer) { - - if (renderer !== null) { - - renderer.setAnimationLoop(null); - renderer.dispose(); - pmremGenerator.dispose(); - - container.dom.removeChild(renderer.domElement); - - } - - renderer = newRenderer; - - renderer.setAnimationLoop(animate); - renderer.setClearColor(0xaaaaaa); - - if (window.matchMedia) { - - var mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); - mediaQuery.addListener(function (event) { - - renderer.setClearColor(event.matches ? 0x333333 : 0xaaaaaa); - updateGridColors(grid1, grid2, event.matches ? [0x222222, 0x888888] : [0x888888, 0x282828]); - - render(); - - }); - - renderer.setClearColor(mediaQuery.matches ? 0x333333 : 0xaaaaaa); - updateGridColors(grid1, grid2, mediaQuery.matches ? [0x222222, 0x888888] : [0x888888, 0x282828]); - - } - - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(container.dom.offsetWidth, container.dom.offsetHeight); - - pmremGenerator = new THREE.PMREMGenerator(renderer); - pmremGenerator.compileEquirectangularShader(); - - container.dom.appendChild(renderer.domElement); - - render(); - - }); - - signals.sceneGraphChanged.add(function () { - - render(); - - }); - - signals.cameraChanged.add(function () { - - render(); - - }); - - signals.objectSelected.add(function (object) { - - selectionBox.visible = false; - transformControls.detach(); - - if (object !== null && object !== scene && object !== camera) { - - box.setFromObject(object); - - if (box.isEmpty() === false) { - - selectionBox.setFromObject(object); - selectionBox.visible = true; - - } - - transformControls.attach(object); - - } - - render(); - - }); - - signals.objectFocused.add(function (object) { - - controls.focus(object); - - }); - - signals.geometryChanged.add(function (object) { - - if (object !== undefined) { - - selectionBox.setFromObject(object); - - } - - render(); - - }); - - signals.objectAdded.add(function (object) { - - object.traverse(function (child) { - - objects.push(child); - - }); - - }); - - signals.objectChanged.add(function (object) { - - if (editor.selected === object) { - - selectionBox.setFromObject(object); - - } - - if (object.isPerspectiveCamera) { - - object.updateProjectionMatrix(); - - } - - if (editor.helpers[object.id] !== undefined) { - - editor.helpers[object.id].update(); - - } - - render(); - - }); - - signals.objectRemoved.add(function (object) { - - controls.enabled = true; // see #14180 - if (object === transformControls.object) { - - transformControls.detach(); - - } - - object.traverse(function (child) { - - objects.splice(objects.indexOf(child), 1); - - }); - - }); - - signals.helperAdded.add(function (object) { - - var picker = object.getObjectByName('picker'); - - if (picker !== undefined) { - - objects.push(picker); - - } - - }); - - signals.helperRemoved.add(function (object) { - - var picker = object.getObjectByName('picker'); - - if (picker !== undefined) { - - objects.splice(objects.indexOf(picker), 1); - - } - - }); - - signals.materialChanged.add(function () { - - render(); - - }); - - signals.animationStopped.add(function () { - - render(); - - }); - - // background - - signals.sceneBackgroundChanged.add(function (backgroundType, backgroundColor, backgroundTexture, backgroundEquirectangularTexture) { - - switch (backgroundType) { - - case 'None': - - scene.background = null; - - break; - - case 'Color': - - scene.background = new THREE.Color(backgroundColor); - - break; - - case 'Texture': - - if (backgroundTexture) { - - scene.background = backgroundTexture; - - } - - break; - - case 'Equirectangular': - - if (backgroundEquirectangularTexture) { - - backgroundEquirectangularTexture.mapping = THREE.EquirectangularReflectionMapping; - scene.background = backgroundEquirectangularTexture; - - } - - break; - - } - - render(); - - }); - - // environment - - signals.sceneEnvironmentChanged.add(function (environmentType, environmentEquirectangularTexture) { - - switch (environmentType) { - - case 'None': - - scene.environment = null; - - break; - - case 'Equirectangular': - - scene.environment = null; - - if (environmentEquirectangularTexture) { - - environmentEquirectangularTexture.mapping = THREE.EquirectangularReflectionMapping; - scene.environment = environmentEquirectangularTexture; - - } - - break; - - case 'ModelViewer': - - scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture; - - break; - - } - - render(); - - }); - - // fog - - signals.sceneFogChanged.add(function (fogType, fogColor, fogNear, fogFar, fogDensity) { - - switch (fogType) { - - case 'None': - scene.fog = null; - break; - case 'Fog': - scene.fog = new THREE.Fog(fogColor, fogNear, fogFar); - break; - case 'FogExp2': - scene.fog = new THREE.FogExp2(fogColor, fogDensity); - break; - - } - - render(); - - }); - - signals.sceneFogSettingsChanged.add(function (fogType, fogColor, fogNear, fogFar, fogDensity) { - - switch (fogType) { - - case 'Fog': - scene.fog.color.setHex(fogColor); - scene.fog.near = fogNear; - scene.fog.far = fogFar; - break; - case 'FogExp2': - scene.fog.color.setHex(fogColor); - scene.fog.density = fogDensity; - break; - - } - - render(); - - }); - - signals.viewportCameraChanged.add(function () { - - var viewportCamera = editor.viewportCamera; - - if (viewportCamera.isPerspectiveCamera) { - - viewportCamera.aspect = editor.camera.aspect; - viewportCamera.projectionMatrix.copy(editor.camera.projectionMatrix); - - } else if (viewportCamera.isOrthographicCamera) { - - // TODO - - } - - // disable EditorControls when setting a user camera - - controls.enabled = (viewportCamera === editor.camera); - - render(); - - }); - - signals.exitedVR.add( render ); - - // - - signals.windowResize.add(function () { - - updateAspectRatio(); - - renderer.setSize(container.dom.offsetWidth, container.dom.offsetHeight); - - render(); - - }); - - signals.showGridChanged.add(function (showGrid) { - - grid.visible = showGrid; - render(); - - }); - - signals.showHelpersChanged.add(function (showHelpers) { - - showSceneHelpers = showHelpers; - transformControls.enabled = showHelpers; - - render(); - - }); - - signals.cameraResetted.add(updateAspectRatio); - - // animations - - var clock = new THREE.Clock(); // only used for animations - - function animate() { - - var mixer = editor.mixer; - var delta = clock.getDelta(); - - var needsUpdate = false; - - if (mixer.stats.actions.inUse > 0) { - - mixer.update(delta); - needsUpdate = true; - - } - - if (viewHelper.animating === true) { - - viewHelper.update(delta); - needsUpdate = true; - - } - - if ( vr.currentSession !== null ) { - - needsUpdate = true; - - } - - - if (needsUpdate === true) render(); - - } - - // - - var startTime = 0; - var endTime = 0; - - function render() { - - startTime = performance.now(); - - // Adding/removing grid to scene so materials with depthWrite false - // don't render under the grid. - - scene.add(grid); - renderer.setViewport(0, 0, container.dom.offsetWidth, container.dom.offsetHeight); - renderer.render(scene, editor.viewportCamera); - scene.remove(grid); - - if (camera === editor.viewportCamera) { - - renderer.autoClear = false; - if ( showSceneHelpers === true ) renderer.render( sceneHelpers, camera ); - if ( vr.currentSession === null ) viewHelper.render( renderer ); - renderer.autoClear = true; - - } - - endTime = performance.now(); - editor.signals.sceneRendered.dispatch(endTime - startTime); - - } - - return container; - -} - -function updateGridColors(grid1, grid2, colors) { - - grid1.material.color.setHex(colors[0]); - grid2.material.color.setHex(colors[1]); - -} - -export { Viewport }; diff --git a/src/ThreeEditor/js/Viewport.js b/src/ThreeEditor/js/Viewport.js index a9f414858..b60c637d5 100644 --- a/src/ThreeEditor/js/Viewport.js +++ b/src/ThreeEditor/js/Viewport.js @@ -1,589 +1,443 @@ import * as THREE from 'three' - -import Split from 'split-grid' - - import { TransformControls } from 'three/examples/jsm/controls/TransformControls'; +import { SetPositionCommand } from './commands/SetPositionCommand'; +import { SetRotationCommand } from './commands/SetRotationCommand'; +import { SetScaleCommand } from './commands/SetScaleCommand'; +import { EditorControls } from './EditorControls'; -import { UIDiv, UIPanel } from './libs/ui.js'; - -import { EditorControls } from './EditorControls.js'; - -import { ViewHelper } from './Viewport.ViewHelper.js'; -import { VR } from './Viewport.VR.js'; - -import { SetPositionCommand } from './commands/SetPositionCommand.js'; -import { SetRotationCommand } from './commands/SetRotationCommand.js'; -import { SetScaleCommand } from './commands/SetScaleCommand.js'; - -import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js'; -import { ViewPanel } from './ViewPanel.js'; - - - -function Viewport(editor) { - - var signals = editor.signals; - - var container = new UIPanel(); - container.setId('viewport'); - container.setPosition('absolute'); - - - // - - var renderer = null; - var pmremGenerator = null; - - var camera = editor.camera; - var scene = editor.scene; - var sceneHelpers = editor.sceneHelpers; - - - var objects = []; - - // helpers - - var grid = new THREE.Group(); - - var grid1 = new THREE.GridHelper(30, 30, 0x888888); - grid1.material.color.setHex(0x888888); - grid1.material.vertexColors = false; - grid.add(grid1); - - var grid2 = new THREE.GridHelper(30, 6, 0x222222); - grid2.material.color.setHex(0x222222); - grid2.material.depthFunc = THREE.AlwaysDepth; - grid2.material.vertexColors = false; - grid.add(grid2); - - - - var vr = new VR( editor ); - - // - - var box = new THREE.Box3(); - - var selectionBox = new THREE.BoxHelper(); - selectionBox.material.depthTest = false; - selectionBox.material.transparent = true; - selectionBox.visible = false; - sceneHelpers.add(selectionBox); - - - let viewsGrid = new UIDiv(); - viewsGrid.setClass("grid"); - viewsGrid.setPosition("absolute"); - viewsGrid.setWidth("100%"); - viewsGrid.setHeight("100%"); - viewsGrid.setBackgroundColor("#aaaaaa"); - container.add(viewsGrid); - - - let view1 = new ViewPanel("ViewPanel1",editor,400, 400 ,{objects,grid,oldCamera:editor.viewportCamera,selectionBox, cameraPosition:new THREE.Vector3(0,0,10)}); - viewsGrid.add(view1.container); - - let gutterCol = new UIDiv().setClass("gutter-col gutter-col-1"); - viewsGrid.add(gutterCol); - - let view2 = new ViewPanel("ViewPanel2",editor,400, 400,{objects,grid,oldCamera:editor.viewportCamera,selectionBox}); - viewsGrid.add(view2.container); - - let view3 = new ViewPanel("ViewPanel3",editor,400, 400,{objects,grid,oldCamera:editor.viewportCamera,selectionBox, cameraPosition:new THREE.Vector3(0,10,0)}); - viewsGrid.add(view3.container); - - let gutterRow = new UIDiv().setClass("gutter-row gutter-row-1"); - viewsGrid.add(gutterRow); - - let view4 = new ViewPanel("ViewPanel4",editor,400, 400,{objects,grid,oldCamera:editor.viewportCamera,selectionBox, cameraPosition:new THREE.Vector3(10,0,0)}); - viewsGrid.add(view4.container); - - - let views = [view1, view2, view3,view4]; - - - Split({ - columnGutters: [{ - track: 1, - element: gutterCol.dom, - }], - rowGutters: [{ - track: 1, - element: gutterRow.dom, - }], - onDragEnd: (direction, track) => { - views.forEach((view) => view.setSize()); - - render(); - } - }) - - // events - - function updateAspectRatio() { - - camera.aspect = container.dom.offsetWidth / container.dom.offsetHeight; - camera.updateProjectionMatrix(); - - } - - - - // signals - - - signals.editorCleared.add(function () { - - views.forEach((view)=>view.controls.center.set(0, 0, 0)); - render(); - - }); - - - - signals.rendererUpdated.add(function () { - - scene.traverse(function (child) { - - if (child.material !== undefined) { - - child.material.needsUpdate = true; - - } - - }); - - render(); - - }); - - signals.rendererCreated.add(function (newRenderer) { - - if (renderer !== null) { - - renderer.setAnimationLoop(null); - renderer.dispose(); - pmremGenerator.dispose(); - - container.dom.removeChild(renderer.domElement); - - } - - renderer = newRenderer; - - renderer.setAnimationLoop(animate); - renderer.setClearColor(0xaaaaaa); - - if (window.matchMedia) { - - var mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); - mediaQuery.addListener(function (event) { - - renderer.setClearColor(event.matches ? 0x333333 : 0xaaaaaa); - updateGridColors(grid1, grid2, event.matches ? [0x222222, 0x888888] : [0x888888, 0x282828]); - - render(); - - }); - - renderer.setClearColor(mediaQuery.matches ? 0x333333 : 0xaaaaaa); - updateGridColors(grid1, grid2, mediaQuery.matches ? [0x222222, 0x888888] : [0x888888, 0x282828]); - - } - - renderer.setPixelRatio(window.devicePixelRatio); - renderer.setSize(container.dom.offsetWidth, container.dom.offsetHeight); - - pmremGenerator = new THREE.PMREMGenerator(renderer); - pmremGenerator.compileEquirectangularShader(); +import { ViewportCamera } from './Viewport.Camera.js'; +import { ViewportInfo } from './Viewport.Info.js'; - container.dom.appendChild(renderer.domElement); +import { UIPanel } from "./libs/ui"; +import { ViewHelper } from './Viewport.ViewHelper'; - render(); +export function Viewport(name, editor, { objects, grid, selectionBox }, cameraPosition) { - }); + let { scene, sceneHelpers, signals } = editor; - signals.sceneGraphChanged.add(function () { + let config = { + showSceneHelpers: true, + visible: false, + } - render(); + let sceneViewHelpers = new THREE.Scene(); - }); + let container = new UIPanel(); + container.setId('ViewPanel'); + container.setPosition('relative'); + container.setOverflow("hidden"); + container.dom.setAttribute('tabindex', '0'); - signals.cameraChanged.add(function () { + container.add(new ViewportCamera(editor)); + container.add(new ViewportInfo(editor)); - render(); + let canvas = document.createElement('canvas'); + container.dom.appendChild(canvas); + // canvas.width = canvas.height = 100; - }); + let context = canvas.getContext('2d'); - signals.objectSelected.add(function (object) { + let cameraPersp = new THREE.PerspectiveCamera(50, 1, 0.01, 1000); + cameraPersp.position.copy(cameraPosition ?? new THREE.Vector3(0, 5, 10)); + cameraPersp.lookAt(new THREE.Vector3()); - selectionBox.visible = false; + let cameraOrtho = new THREE.OrthographicCamera(1 / - 2, 1 / 2, 1 / 2, 1 / - 2, 1, 1000); + cameraOrtho.position.copy(cameraPersp.position); + cameraOrtho.lookAt(new THREE.Vector3()); + let camera = cameraPersp; + camera.name = name; + updateAspectRatio(); - if (object !== null && object !== scene && object !== camera) { + let viewHelper = new ViewHelper(camera, container); - box.setFromObject(object); + let cachedRenderer = null; - if (box.isEmpty() === false) { + function render(renderer = cachedRenderer) { + if (!config.visible) return; - selectionBox.setFromObject(object); - selectionBox.visible = true; + cachedRenderer = renderer; - } + if (!renderer) return; - } + // Adding/removing grid to scene so materials with depthWrite false + // don't render under the grid. + scene.add(grid); + renderer.setSize(canvas.width, canvas.height); + renderer.render(scene, camera); + scene.remove(grid); - render(); + renderer.autoClear = false; + if (config.showSceneHelpers) { + renderer.render(sceneHelpers, camera); + renderer.render(sceneViewHelpers, camera); + viewHelper.render(renderer); + } + renderer.autoClear = true; - }); + context.drawImage(renderer.domElement, 0, 0); - signals.objectFocused.add(function (object) { + }; - views.forEach((view)=>view.controls.focus(object)); + function animate(delta) { + if (!config.visible) return false; - }); + if (viewHelper.animating === true) { - signals.geometryChanged.add(function (object) { + viewHelper.update(delta); - if (object !== undefined) { + return true; + } - selectionBox.setFromObject(object); + return false; + } - } - render(); - }); + var objectPositionOnDown = null; + var objectRotationOnDown = null; + var objectScaleOnDown = null; - signals.objectAdded.add(function (object) { + var transformControls = new TransformControls(camera, container.dom); + transformControls.addEventListener('change', function () { - object.traverse(function (child) { + var object = transformControls.object; - objects.push(child); + if (object !== undefined) { - }); + selectionBox.setFromObject(object); - }); + var helper = editor.helpers[object.id]; - signals.objectChanged.add(function (object) { + if (helper !== undefined && helper.isSkeletonHelper !== true) { - if (editor.selected === object) { + helper.update(); - selectionBox.setFromObject(object); + } - } + signals.refreshSidebarObject3D.dispatch(object); - if (object.isPerspectiveCamera) { + } - object.updateProjectionMatrix(); + render(); - } + }); - if (editor.helpers[object.id] !== undefined) { + transformControls.addEventListener('mouseDown', function () { - editor.helpers[object.id].update(); + var object = transformControls.object; - } + objectPositionOnDown = object.position.clone(); + objectRotationOnDown = object.rotation.clone(); + objectScaleOnDown = object.scale.clone(); - render(); + controls.enabled = false; - }); - signals.objectRemoved.add(function (object) { + }); - object.traverse(function (child) { + transformControls.addEventListener('mouseUp', function () { - objects.splice(objects.indexOf(child), 1); + var object = transformControls.object; - }); + if (object !== undefined) { - }); + switch (transformControls.getMode()) { - signals.helperAdded.add(function (object) { + case 'translate': - var picker = object.getObjectByName('picker'); + if (!objectPositionOnDown.equals(object.position)) { - if (picker !== undefined) { + editor.execute(new SetPositionCommand(editor, object, object.position, objectPositionOnDown)); - objects.push(picker); + } - } + break; - }); + case 'rotate': - signals.helperRemoved.add(function (object) { + if (!objectRotationOnDown.equals(object.rotation)) { - var picker = object.getObjectByName('picker'); + editor.execute(new SetRotationCommand(editor, object, object.rotation, objectRotationOnDown)); - if (picker !== undefined) { + } - objects.splice(objects.indexOf(picker), 1); + break; - } + case 'scale': - }); + if (!objectScaleOnDown.equals(object.scale)) { - signals.materialChanged.add(function () { + editor.execute(new SetScaleCommand(editor, object, object.scale, objectScaleOnDown)); - render(); + } - }); + break; - signals.animationStopped.add(function () { + default: + console.error(transformControls.getMode()); + } - render(); + } - }); + controls.enabled = true; - // background + }); - signals.sceneBackgroundChanged.add(function (backgroundType, backgroundColor, backgroundTexture, backgroundEquirectangularTexture) { - switch (backgroundType) { + sceneViewHelpers.add(transformControls); - case 'None': - scene.background = null; + // object picking - break; + var raycaster = new THREE.Raycaster(); + var mouse = new THREE.Vector2(); - case 'Color': + function getIntersects(point, objects) { - scene.background = new THREE.Color(backgroundColor); + mouse.set((point.x * 2) - 1, - (point.y * 2) + 1); - break; + raycaster.setFromCamera(mouse, camera); - case 'Texture': + return raycaster.intersectObjects(objects) + .filter(intersect => intersect.object.visible === true); - if (backgroundTexture) { + } - scene.background = backgroundTexture; + var onDownPosition = new THREE.Vector2(); + var onUpPosition = new THREE.Vector2(); + var onDoubleClickPosition = new THREE.Vector2(); - } + function getMousePosition(dom, x, y) { - break; + var rect = dom.getBoundingClientRect(); + return [(x - rect.left) / rect.width, (y - rect.top) / rect.height]; - case 'Equirectangular': + } - if (backgroundEquirectangularTexture) { + // events - backgroundEquirectangularTexture.mapping = THREE.EquirectangularReflectionMapping; - scene.background = backgroundEquirectangularTexture; + function updateAspectRatio() { + const aspect = container.dom.offsetWidth / container.dom.offsetHeight; - } + cameraPersp.aspect = aspect; + cameraPersp.updateProjectionMatrix(); - break; + cameraOrtho.left = cameraOrtho.bottom * aspect; + cameraOrtho.right = cameraOrtho.top * aspect; + cameraOrtho.updateProjectionMatrix(); - } + } - render(); + function handleClick() { - }); + if (onDownPosition.distanceTo(onUpPosition) === 0) { - // environment + var intersects = getIntersects(onUpPosition, objects); - signals.sceneEnvironmentChanged.add(function (environmentType, environmentEquirectangularTexture) { + if (intersects.length > 0) { - switch (environmentType) { + var object = intersects[0].object; - case 'None': + if (object.userData.object !== undefined) { - scene.environment = null; + // helper - break; + editor.select(object.userData.object); - case 'Equirectangular': + } else { - scene.environment = null; + editor.select(object); - if (environmentEquirectangularTexture) { + } - environmentEquirectangularTexture.mapping = THREE.EquirectangularReflectionMapping; - scene.environment = environmentEquirectangularTexture; + transformControls.camera = camera; - } + } else { - break; + editor.select(null); - case 'ModelViewer': + } - scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture; + render(); - break; + } - } + } - render(); + function onMouseDown(event) { - }); + // event.preventDefault(); - // fog + var array = getMousePosition(container.dom, event.clientX, event.clientY); + onDownPosition.fromArray(array); - signals.sceneFogChanged.add(function (fogType, fogColor, fogNear, fogFar, fogDensity) { + document.addEventListener('mouseup', onMouseUp, false); - switch (fogType) { + } - case 'None': - scene.fog = null; - break; - case 'Fog': - scene.fog = new THREE.Fog(fogColor, fogNear, fogFar); - break; - case 'FogExp2': - scene.fog = new THREE.FogExp2(fogColor, fogDensity); - break; + function onMouseUp(event) { - } + var array = getMousePosition(container.dom, event.clientX, event.clientY); + onUpPosition.fromArray(array); - render(); + handleClick(); - }); + document.removeEventListener('mouseup', onMouseUp, false); - signals.sceneFogSettingsChanged.add(function (fogType, fogColor, fogNear, fogFar, fogDensity) { + } - switch (fogType) { + function onTouchStart(event) { - case 'Fog': - scene.fog.color.setHex(fogColor); - scene.fog.near = fogNear; - scene.fog.far = fogFar; - break; - case 'FogExp2': - scene.fog.color.setHex(fogColor); - scene.fog.density = fogDensity; - break; + var touch = event.changedTouches[0]; - } + var array = getMousePosition(container.dom, touch.clientX, touch.clientY); + onDownPosition.fromArray(array); - render(); + document.addEventListener('touchend', onTouchEnd, false); - }); + } - signals.viewportCameraChanged.add(function () { + function onTouchEnd(event) { - var viewportCamera = editor.viewportCamera; + var touch = event.changedTouches[0]; - if (viewportCamera.isPerspectiveCamera) { + var array = getMousePosition(container.dom, touch.clientX, touch.clientY); + onUpPosition.fromArray(array); - viewportCamera.aspect = editor.camera.aspect; - viewportCamera.projectionMatrix.copy(editor.camera.projectionMatrix); + handleClick(); - } else if (viewportCamera.isOrthographicCamera) { + document.removeEventListener('touchend', onTouchEnd, false); - // TODO + } - } + function onDoubleClick(event) { - // disable EditorControls when setting a user camera + var array = getMousePosition(container.dom, event.clientX, event.clientY); + onDoubleClickPosition.fromArray(array); - // controls.enabled = (viewportCamera === editor.camera); - // views.forEach((view)=>view.controls.enabled = true); + var intersects = getIntersects(onDoubleClickPosition, objects); - render(); + if (intersects.length > 0) { - }); + var intersect = intersects[0]; - signals.exitedVR.add( render ); + signals.objectFocused.dispatch(intersect.object); - // + } - signals.windowResize.add(function () { + } - views.forEach((view) => view.setSize()); - - render(); + container.dom.addEventListener('keydown', function (event) { - }); + switch (event.code) { + case 'KeyC': // C + const position = camera.position.clone(); - signals.showGridChanged.add(function (showGrid) { + camera = camera.isPerspectiveCamera ? cameraOrtho : cameraPersp; + camera.position.copy(position); - grid.visible = showGrid; - render(); + controls.object = camera; + transformControls.camera = camera; + viewHelper.editorCamera = camera; - }); + camera.lookAt(controls.center.x, controls.center.y, controls.center.z); + updateAspectRatio(); + break; + default: - signals.cameraResetted.add(updateAspectRatio); - // animations + } - var clock = new THREE.Clock(); // only used for animations + }); - function animate() { + container.dom.addEventListener('mousedown', onMouseDown, false); + container.dom.addEventListener('touchstart', onTouchStart, false); + container.dom.addEventListener('dblclick', onDoubleClick, false); - var mixer = editor.mixer; - var delta = clock.getDelta(); + // controls need to be added *after* main logic, + // otherwise controls.enabled doesn't work. - var needsUpdate = false; + var controls = new EditorControls(camera, container.dom); + controls.addEventListener('change', function () { - if (mixer.stats.actions.inUse > 0) { + signals.cameraChanged.dispatch(camera); + signals.refreshSidebarObject3D.dispatch(camera); - mixer.update(delta); - needsUpdate = true; + }); + viewHelper.controls = controls; - } - needsUpdate = views.map((view)=> view.animate(delta)).some(e => e); - + signals.transformModeChanged.add(function (mode) { - if ( vr.currentSession !== null ) { + transformControls.setMode(mode); - needsUpdate = true; + }); - } + signals.snapChanged.add(function (dist) { + transformControls.setTranslationSnap(dist); - if (needsUpdate === true) render(); + }); - } + signals.spaceChanged.add(function (space) { - // + transformControls.setSpace(space); - var startTime = 0; - var endTime = 0; + }); - function render() { + signals.objectSelected.add(function (object) { - startTime = performance.now(); - // Adding/removing grid to scene so materials with depthWrite false - // don't render under the grid. + transformControls.detach(); + if (object !== null && object !== scene && object !== camera) { + transformControls.attach(object); + } - views.forEach((view)=> view.render(renderer)); + render(); + }); - // renderer.setSize(container.dom.offsetWidth, container.dom.offsetHeight); - // renderer.render(scene, editor.viewportCamera); + signals.objectRemoved.add(function (object) { + controls.enabled = true; - // if (camera === editor.viewportCamera) { + if (object === transformControls.object) { - // renderer.autoClear = false; - // if ( showSceneHelpers === true ) renderer.render( sceneHelpers, camera ); - // renderer.autoClear = true; + transformControls.detach(); - // } + } + }); - endTime = performance.now(); - editor.signals.sceneRendered.dispatch(endTime - startTime); + signals.showHelpersChanged.add(function (showHelpers) { - } + transformControls.enabled = showHelpers; - return container; + render(); -} + }); -function updateGridColors(grid1, grid2, colors) { - grid1.material.color.setHex(colors[0]); - grid2.material.color.setHex(colors[1]); + function setSize(viewWidth = container.dom.offsetWidth, viewHeight = container.dom.offsetHeight) { + canvas.width = viewWidth; + canvas.height = viewHeight; + updateAspectRatio(); + } -} + return { + render, + container, + controls, + viewHelper, + animate, + setSize, + config + } -export { Viewport }; +} \ No newline at end of file diff --git a/src/ThreeEditor/js/ViewportManager.js b/src/ThreeEditor/js/ViewportManager.js index 4e6d98c28..f7e51dbca 100644 --- a/src/ThreeEditor/js/ViewportManager.js +++ b/src/ThreeEditor/js/ViewportManager.js @@ -1,27 +1,17 @@ import * as THREE from 'three' +import Split from 'split-grid' -import { TransformControls } from 'three/examples/jsm/controls/TransformControls'; +import { UIDiv, UIPanel } from './libs/ui.js'; -import { UIPanel } from './libs/ui.js'; - -import { EditorControls } from './EditorControls.js'; - -import { ViewportCamera } from './Viewport.Camera.js'; -import { ViewportInfo } from './Viewport.Info.js'; -import { ViewHelper } from './Viewport.ViewHelper.js'; import { VR } from './Viewport.VR.js'; -import { SetPositionCommand } from './commands/SetPositionCommand.js'; -import { SetRotationCommand } from './commands/SetRotationCommand.js'; -import { SetScaleCommand } from './commands/SetScaleCommand.js'; - import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js'; import { Viewport } from './Viewport.js'; -function ViewportManager(editor) { +function ViewManager(editor) { var signals = editor.signals; @@ -30,7 +20,6 @@ function ViewportManager(editor) { container.setPosition('absolute'); - // var renderer = null; @@ -39,14 +28,9 @@ function ViewportManager(editor) { var camera = editor.camera; var scene = editor.scene; var sceneHelpers = editor.sceneHelpers; - var showSceneHelpers = true; - - var objects = []; - - - + var objects = []; // helpers @@ -63,6 +47,7 @@ function ViewportManager(editor) { grid2.material.vertexColors = false; grid.add(grid2); + var vr = new VR(editor); // @@ -75,121 +60,101 @@ function ViewportManager(editor) { selectionBox.visible = false; sceneHelpers.add(selectionBox); - var objectPositionOnDown = null; - var objectRotationOnDown = null; - var objectScaleOnDown = null; - - function updateAspectRatio() { + // Four Views Layout - camera.aspect = container.dom.offsetWidth / container.dom.offsetHeight; - camera.updateProjectionMatrix(); + let viewsGrid = new UIDiv(); + viewsGrid.setClass("grid"); + viewsGrid.setPosition("absolute"); + viewsGrid.setWidth("100%"); + viewsGrid.setHeight("100%"); + viewsGrid.setBackgroundColor("#aaaaaa"); + container.add(viewsGrid); + let viewManagerProps = { + objects, + grid, + selectionBox } - var transformControls = new TransformControls(camera, container.dom); - transformControls.addEventListener('change', function () { + let viewZ = new Viewport("ViewPanel1", editor, viewManagerProps, new THREE.Vector3(0, 0, 10)); + viewsGrid.add(viewZ.container); - var object = transformControls.object; + let gutterCol = new UIDiv().setClass("gutter-col gutter-col-1"); + viewsGrid.add(gutterCol); - if (object !== undefined) { - - selectionBox.setFromObject(object); + let view3D = new Viewport("ViewPanel2", editor, viewManagerProps); + viewsGrid.add(view3D.container); - var helper = editor.helpers[object.id]; + let viewY = new Viewport("ViewPanel3", editor, viewManagerProps, new THREE.Vector3(0, 10, 0)); + viewsGrid.add(viewY.container); - if (helper !== undefined && helper.isSkeletonHelper !== true) { + let gutterRow = new UIDiv().setClass("gutter-row gutter-row-1"); + viewsGrid.add(gutterRow); - helper.update(); + let viewX = new Viewport("ViewPanel4", editor, viewManagerProps, new THREE.Vector3(10, 0, 0)); + viewsGrid.add(viewX.container); - } + // Add resizable views - signals.refreshSidebarObject3D.dispatch(object); + Split({ + columnGutters: [{ + track: 1, + element: gutterCol.dom, + }], + rowGutters: [{ + track: 1, + element: gutterRow.dom, + }], + onDragEnd: (direction, track) => { + views.forEach((view) => view.setSize()); + render(); } - - render(); - }); - transformControls.addEventListener('mouseDown', function () { - var object = transformControls.object; + let fourViews = [viewZ, view3D, viewY, viewX]; - objectPositionOnDown = object.position.clone(); - objectRotationOnDown = object.rotation.clone(); - objectScaleOnDown = object.scale.clone(); + // Single View Layout + let viewSingle = new UIDiv(); + viewSingle.setPosition("absolute"); + viewSingle.setWidth("100%"); + viewSingle.setHeight("100%"); + viewSingle.setBackgroundColor("#aaaaaa"); + container.add(viewSingle); + let viewport = new Viewport("ViewPanel", editor, viewManagerProps); + viewport.container.setPosition("absolute"); + viewport.container.setWidth("100%"); + viewport.container.setHeight("100%"); + viewSingle.add(viewport.container); - }); - transformControls.addEventListener('mouseUp', function () { + let singleView = [viewport]; - var object = transformControls.object; + let currentLayout = 'singleView'; - if (object !== undefined) { + let views = singleView; - switch (transformControls.getMode()) { - - case 'translate': - - if (!objectPositionOnDown.equals(object.position)) { - - editor.execute(new SetPositionCommand(editor, object, object.position, objectPositionOnDown)); - - } - - break; - - case 'rotate': - - if (!objectRotationOnDown.equals(object.rotation)) { - - editor.execute(new SetRotationCommand(editor, object, object.rotation, objectRotationOnDown)); - - } - - break; - - case 'scale': - - if (!objectScaleOnDown.equals(object.scale)) { - - editor.execute(new SetScaleCommand(editor, object, object.scale, objectScaleOnDown)); - - } - - break; - - } - - } + views.forEach((view) => view.config.visible = true); + + // events - }); - - sceneHelpers.add(transformControls); + function updateAspectRatio() { + camera.aspect = container.dom.offsetWidth / container.dom.offsetHeight; + camera.updateProjectionMatrix(); + } // signals + signals.editorCleared.add(function () { - signals.transformModeChanged.add(function (mode) { - - transformControls.setMode(mode); - - }); - - signals.snapChanged.add(function (dist) { - - transformControls.setTranslationSnap(dist); - - }); - - signals.spaceChanged.add(function (space) { - - transformControls.setSpace(space); + views.forEach((view) => view.controls.center.set(0, 0, 0)); + render(); }); @@ -270,7 +235,7 @@ function ViewportManager(editor) { signals.objectSelected.add(function (object) { selectionBox.visible = false; - transformControls.detach(); + if (object !== null && object !== scene && object !== camera) { @@ -283,15 +248,17 @@ function ViewportManager(editor) { } - transformControls.attach(object); - } render(); }); + signals.objectFocused.add(function (object) { + views.forEach((view) => view.controls.focus(object)); + + }); signals.geometryChanged.add(function (object) { @@ -339,7 +306,15 @@ function ViewportManager(editor) { }); + signals.objectRemoved.add(function (object) { + + object.traverse(function (child) { + + objects.splice(objects.indexOf(child), 1); + + }); + }); signals.helperAdded.add(function (object) { @@ -516,7 +491,10 @@ function ViewportManager(editor) { } + // disable EditorControls when setting a user camera + // controls.enabled = (viewportCamera === editor.camera); + // views.forEach((view)=>view.controls.enabled = true); render(); @@ -528,9 +506,7 @@ function ViewportManager(editor) { signals.windowResize.add(function () { - updateAspectRatio(); - - renderer.setSize(container.dom.offsetWidth, container.dom.offsetHeight); + views.forEach((view) => view.setSize()); render(); @@ -543,16 +519,40 @@ function ViewportManager(editor) { }); - signals.showHelpersChanged.add(function (showHelpers) { - showSceneHelpers = showHelpers; - transformControls.enabled = showHelpers; + signals.cameraResetted.add(updateAspectRatio); - render(); + // Layout + + editor.signals.layoutChanged.add(function (layout) { + currentLayout = layout; + + viewsGrid.setDisplay('none'); + viewSingle.setDisplay('none'); + views.forEach((view) => view.config.visible = false); + + switch (layout) { + case 'fourViews': + views = fourViews; + viewsGrid.dom.style.display = null; + break; + + case 'singleView': + default: + currentLayout = 'singleView'; + views = singleView; + viewSingle.dom.style.display = null; + + } + + views.forEach((view) => view.setSize()); + views.forEach((view) => view.config.visible = true); + + render(); + }); - signals.cameraResetted.add(updateAspectRatio); // animations @@ -572,6 +572,8 @@ function ViewportManager(editor) { } + needsUpdate = views.map((view) => view.animate(delta)).some(e => e); + if (vr.currentSession !== null) { @@ -593,27 +595,7 @@ function ViewportManager(editor) { startTime = performance.now(); - // Adding/removing grid to scene so materials with depthWrite false - // don't render under the grid. - - scene.add(grid); - renderer.setViewport(0, 0, container.dom.offsetWidth, container.dom.offsetHeight); - renderer.render(scene, editor.viewportCamera); - - views.forEach((view) => { - console.log(view) - view.render() - }); - scene.remove(grid); - - if (camera === editor.viewportCamera) { - - renderer.autoClear = false; - if (showSceneHelpers === true) renderer.render(sceneHelpers, camera); - - renderer.autoClear = true; - - } + views.forEach((view) => view.render(renderer)); endTime = performance.now(); editor.signals.sceneRendered.dispatch(endTime - startTime); @@ -631,4 +613,4 @@ function updateGridColors(grid1, grid2, colors) { } -export { ViewportManager }; +export { ViewManager }; diff --git a/src/ThreeEditor/main.js b/src/ThreeEditor/main.js index 9393dd874..9a44bca6f 100644 --- a/src/ThreeEditor/main.js +++ b/src/ThreeEditor/main.js @@ -1,7 +1,7 @@ import * as THREE from 'three'; import { Editor } from './js/Editor.js'; -import { Viewport } from './js/Viewport.js'; +import { ViewManager } from './js/ViewportManager.js'; import { Toolbar } from './js/Toolbar.js'; import { Sidebar } from './js/Sidebar.js'; import { Menubar } from './js/Menubar.js'; @@ -28,8 +28,8 @@ export function initEditor(container) { window.editor = editor; // Expose editor to Console window.THREE = THREE; // Expose THREE to APP Scripts and Console - var viewport = new Viewport(editor); - container.appendChild(viewport.dom); + var viewManager = new ViewManager(editor); + container.appendChild(viewManager.dom); var toolbar = new Toolbar(editor); container.appendChild(toolbar.dom); @@ -178,6 +178,6 @@ export function initEditor(container) { } - return { editor, viewport, toolbar, sidebar, menubar, resizer } + return { editor, viewport: viewManager, toolbar, sidebar, menubar, resizer } }