2017-01-10 17:04:30 +01:00
|
|
|
/**
|
|
|
|
* Input parent class
|
|
|
|
* @param graphics GameLib.D3.Graphics
|
|
|
|
* @param apiInputEditor GameLib.D3.API.Input.Editor
|
2017-01-12 17:40:17 +01:00
|
|
|
* @param dom GameLib.DOM
|
2017-01-10 17:04:30 +01:00
|
|
|
* @constructor
|
|
|
|
*/
|
|
|
|
GameLib.D3.Input.Editor = function (
|
|
|
|
graphics,
|
2017-01-12 17:40:17 +01:00
|
|
|
apiInputEditor,
|
|
|
|
dom
|
2017-01-10 17:04:30 +01:00
|
|
|
) {
|
|
|
|
|
|
|
|
this.graphics = graphics;
|
|
|
|
this.graphics.isNotThreeThrow();
|
|
|
|
|
2017-01-12 17:40:17 +01:00
|
|
|
if (GameLib.Utils.UndefinedOrNull(apiInputEditor)) {
|
|
|
|
apiInputEditor = {};
|
|
|
|
}
|
|
|
|
|
2017-01-10 17:04:30 +01:00
|
|
|
GameLib.D3.API.Input.Editor.call(
|
|
|
|
this,
|
|
|
|
apiInputEditor.id,
|
|
|
|
apiInputEditor.name,
|
2017-02-21 18:55:18 +01:00
|
|
|
apiInputEditor.domElement,
|
|
|
|
apiInputEditor.domContainer,
|
2017-01-12 17:40:17 +01:00
|
|
|
apiInputEditor.editor,
|
2017-01-10 17:04:30 +01:00
|
|
|
apiInputEditor.camera,
|
2017-01-12 17:40:17 +01:00
|
|
|
apiInputEditor.widthOffset,
|
|
|
|
apiInputEditor.heightOffset,
|
|
|
|
apiInputEditor.containerWidthOffset,
|
|
|
|
apiInputEditor.containerHeightOffset,
|
2017-01-17 13:24:45 +01:00
|
|
|
apiInputEditor.selectDelayMs,
|
2017-01-10 17:04:30 +01:00
|
|
|
apiInputEditor.parentEntity
|
|
|
|
);
|
2017-01-11 16:09:06 +01:00
|
|
|
|
2017-01-12 17:40:17 +01:00
|
|
|
if (GameLib.Utils.UndefinedOrNull(dom)) {
|
2017-02-21 18:55:18 +01:00
|
|
|
console.warn('Cannot create window resize event without handle to the DOM');
|
|
|
|
dom = null;
|
|
|
|
// throw new Error('Cannot create Input without an handle to the DOM');
|
2017-01-12 17:40:17 +01:00
|
|
|
}
|
|
|
|
this.dom = dom;
|
|
|
|
|
2017-02-21 18:55:18 +01:00
|
|
|
if (this.domElement instanceof GameLib.API.DomElement) {
|
|
|
|
this.domElement = new GameLib.DomElement(
|
|
|
|
this.graphics,
|
|
|
|
this.domElement
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.domContainer instanceof GameLib.API.DomElement) {
|
|
|
|
this.domContainer = new GameLib.DomElement(
|
|
|
|
this.graphics,
|
|
|
|
this.domContainer
|
|
|
|
)
|
|
|
|
}
|
2017-01-12 17:40:17 +01:00
|
|
|
|
2017-01-13 16:19:51 +01:00
|
|
|
this.meshMoveMode = false;
|
|
|
|
this.meshMoveXMode = false;
|
|
|
|
this.meshMoveYMode = false;
|
|
|
|
this.meshMoveZMode = false;
|
|
|
|
|
2017-01-12 17:40:17 +01:00
|
|
|
/**
|
|
|
|
* We need new function pointers with scope bound to this so we can remove the
|
|
|
|
* window event handlers when we need to
|
|
|
|
* @type {function()}
|
|
|
|
*/
|
|
|
|
this.resize = this.onWindowResize.bind(this);
|
|
|
|
this.mouseMove = this.onMouseMove.bind(this);
|
|
|
|
this.mouseDown = this.onMouseDown.bind(this);
|
|
|
|
this.keyPress = this.onKeyPress.bind(this);
|
|
|
|
this.contextMenu = this.onContextMenu.bind(this);
|
2017-01-11 16:09:06 +01:00
|
|
|
|
2017-01-17 13:24:45 +01:00
|
|
|
this.raycaster = new GameLib.D3.Raycaster(
|
|
|
|
this.graphics
|
|
|
|
);
|
|
|
|
|
2017-01-17 17:16:10 +01:00
|
|
|
this.mouse = new GameLib.Mouse(
|
|
|
|
this.graphics
|
|
|
|
);
|
|
|
|
|
2017-01-19 17:50:11 +01:00
|
|
|
this.buildIdToObject();
|
|
|
|
|
2017-01-10 17:04:30 +01:00
|
|
|
this.instance = this.createInstance();
|
|
|
|
};
|
|
|
|
|
|
|
|
GameLib.D3.Input.Editor.prototype = Object.create(GameLib.D3.API.Input.Editor.prototype);
|
|
|
|
GameLib.D3.Input.Editor.prototype.constructor = GameLib.D3.Input.Editor;
|
|
|
|
|
|
|
|
GameLib.D3.Input.Editor.prototype.createInstance = function(update) {
|
|
|
|
|
2017-01-13 16:19:51 +01:00
|
|
|
var instance = null;
|
|
|
|
|
|
|
|
if (update) {
|
|
|
|
instance = this.instance;
|
|
|
|
instance.camera = this.camera.instance;
|
|
|
|
return instance;
|
|
|
|
} else {
|
|
|
|
instance = new THREE.EditorControls(
|
|
|
|
this.camera.instance,
|
2017-02-21 18:55:18 +01:00
|
|
|
this.domElement.instance
|
2017-01-13 16:19:51 +01:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2017-02-21 18:55:18 +01:00
|
|
|
this.domElement.instance.addEventListener(
|
2017-01-12 17:40:17 +01:00
|
|
|
'mousemove',
|
|
|
|
this.mouseMove,
|
|
|
|
false
|
|
|
|
);
|
2017-01-10 17:04:30 +01:00
|
|
|
|
2017-02-21 18:55:18 +01:00
|
|
|
this.domElement.instance.addEventListener(
|
2017-01-12 17:40:17 +01:00
|
|
|
'contextmenu',
|
|
|
|
this.contextMenu,
|
|
|
|
false
|
|
|
|
);
|
2017-01-10 17:04:30 +01:00
|
|
|
|
2017-02-21 18:55:18 +01:00
|
|
|
this.domElement.instance.addEventListener(
|
2017-01-12 17:40:17 +01:00
|
|
|
'mousedown',
|
|
|
|
this.mouseDown,
|
|
|
|
false
|
|
|
|
);
|
2017-01-10 17:04:30 +01:00
|
|
|
|
2017-02-21 18:55:18 +01:00
|
|
|
this.domElement.instance.addEventListener(
|
2017-01-12 17:40:17 +01:00
|
|
|
'keydown',
|
|
|
|
this.keyPress,
|
|
|
|
false
|
|
|
|
);
|
|
|
|
|
2017-02-21 18:55:18 +01:00
|
|
|
//TODO : window resize
|
|
|
|
// this.dom.window.addEventListener(
|
|
|
|
// 'resize',
|
|
|
|
// this.resize,
|
|
|
|
// false
|
|
|
|
// );
|
2017-01-10 17:04:30 +01:00
|
|
|
|
|
|
|
return instance;
|
|
|
|
};
|
|
|
|
|
|
|
|
GameLib.D3.Input.Editor.prototype.updateInstance = function() {
|
|
|
|
this.instance = this.createInstance(true);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* GameLib.D3.Input.Editor to GameLib.D3.API.Input.Editor
|
|
|
|
* @returns {GameLib.D3.API.Input.Editor}
|
|
|
|
*/
|
|
|
|
GameLib.D3.Input.Editor.prototype.toApiComponent = function() {
|
|
|
|
|
|
|
|
var apiInputEditor = new GameLib.D3.API.Input.Editor(
|
|
|
|
this.id,
|
|
|
|
this.name,
|
|
|
|
this.domElementId,
|
2017-01-13 16:19:51 +01:00
|
|
|
this.domContainerId,
|
2017-01-12 17:40:17 +01:00
|
|
|
GameLib.Utils.IdOrNull(this.editor),
|
|
|
|
GameLib.Utils.IdOrNull(this.camera),
|
2017-01-13 16:19:51 +01:00
|
|
|
this.widthOffset,
|
|
|
|
this.heightOffset,
|
|
|
|
this.containerWidthOffset,
|
|
|
|
this.containerHeightOffset,
|
2017-01-17 13:24:45 +01:00
|
|
|
this.selectDelayMs,
|
2017-01-12 17:40:17 +01:00
|
|
|
GameLib.Utils.IdOrNull(this.parentEntity)
|
2017-01-10 17:04:30 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
return apiInputEditor;
|
|
|
|
};
|
|
|
|
|
|
|
|
GameLib.D3.Input.Editor.FromObjectComponent = function(graphics, objectComponent) {
|
|
|
|
|
|
|
|
var apiInputEditor = GameLib.D3.API.Input.Editor.FromObjectComponent(objectComponent);
|
|
|
|
|
|
|
|
return new GameLib.D3.Input.Editor(
|
|
|
|
graphics,
|
|
|
|
apiInputEditor
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2017-01-12 17:40:17 +01:00
|
|
|
GameLib.D3.Input.Editor.prototype.onWindowResize = function() {
|
|
|
|
|
2017-02-21 18:55:18 +01:00
|
|
|
this.domContainer.instance.style.height = (this.window.innerHeight - this.containerHeightOffset) + 'px';
|
|
|
|
this.domContainer.instance.style.width = (this.window.innerWidth - this.containerWidthOffset) + 'px';
|
2017-01-12 17:40:17 +01:00
|
|
|
|
2017-01-13 16:19:51 +01:00
|
|
|
var width = this.window.innerWidth - this.widthOffset;
|
|
|
|
|
|
|
|
var height = this.window.innerHeight - this.heightOffset;
|
|
|
|
|
|
|
|
//TODO: map the relative viewport sizes and offsets with the size differences
|
|
|
|
|
|
|
|
this.editor.viewports.map(
|
|
|
|
function(viewport) {
|
|
|
|
viewport.width = width;
|
|
|
|
viewport.height = height;
|
|
|
|
viewport.updateInstance();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
this.editor.game.viewports.map(
|
|
|
|
function(viewport) {
|
|
|
|
viewport.width = width;
|
|
|
|
viewport.height = height;
|
|
|
|
viewport.updateInstance();
|
|
|
|
}
|
2017-01-12 17:40:17 +01:00
|
|
|
);
|
|
|
|
//
|
|
|
|
// this.scene.cameras[this.scene.activeCameraIndex].aspect = () / window.innerHeight;
|
|
|
|
// this.scene.cameras[this.scene.activeCameraIndex].updateInstance();
|
|
|
|
//
|
|
|
|
// this.scene.renderers[this.scene.activeRendererIndex].width = window.innerWidth - 400;
|
|
|
|
// this.scene.renderers[this.scene.activeRendererIndex].height = window.innerHeight;
|
|
|
|
// this.scene.renderers[this.scene.activeRendererIndex].updateInstance();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Keypress events
|
|
|
|
* @param event
|
|
|
|
*/
|
|
|
|
GameLib.D3.Input.Editor.prototype.onKeyPress = function(event) {
|
|
|
|
|
|
|
|
if (event.code == "KeyQ") {
|
|
|
|
|
|
|
|
this.editor.allSelected = !this.editor.allSelected;
|
|
|
|
|
2017-01-17 13:24:45 +01:00
|
|
|
this.editor.selectedObjects = [];
|
2017-01-12 17:40:17 +01:00
|
|
|
|
2017-01-17 13:24:45 +01:00
|
|
|
if (this.editor.allSelected) {
|
2017-01-20 13:40:27 +01:00
|
|
|
for (var property in this.editor.idToObject) {
|
|
|
|
if (this.editor.idToObject.hasOwnProperty(property)) {
|
|
|
|
this.editor.selectedObjects.push(
|
|
|
|
new GameLib.D3.SelectedObject(
|
|
|
|
this.graphics,
|
|
|
|
this.editor.idToObject(property)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2017-01-12 17:40:17 +01:00
|
|
|
}
|
|
|
|
|
2017-01-17 13:24:45 +01:00
|
|
|
if (this.editor.onSelectionChanged) {
|
|
|
|
this.editor.onSelectionChanged(this.editor);
|
2017-01-12 17:40:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event.code == 'KeyG') {
|
|
|
|
if (!this.meshMoveMode) {
|
|
|
|
console.log('move mode');
|
|
|
|
this.meshMoveMode = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event.code == 'KeyX') {
|
|
|
|
if (this.meshMoveMode) {
|
|
|
|
console.log('move along x');
|
|
|
|
this.meshMoveXMode = true;
|
|
|
|
this.meshMoveYMode = false;
|
|
|
|
this.meshMoveZMode = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event.code == 'KeyY') {
|
|
|
|
if (this.meshMoveMode) {
|
|
|
|
console.log('move along y');
|
|
|
|
this.meshMoveXMode = false;
|
|
|
|
this.meshMoveYMode = true;
|
|
|
|
this.meshMoveZMode = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event.code == 'KeyZ') {
|
|
|
|
if (this.meshMoveMode) {
|
|
|
|
console.log('move along z');
|
|
|
|
this.meshMoveXMode = false;
|
|
|
|
this.meshMoveYMode = false;
|
|
|
|
this.meshMoveZMode = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event.code == 'Escape') {
|
|
|
|
if (this.meshMoveMode) {
|
|
|
|
this.meshMoveMode = false;
|
|
|
|
console.log('TODO: implement restore positions');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event.code == 'Enter') {
|
|
|
|
if (this.meshMoveMode) {
|
|
|
|
this.meshMoveMode = false;
|
|
|
|
console.log('TODO: implement apply positions');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mouse click events
|
|
|
|
* @param event
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
GameLib.D3.Input.Editor.prototype.onMouseDown = function(event) {
|
|
|
|
|
|
|
|
if (event.button == 2) {
|
|
|
|
|
|
|
|
event.cancelBubble = true;
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
if (event.stopPropagation) {
|
|
|
|
event.stopPropagation();
|
|
|
|
}
|
|
|
|
|
2017-01-20 13:40:27 +01:00
|
|
|
var meshes = [];
|
|
|
|
|
|
|
|
for (var property in this.editor.idToObject) {
|
|
|
|
if (this.editor.idToObject.hasOwnProperty(property)) {
|
|
|
|
if (this.editor.idToObject[property] instanceof GameLib.D3.Mesh) {
|
|
|
|
meshes.push(this.editor.idToObject[property]);
|
|
|
|
}
|
2017-01-17 13:24:45 +01:00
|
|
|
}
|
2017-01-20 13:40:27 +01:00
|
|
|
}
|
2017-01-12 17:40:17 +01:00
|
|
|
|
2017-01-17 13:24:45 +01:00
|
|
|
var intersects = this.raycaster.getIntersectedObjects(meshes);
|
2017-01-12 17:40:17 +01:00
|
|
|
|
|
|
|
if (intersects.length > 0) {
|
|
|
|
|
|
|
|
var index = -1;
|
|
|
|
|
2017-01-17 13:24:45 +01:00
|
|
|
for (var s = 0; s < this.editor.selectedObjects.length; s++) {
|
|
|
|
if (this.editor.selectedObjects[s].object == intersects[0]) {
|
2017-01-12 17:40:17 +01:00
|
|
|
index = s;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index == -1) {
|
|
|
|
/**
|
|
|
|
* The object is not selected, select it
|
|
|
|
*/
|
2017-01-17 13:24:45 +01:00
|
|
|
this.selectObject(intersects[0]);
|
2017-01-12 17:40:17 +01:00
|
|
|
|
|
|
|
} else {
|
|
|
|
/**
|
|
|
|
* De-select the objec
|
|
|
|
*/
|
2017-01-17 13:24:45 +01:00
|
|
|
var delta = Date.now() - this.editor.selectedObjects[index].lastUpdate;
|
|
|
|
if (delta > this.selectDelayMs) {
|
|
|
|
this.unselectObject(intersects[0]);
|
2017-01-12 17:40:17 +01:00
|
|
|
}
|
|
|
|
}
|
2017-01-17 13:24:45 +01:00
|
|
|
|
|
|
|
if (this.editor.onSelectionChanged) {
|
|
|
|
this.editor.onSelectionChanged(this.editor);
|
|
|
|
}
|
2017-01-12 17:40:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event.button == 0) {
|
|
|
|
if (this.meshMoveMode) {
|
|
|
|
this.meshMoveMode = false;
|
|
|
|
this.meshMoveXMode = false;
|
|
|
|
this.meshMoveYMode = false;
|
|
|
|
this.meshMoveZMode = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mouse move events
|
|
|
|
* @param event
|
|
|
|
*/
|
|
|
|
GameLib.D3.Input.Editor.prototype.onMouseMove = function(event) {
|
|
|
|
|
2017-01-17 13:24:45 +01:00
|
|
|
var clientX = event.clientX - this.widthOffset;
|
|
|
|
|
2017-01-17 17:16:10 +01:00
|
|
|
this.mouse.x = ((clientX / (window.innerWidth - this.widthOffset))) * 2 - 1;
|
|
|
|
this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
2017-01-12 17:40:17 +01:00
|
|
|
|
2017-01-17 17:16:10 +01:00
|
|
|
this.raycaster.instance.setFromCamera(
|
|
|
|
this.mouse,
|
|
|
|
this.cameras[this.scene.activeCameraIndex].instance
|
2017-01-12 17:40:17 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
if (this.meshMoveMode) {
|
|
|
|
|
|
|
|
var units = event.movementY;
|
|
|
|
|
|
|
|
if (this.meshMoveXMode) {
|
|
|
|
this.moveSelectedObjects('x', units);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.meshMoveYMode) {
|
|
|
|
this.moveSelectedObjects('y', units);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.meshMoveZMode) {
|
|
|
|
this.moveSelectedObjects('z', units);
|
|
|
|
}
|
|
|
|
}
|
2017-01-17 17:16:10 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Moves selected objects along an axis
|
|
|
|
* @param alongAxis
|
|
|
|
* @param units
|
|
|
|
*/
|
|
|
|
GameLib.D3.Input.Editor.prototype.moveSelectedObjects = function(alongAxis, units) {
|
|
|
|
|
|
|
|
for (var s = 0; s < this.editor.selectedObjects.length; s++) {
|
|
|
|
|
|
|
|
var object = this.editor.selectedObjects[s].object;
|
|
|
|
|
|
|
|
if (object.position) {
|
|
|
|
if (alongAxis == 'x') {
|
|
|
|
object.position.x += units;
|
|
|
|
}
|
|
|
|
if (alongAxis == 'y') {
|
|
|
|
object.position.y += units;
|
|
|
|
}
|
|
|
|
if (alongAxis == 'z') {
|
|
|
|
object.position.z += units;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (object.updateInstance) {
|
|
|
|
object.updateInstance();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-01-12 17:40:17 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prevent Context Menu creation
|
|
|
|
* @param event
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
GameLib.D3.Input.Editor.prototype.onContextMenu = function(event){
|
|
|
|
|
|
|
|
if (event.stopPropagation) {
|
|
|
|
event.stopPropagation();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event.preventDefault) {
|
|
|
|
event.preventDefault();
|
|
|
|
}
|
|
|
|
|
|
|
|
event.cancelBubble = true;
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2017-01-10 17:04:30 +01:00
|
|
|
GameLib.D3.Input.Editor.prototype.update = function(deltaTime) {
|
2017-02-21 18:55:18 +01:00
|
|
|
return;
|
2017-01-10 17:04:30 +01:00
|
|
|
};
|