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.
 
 
 
 
 

757 lines
13 KiB

import * as THREE from 'three';
import { Config } from './Config.js';
import { Loader } from './Loader.js';
import { History as _History } from './History.js';
import { Strings } from './Strings.js';
import { Storage as _Storage } from './Storage.js';
import { Selector } from './Viewport.Selector.js';
var _DEFAULT_CAMERA = new THREE.PerspectiveCamera(50, 1, 0.01, 1000);
_DEFAULT_CAMERA.name = 'Camera';
_DEFAULT_CAMERA.position.set(0, 5, 10);
_DEFAULT_CAMERA.lookAt(new THREE.Vector3());
function Editor() {
const Signal = signals.Signal; // eslint-disable-line no-undef
this.signals = {
// script
editScript: new Signal(),
// player
startPlayer: new Signal(),
stopPlayer: new Signal(),
// vr
toggleVR: new Signal(),
exitedVR: new Signal(),
// notifications
editorCleared: new Signal(),
savingStarted: new Signal(),
savingFinished: new Signal(),
transformModeChanged: new Signal(),
snapChanged: new Signal(),
spaceChanged: new Signal(),
rendererCreated: new Signal(),
rendererUpdated: new Signal(),
rendererCSSCreated: new Signal(),
rendererCSSUpdated: new Signal(),
sceneBackgroundChanged: new Signal(),
sceneEnvironmentChanged: new Signal(),
sceneFogChanged: new Signal(),
sceneFogSettingsChanged: new Signal(),
sceneGraphChanged: new Signal(),
sceneRendered: new Signal(),
cameraChanged: new Signal(),
cameraResetted: new Signal(),
geometryChanged: new Signal(),
objectSelected: new Signal(),
objectFocused: new Signal(),
objectAdded: new Signal(),
objectChanged: new Signal(),
objectRemoved: new Signal(),
cameraAdded: new Signal(),
cameraRemoved: new Signal(),
helperAdded: new Signal(),
helperRemoved: new Signal(),
materialAdded: new Signal(),
materialChanged: new Signal(),
materialRemoved: new Signal(),
scriptAdded: new Signal(),
scriptChanged: new Signal(),
scriptRemoved: new Signal(),
windowResize: new Signal(),
showGridChanged: new Signal(),
showHelpersChanged: new Signal(),
refreshSidebarObject3D: new Signal(),
historyChanged: new Signal(),
viewportCameraChanged: new Signal(),
intersectionsDetected: new Signal(),
render: new Signal(),
};
this.config = new Config();
this.history = new _History(this);
this.storage = new _Storage();
this.strings = new Strings(this.config);
console.log("language=", this.config.getKey("language"));
this.selector = new Selector(this);
this.loader = new Loader(this);
this.camera = _DEFAULT_CAMERA.clone();
this.scene = new THREE.Scene();
this.scene.name = 'Scene';
this.sceneHelpers = new THREE.Scene();
this.object = {};
this.geometries = {};
this.materials = {};
this.textures = {};
this.scripts = {};
this.materialsRefCounter = new Map(); // tracks how often is a material used by a 3D object
this.mixer = new THREE.AnimationMixer(this.scene);
this.selected = null;
this.helpers = {};
this.cameras = {};
this.labellist = [];
this.monitoringlist = [];
this.viewportCamera = this.camera;
this.addCamera(this.camera);
}
Editor.prototype = {
addBuilding: function (building) {
this.removeBuilding()
this._building = building
this.scene.add(building)
this.signals.objectAdded.dispatch(building);
this.signals.sceneGraphChanged.dispatch();
},
removeBuilding: function () {
if (this._building) {
let building = this._building
this.scene.remove(this._building)
this._building = null
// this.signals.objectRemoved.dispatch(building)
// this.signals.sceneGraphChanged.dispatch();
}
},
setScene: function (scene) {
this.scene.uuid = scene.uuid;
this.scene.name = scene.name;
this.scene.background = scene.background;
this.scene.environment = scene.environment;
this.scene.fog = scene.fog;
this.scene.userData = JSON.parse(JSON.stringify(scene.userData));
// avoid render per object
this.signals.sceneGraphChanged.active = false;
while (scene.children.length > 0) {
this.addObject(scene.children[0]);
}
this.signals.sceneGraphChanged.active = true;
this.signals.sceneGraphChanged.dispatch();
},
//
addObject: function (object, parent, index) {
var scope = this;
object.traverse(function (child) {
if (child.geometry !== undefined) scope.addGeometry(child.geometry);
if (child.material !== undefined) scope.addMaterial(child.material);
scope.addCamera(child);
scope.addHelper(child);
});
if (parent === undefined) {
this.scene.add(object);
} else {
parent.children.splice(index, 0, object);
object.parent = parent;
}
this.signals.objectAdded.dispatch(object);
this.signals.sceneGraphChanged.dispatch();
},
addLable: function (object, parent, index) {
// debugger
// this.labellist.push(object);
},
moveObject: function (object, parent, before) {
if (parent === undefined) {
parent = this.scene;
}
parent.add(object);
// sort children array
if (before !== undefined) {
var index = parent.children.indexOf(before);
parent.children.splice(index, 0, object);
parent.children.pop();
}
this.signals.sceneGraphChanged.dispatch();
},
nameObject: function (object, name) {
object.name = name;
this.signals.sceneGraphChanged.dispatch();
},
removeObject: function (object) {
if (object.parent === null) return; // avoid deleting the camera or scene
var scope = this;
object.traverse(function (child) {
scope.removeCamera(child);
scope.removeHelper(child);
if (child.material !== undefined) scope.removeMaterial(child.material);
});
object.parent.remove(object);
this.signals.objectRemoved.dispatch(object);
this.signals.sceneGraphChanged.dispatch();
},
addGeometry: function (geometry) {
this.geometries[geometry.uuid] = geometry;
},
setGeometryName: function (geometry, name) {
geometry.name = name;
this.signals.sceneGraphChanged.dispatch();
},
addMaterial: function (material) {
if (Array.isArray(material)) {
for (var i = 0, l = material.length; i < l; i++) {
this.addMaterialToRefCounter(material[i]);
}
} else {
this.addMaterialToRefCounter(material);
}
this.signals.materialAdded.dispatch();
},
addMaterialToRefCounter: function (material) {
var materialsRefCounter = this.materialsRefCounter;
var count = materialsRefCounter.get(material);
if (count === undefined) {
materialsRefCounter.set(material, 1);
this.materials[material.uuid] = material;
} else {
count++;
materialsRefCounter.set(material, count);
}
},
removeMaterial: function (material) {
if (Array.isArray(material)) {
for (var i = 0, l = material.length; i < l; i++) {
this.removeMaterialFromRefCounter(material[i]);
}
} else {
this.removeMaterialFromRefCounter(material);
}
this.signals.materialRemoved.dispatch();
},
removeMaterialFromRefCounter: function (material) {
var materialsRefCounter = this.materialsRefCounter;
var count = materialsRefCounter.get(material);
count--;
if (count === 0) {
materialsRefCounter.delete(material);
delete this.materials[material.uuid];
} else {
materialsRefCounter.set(material, count);
}
},
getMaterialById: function (id) {
var material;
var materials = Object.values(this.materials);
for (var i = 0; i < materials.length; i++) {
if (materials[i].id === id) {
material = materials[i];
break;
}
}
return material;
},
setMaterialName: function (material, name) {
material.name = name;
this.signals.sceneGraphChanged.dispatch();
},
addTexture: function (texture) {
this.textures[texture.uuid] = texture;
},
//
addCamera: function (camera) {
if (camera.isCamera) {
this.cameras[camera.uuid] = camera;
this.signals.cameraAdded.dispatch(camera);
}
},
removeCamera: function (camera) {
if (this.cameras[camera.uuid] !== undefined) {
delete this.cameras[camera.uuid];
this.signals.cameraRemoved.dispatch(camera);
}
},
//
addHelper: function () {
var geometry = new THREE.SphereGeometry(2, 4, 2);
var material = new THREE.MeshBasicMaterial({ color: 0xff0000, visible: false });
return function (object, helper) {
if (helper === undefined) {
if (object.isCamera) {
helper = new THREE.CameraHelper(object);
} else if (object.isPointLight) {
helper = new THREE.PointLightHelper(object, 1);
} else if (object.isDirectionalLight) {
helper = new THREE.DirectionalLightHelper(object, 1);
} else if (object.isSpotLight) {
helper = new THREE.SpotLightHelper(object);
} else if (object.isHemisphereLight) {
helper = new THREE.HemisphereLightHelper(object, 1);
} else if (object.isSkinnedMesh) {
helper = new THREE.SkeletonHelper(object.skeleton.bones[0]);
} else if (object.isBone === true && object.parent?.isBone !== true) {
helper = new THREE.SkeletonHelper(object);
} else {
// no helper for this object type
return;
}
const picker = new THREE.Mesh(geometry, material);
picker.name = 'picker';
picker.userData.object = object;
helper.add(picker);
}
this.sceneHelpers.add(helper);
this.helpers[object.id] = helper;
this.signals.helperAdded.dispatch(helper);
};
}(),
removeHelper: function (object) {
if (this.helpers[object.id] !== undefined) {
var helper = this.helpers[object.id];
helper.parent.remove(helper);
delete this.helpers[object.id];
this.signals.helperRemoved.dispatch(helper);
}
},
//
addScript: function (object, script) {
if (this.scripts[object.uuid] === undefined) {
this.scripts[object.uuid] = [];
}
this.scripts[object.uuid].push(script);
this.signals.scriptAdded.dispatch(script);
},
removeScript: function (object, script) {
if (this.scripts[object.uuid] === undefined) return;
var index = this.scripts[object.uuid].indexOf(script);
if (index !== - 1) {
this.scripts[object.uuid].splice(index, 1);
}
this.signals.scriptRemoved.dispatch(script);
},
getObjectMaterial: function (object, slot) {
var material = object.material;
if (Array.isArray(material) && slot !== undefined) {
material = material[slot];
}
return material;
},
setObjectMaterial: function (object, slot, newMaterial) {
if (Array.isArray(object.material) && slot !== undefined) {
object.material[slot] = newMaterial;
} else {
object.material = newMaterial;
}
},
setViewportCamera: function (uuid) {
this.viewportCamera = this.cameras[uuid];
this.signals.viewportCameraChanged.dispatch();
},
//
select: function (object) {
this.selector.select(object);
},
selectById: function (id) {
if (id === this.camera.id) {
this.select(this.camera);
return;
}
this.select(this.scene.getObjectById(id));
},
selectByUuid: function (uuid) {
var scope = this;
this.scene.traverse(function (child) {
if (child.uuid === uuid) {
scope.select(child);
}
});
},
deselect: function () {
this.selector.deselect();
},
focus: function (object) {
if (object !== undefined) {
this.signals.objectFocused.dispatch(object);
}
},
focusById: function (id) {
this.focus(this.scene.getObjectById(id));
},
clear: function () {
this.history.clear();
this.storage.clear();
this.camera.copy(_DEFAULT_CAMERA);
this.signals.cameraResetted.dispatch();
this.scene.name = 'Scene';
this.scene.userData = {};
this.scene.background = null;
this.scene.environment = null;
this.scene.fog = null;
var objects = this.scene.children;
while (objects.length > 0) {
this.removeObject(objects[0]);
}
this.geometries = {};
this.materials = {};
this.textures = {};
this.scripts = {};
this.materialsRefCounter.clear();
this.animations = {};
this.mixer.stopAllAction();
this.deselect();
this.signals.editorCleared.dispatch();
this.labellist = [];
this.monitoringlist = [];
},
//
fromJSON: async function (json) {
var loader = new THREE.ObjectLoader();
var camera = await loader.parseAsync(json.camera);
this.camera.copy(camera);
this.signals.cameraResetted.dispatch();
this.history.fromJSON(json.history);
this.scripts = json.scripts;
this.setScene(await loader.parseAsync(json.scene));
},
toJSON: function () {
// scripts clean up
var scene = this.scene;
var scripts = this.scripts;
// debugger
for (var key in scripts) {
var script = scripts[key];
if (script.length === 0 || scene.getObjectByProperty('uuid', key) === undefined) {
delete scripts[key];
}
}
//
return {
metadata: {},
project: {
shadows: this.config.getKey('project/renderer/shadows'),
shadowType: this.config.getKey('project/renderer/shadowType'),
vr: this.config.getKey('project/vr'),
physicallyCorrectLights: this.config.getKey('project/renderer/physicallyCorrectLights'),
toneMapping: this.config.getKey('project/renderer/toneMapping'),
toneMappingExposure: this.config.getKey('project/renderer/toneMappingExposure')
},
camera: this.camera.toJSON(),
scene: this.scene.toJSON(),
scripts: this.scripts,
history: this.history.toJSON(),
labels: this.labellist,
};
},
objectByUuid: function (uuid) {
return this.scene.getObjectByProperty('uuid', uuid, true);
},
execute: function (cmd, optionalName) {
this.history.execute(cmd, optionalName);
},
undo: function () {
this.history.undo();
},
redo: function () {
this.history.redo();
}
};
export { Editor };