114 lines
3.7 KiB
TypeScript
114 lines
3.7 KiB
TypeScript
import { EngineComponent, EventEmitter, Renderer } from '@freeblox/engine';
|
|
import { EditorEvents, SelectEvent } from '../types/events';
|
|
import { Object3D, Raycaster, Vector2 } from 'three';
|
|
|
|
type MouseMap = [boolean, boolean, boolean];
|
|
type EventMap = [string, Function];
|
|
|
|
export class EditorMouse extends EngineComponent {
|
|
private helpers!: Object3D;
|
|
private world!: Object3D;
|
|
|
|
private mouseButtons: MouseMap = [false, false, false];
|
|
private mouseButtonsLast: MouseMap = [false, false, false];
|
|
|
|
private mousePosition = new Vector2(0, 0);
|
|
private mousePositionGL = new Vector2(0, 0);
|
|
private mousePositionLast = new Vector2(0, 0);
|
|
private mousePositionGLLast = new Vector2(0, 0);
|
|
|
|
private boundEvents: EventMap[] = [];
|
|
private ray = new Raycaster();
|
|
|
|
constructor(
|
|
protected renderer: Renderer,
|
|
protected events: EventEmitter<EditorEvents>
|
|
) {
|
|
super(renderer, events);
|
|
}
|
|
|
|
get canvas() {
|
|
return this.renderer.renderer.domElement;
|
|
}
|
|
|
|
initialize(): void {
|
|
this.helpers = this.renderer.scene.getObjectByName('_helpers')!;
|
|
this.world = this.renderer.scene.getObjectByName('_world')!;
|
|
|
|
const mouseDown = (ev: MouseEvent) => {
|
|
const [object] = this.ray.intersectObjects(this.world.children, true);
|
|
this.mouseButtons[ev.button] = true;
|
|
this.events.emit('mouseDown', {
|
|
position: this.mousePosition,
|
|
positionGL: this.mousePositionGL,
|
|
button: ev.button,
|
|
target: object,
|
|
shift: ev.shiftKey,
|
|
control: ev.ctrlKey,
|
|
alt: ev.altKey,
|
|
});
|
|
};
|
|
|
|
const mouseUp = (ev: MouseEvent) => {
|
|
const [object] = this.ray.intersectObjects(this.world.children, true);
|
|
this.mouseButtons[ev.button] = false;
|
|
this.events.emit('mouseUp', {
|
|
position: this.mousePosition,
|
|
positionGL: this.mousePositionGL,
|
|
button: ev.button,
|
|
target: object,
|
|
});
|
|
};
|
|
|
|
const mouseMove = (ev: MouseEvent) => {
|
|
this.mousePositionLast = this.mousePosition.clone();
|
|
this.mousePositionGLLast = this.mousePositionGL.clone();
|
|
|
|
this.mousePosition.set(ev.clientX, ev.clientY);
|
|
this.mousePositionGL.set(
|
|
(this.mousePosition.x / this.renderer.resolution.x) * 2 - 1,
|
|
-(this.mousePosition.y / this.renderer.resolution.y) * 2 + 1
|
|
);
|
|
|
|
this.events.emit('mouseMove', {
|
|
position: this.mousePosition,
|
|
positionGL: this.mousePositionGL,
|
|
offset: this.mousePositionLast.clone().sub(this.mousePosition),
|
|
offsetGL: this.mousePositionGLLast.clone().sub(this.mousePositionGL),
|
|
});
|
|
};
|
|
|
|
const contextMenu = (ev: MouseEvent) => ev.preventDefault();
|
|
|
|
this.canvas.addEventListener('mousedown', mouseDown);
|
|
this.canvas.addEventListener('mousemove', mouseMove);
|
|
this.canvas.addEventListener('mouseup', mouseUp);
|
|
this.canvas.addEventListener('contextmenu', contextMenu);
|
|
|
|
this.boundEvents.push(
|
|
['mousedown', mouseDown],
|
|
['mousemove', mouseMove],
|
|
['mouseup', mouseUp],
|
|
['contextmenu', contextMenu]
|
|
);
|
|
}
|
|
|
|
update(delta: number): void {
|
|
this.ray.setFromCamera(this.mousePositionGL, this.renderer.camera);
|
|
this.mouseButtonsLast = [...this.mouseButtons];
|
|
}
|
|
|
|
cleanUp(): void {
|
|
for (const [event, handler] of this.boundEvents) {
|
|
this.canvas.removeEventListener(event, handler as EventListener);
|
|
}
|
|
}
|
|
|
|
// private realMousePos(vec: Vector2, x: number, y: number) {
|
|
// const rect = this.renderer.renderer.domElement.getBoundingClientRect();
|
|
// const scaleX = this.renderer.renderer.domElement.width / rect.width;
|
|
// const scaleY = this.renderer.renderer.domElement.height / rect.height;
|
|
// vec.set((x - rect.left) * scaleX, (y - rect.top) * scaleY);
|
|
// }
|
|
}
|