ShadowEditor/editor/js/Editor.js
2018-06-07 19:50:07 +08:00

539 lines
11 KiB
JavaScript

/**
* @author mrdoob / http://mrdoob.com/
*/
var Editor = function () {
this.DEFAULT_CAMERA = new THREE.PerspectiveCamera(50, 1, 0.1, 10000);
this.DEFAULT_CAMERA.name = 'Camera';
this.DEFAULT_CAMERA.position.set(20, 10, 20);
this.DEFAULT_CAMERA.lookAt(new THREE.Vector3());
var Signal = signals.Signal;
this.signals = {
// script
editScript: new Signal(),
// player
startPlayer: new Signal(),
stopPlayer: new Signal(),
// vr
enterVR: new Signal(),
enteredVR: new Signal(),
exitedVR: new Signal(),
// actions
showModal: new Signal(),
// notifications
editorCleared: new Signal(),
savingStarted: new Signal(),
savingFinished: new Signal(),
themeChanged: new Signal(),
transformModeChanged: new Signal(),
snapChanged: new Signal(),
spaceChanged: new Signal(),
rendererChanged: new Signal(),
sceneBackgroundChanged: new Signal(),
sceneFogChanged: new Signal(),
sceneGraphChanged: new Signal(),
cameraChanged: new Signal(),
geometryChanged: new Signal(),
objectSelected: new Signal(),
objectFocused: new Signal(),
objectAdded: new Signal(),
objectChanged: new Signal(),
objectRemoved: new Signal(),
helperAdded: new Signal(),
helperRemoved: new Signal(),
materialChanged: new Signal(),
scriptAdded: new Signal(),
scriptChanged: new Signal(),
scriptRemoved: new Signal(),
windowResize: new Signal(),
showGridChanged: new Signal(),
refreshSidebarObject3D: new Signal(),
historyChanged: new Signal(),
refreshScriptEditor: new Signal()
};
this.config = new Config('threejs-editor');
this.history = new History(this);
this.storage = new Storage();
this.loader = new Loader(this);
this.camera = this.DEFAULT_CAMERA.clone();
this.scene = new THREE.Scene();
this.scene.name = 'Scene';
this.scene.background = new THREE.Color(0xaaaaaa);
this.sceneHelpers = new THREE.Scene();
this.object = {};
this.geometries = {};
this.materials = {};
this.textures = {};
this.scripts = {};
this.selected = null;
this.helpers = {};
};
Editor.prototype = {
setTheme: function (value) {
document.getElementById('theme').href = value;
this.signals.themeChanged.dispatch(value);
},
//
setScene: function (scene) {
this.scene.uuid = scene.uuid;
this.scene.name = scene.name;
if (scene.background !== null) this.scene.background = scene.background.clone();
if (scene.fog !== null) this.scene.fog = scene.fog.clone();
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) {
var scope = this;
object.traverse(function (child) {
if (child.geometry !== undefined) scope.addGeometry(child.geometry);
if (child.material !== undefined) scope.addMaterial(child.material);
scope.addHelper(child);
});
this.scene.add(object);
this.signals.objectAdded.dispatch(object);
this.signals.sceneGraphChanged.dispatch();
},
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.removeHelper(child);
});
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) {
this.materials[material.uuid] = material;
},
setMaterialName: function (material, name) {
material.name = name;
this.signals.sceneGraphChanged.dispatch();
},
addTexture: function (texture) {
this.textures[texture.uuid] = texture;
},
//
addHelper: function () {
var geometry = new THREE.SphereBufferGeometry(2, 4, 2);
var material = new THREE.MeshBasicMaterial({ color: 0xff0000, visible: false });
return function (object) {
var helper;
if (object instanceof THREE.Camera) {
helper = new THREE.CameraHelper(object, 1);
} else if (object instanceof THREE.PointLight) {
helper = new THREE.PointLightHelper(object, 1);
} else if (object instanceof THREE.DirectionalLight) {
helper = new THREE.DirectionalLightHelper(object, 1);
} else if (object instanceof THREE.SpotLight) {
helper = new THREE.SpotLightHelper(object, 1);
} else if (object instanceof THREE.HemisphereLight) {
helper = new THREE.HemisphereLightHelper(object, 1);
} else if (object instanceof THREE.SkinnedMesh) {
helper = new THREE.SkeletonHelper(object);
} else {
// no helper for this object type
return;
}
var 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);
},
//
select: function (object) {
if (this.selected === object) return;
var uuid = null;
if (object !== null) {
uuid = object.uuid;
}
this.selected = object;
this.config.setKey('selected', uuid);
this.signals.objectSelected.dispatch(object);
},
selectById: function (id) {
if (id === this.camera.id) {
this.select(this.camera);
return;
}
this.select(this.scene.getObjectById(id, true));
},
selectByUuid: function (uuid) {
var scope = this;
this.scene.traverse(function (child) {
if (child.uuid === uuid) {
scope.select(child);
}
});
},
deselect: function () {
this.select(null);
},
focus: function (object) {
this.signals.objectFocused.dispatch(object);
},
focusById: function (id) {
this.focus(this.scene.getObjectById(id, true));
},
clear: function () {
this.history.clear();
this.storage.clear();
this.camera.copy(this.DEFAULT_CAMERA);
this.scene.background.setHex(0xaaaaaa);
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.deselect();
this.signals.editorCleared.dispatch();
},
//
fromJSON: function (json) {
var loader = new THREE.ObjectLoader();
// backwards
if (json.scene === undefined) {
this.setScene(loader.parse(json));
return;
}
var camera = loader.parse(json.camera);
this.camera.copy(camera);
this.camera.aspect = this.DEFAULT_CAMERA.aspect;
this.camera.updateProjectionMatrix();
this.history.fromJSON(json.history);
this.scripts = json.scripts;
this.setScene(loader.parse(json.scene));
},
toJSON: function () {
// scripts clean up
var scene = this.scene;
var scripts = this.scripts;
for (var key in scripts) {
var script = scripts[key];
if (script.length === 0 || scene.getObjectByProperty('uuid', key) === undefined) {
delete scripts[key];
}
}
//
return {
metadata: {},
project: {
gammaInput: this.config.getKey('project/renderer/gammaInput'),
gammaOutput: this.config.getKey('project/renderer/gammaOutput'),
shadows: this.config.getKey('project/renderer/shadows'),
vr: this.config.getKey('project/vr')
},
camera: this.camera.toJSON(),
scene: this.scene.toJSON(),
scripts: this.scripts,
history: this.history.toJSON()
};
},
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();
}
};