control/entityEditor/EntityEditorScene.tstypescript
import { createEvents, type EventsHandler } from "../../Events";
import { MAX32 } from "../../math";
import { Plane } from "../../math/Plane";
import { Planet } from "../../scene/Planet";
import { Scene } from "../../scene/Scene";
import { Vec2 } from "../../math/Vec2";
import { Vec3 } from "../../math/Vec3";
import { Quat } from "../../math/Quat";
import type { IMouseState } from "../../renderer/RendererEvents";
import { Ellipsoid } from "../../ellipsoid/Ellipsoid";
import { LonLat } from "../../LonLat";
import { Entity } from "../../entity/Entity";
import { MoveAxisEntity } from "./MoveAxisEntity";
import { MovePlaneEntity } from "./MovePlaneEntity";
import { RotateEntity } from "./RotateEntity";
import { Ray } from "../../math/Ray";
import { Sphere } from "../../bv/Sphere";
import { AxisTrackEntity } from "./AxisTrackEntity";
import { CameraLock } from "../CameraLock";
import { EntityCollection } from "../../entity/EntityCollection";
import { SHADE_UNLIT } from "../../shadeModeConstants";
export interface IEntityEditorSceneParams {
planet?: Planet;
name?: string;
editMode?: EditModeName;
}
export const NATIVE_MODE = 0;
export const YAW_MODE = 1;
export type EditMode = typeof NATIVE_MODE | typeof YAW_MODE;
export type EditModeName = "native" | "yaw";
function dragSimpleRes(unit: Vec3, clickRay: Ray, currRay: Ray, p0: Vec3, res: Vec3) {
let p1 = p0.add(Vec3.UP),
p2 = p0.add(unit);
let px = new Vec3();
if (clickRay.hitPlaneRes(Plane.fromPoints(p0, p1, p2), px) === Ray.INSIDE) {
let clickCart = Vec3.proj_b_to_a(px, unit);
if (currRay.hitPlaneRes(Plane.fromPoints(p0, p1, p2), px) === Ray.INSIDE) {
let dragCart = Vec3.proj_b_to_a(px, unit);
let dragVec = dragCart.sub(clickCart);
res.copy(p0.add(dragVec));
}
}
}
type EntityEditorSceneEventsList = [
"mousemove",
"mouseenter",
"mouseleave",
"lclick",
"rclick",
"mclick",
"ldblclick",
"rdblclick",
"mdblclick",
"lup",
"rup",
"mup",
"ldown",
"rdown",
"mdown",
"lhold",
"rhold",
"mhold",
"mousewheel",
"touchmove",
"touchstart",
"touchend",
"doubletouch",
"touchleave",
"touchenter",
"select",
"unselect",
"change",
"position",
"pitch",
"yaw",
"roll",
"scale"
];
class EntityEditorScene extends Scene {
public events: EventsHandler<EntityEditorSceneEventsList>;
protected _planet: Planet | null;
protected _startPos: Vec2 | null;
protected _startClick: Vec2;
protected _moveLayer: EntityCollection;
protected _planeLayer: EntityCollection;
protected _rotateLayer: EntityCollection;
protected _axisTrackLayer: EntityCollection;
protected _selectedEntity: Entity | null;
protected _selectedEntityCart: Vec3;
protected _selectedEntityRotation: Quat;
protected _selectedEntityPitch: number;
protected _selectedEntityYaw: number;
protected _selectedEntityRoll: number;
protected _clickPos: Vec2;
protected _axisEntity: MoveAxisEntity;
protected _planeEntity: MovePlaneEntity;
protected _rotateEntity: RotateEntity;
protected _axisTrackEntity: AxisTrackEntity;
protected _selectedMove: string | null;
protected _ops: Record<string, (mouseState: IMouseState) => void>;
protected _axisTrackVisibility: boolean;
protected _editMode: EditMode;
constructor(options: IEntityEditorSceneParams = {}) {
super(options.name || "EntityEditorScene");
this.events = createEvents(ENTITY_EDITOR_SCENE_EVENTS);
this._planet = options.planet || null;
this._editMode = this._parseEditMode(options.editMode);
this._startPos = null;
this._startClick = new Vec2();
this._axisEntity = new MoveAxisEntity();
this._planeEntity = new MovePlaneEntity();
this._rotateEntity = new RotateEntity();
this._axisTrackEntity = new AxisTrackEntity();
this._moveLayer = new EntityCollection({
scaleByDistance: [0.1, MAX32, MAX32, 0.1],
shadeMode: SHADE_UNLIT,
pickingScale: [5, 1.1, 5],
visibility: false,
depthOrder: 1000
});
this._planeLayer = new EntityCollection({
scaleByDistance: [0.1, MAX32, MAX32, 0.1],
shadeMode: SHADE_UNLIT,
visibility: false,
depthOrder: 1000
});
this._rotateLayer = new EntityCollection({
shadeMode: SHADE_UNLIT,
visibility: false,
depthOrder: 1000,
pickingScale: 5
});
this._selectedEntity = null;
this._clickPos = new Vec2();
this._selectedEntityCart = new Vec3();
this._selectedEntityRotation = Quat.IDENTITY;
this._selectedEntityPitch = 0;
this._selectedEntityYaw = 0;
this._selectedEntityRoll = 0;
this._selectedMove = null;
this._axisTrackVisibility = false;
this._axisTrackLayer = new EntityCollection({
shadeMode: SHADE_UNLIT,
visibility: false,
pickingScale: 5,
pickingEnabled: false,
opacity: 0.6
});
this._ops = {
move_x: this._moveX,
move_y: this._moveY,
move_z: this._moveZ,
move_xz: this._moveXZ,
move_xy: this._moveXY,
move_zy: this._moveZY,
rotate_pitch: this._rotatePitch,
rotate_yaw: this._rotateYaw,
rotate_roll: this._rotateRoll,
scale: this._scale,
scale_x: this._scaleX,
scale_y: this._scaleY,
scale_z: this._scaleZ
};
}
get ellipsoid(): Ellipsoid | undefined {
if (this._planet) {
return this._planet.ellipsoid;
}
}
get planet(): Planet | null {
return this._planet;
}
get editMode(): EditMode {
return this._editMode;
}
set editMode(mode: EditMode) {
this._editMode = mode;
if (this._selectedEntity) {
let cart = this._selectedEntity.getAbsoluteCartesian();
this._selectedEntityRotation = this._getEntityRotation(this._selectedEntity, cart);
this._setRotateEntityCartesian3v(this._selectedEntity, cart);
}
}
public bindPlanet(planet: Planet) {
this._planet = planet;
}
protected _parseEditMode(mode: EditModeName | undefined): EditMode {
if (mode === "native") {
return NATIVE_MODE;
} else if (mode === "yaw") {
return YAW_MODE;
}
return NATIVE_MODE;
}
public override init() {
this.activate();
}
public override onremove() {
this.deactivate();
}
protected _addAxisLayers() {
this._moveLayer.addTo(this);
this._planeLayer.addTo(this);
this._rotateLayer.addTo(this);
this._axisTrackLayer.addTo(this);
this._moveLayer.add(this._axisEntity);
this._moveLayer.events.on("mouseenter", this._onAxisLayerMouseEnter);
this._moveLayer.events.on("mouseleave", this._onAxisLayerMouseLeave);
this._moveLayer.events.on("lup", this._onAxisLayerLUp);
this._moveLayer.events.on("ldown", this._onAxisLayerLDown);
this._planeLayer.add(this._planeEntity);
this._planeLayer.events.on("mouseenter", this._onPlaneLayerMouseEnter);
this._planeLayer.events.on("mouseleave", this._onPlaneLayerMouseLeave);
this._planeLayer.events.on("lup", this._onPlaneLayerLUp);
this._planeLayer.events.on("ldown", this._onPlaneLayerLDown);
this._rotateLayer.add(this._rotateEntity);
this._rotateLayer.events.on("mouseenter", this._onRotateLayerMouseEnter);
this._rotateLayer.events.on("mouseleave", this._onRotateLayerMouseLeave);
this._rotateLayer.events.on("lup", this._onRotateLayerLUp);
this._rotateLayer.events.on("ldown", this._onRotateLayerLDown);
this._axisTrackLayer.add(this._axisTrackEntity);
}
protected _onAxisLayerMouseEnter = (e: IMouseState) => {
this.renderer!.handler!.canvas!.style.cursor = "pointer";
e.pickingObject.setColorHTML(e.pickingObject.properties.style.selectColor);
};
protected _onAxisLayerMouseLeave = (e: IMouseState) => {
this.renderer!.handler!.canvas!.style.cursor = "default";
e.pickingObject.setColorHTML(e.pickingObject.properties.style.color);
};
protected _navActivate() {
if (this.renderer) {
if (this.renderer.controls.navigation) {
this.renderer.controls.navigation.activate();
}
if (this.renderer.controls.SimpleNavigation) {
this.renderer.controls.SimpleNavigation.activate();
}
}
}
protected _navDeactivate() {
if (this.renderer) {
if (this.renderer.controls.navigation) {
this.renderer.controls.navigation.deactivate();
}
if (this.renderer.controls.SimpleNavigation) {
this.renderer.controls.SimpleNavigation.deactivate();
}
}
}
protected _onAxisLayerLUp = (e: IMouseState) => {
this._selectedMove = null;
this._navActivate();
this._setAxisTrackVisibility(false);
};
protected _onAxisLayerLDown = (e: IMouseState) => {
this._clickPos = e.pos.clone();
if (this._selectedEntity) {
this._selectedEntityCart = this._selectedEntity.getAbsoluteCartesian();
this._setAxisTrackVisibility(true);
}
this._selectedMove = e.pickingObject.properties.opName;
this._navDeactivate();
};
protected _onPlaneLayerMouseEnter = (e: IMouseState) => {
this.renderer!.handler!.canvas!.style.cursor = "pointer";
e.pickingObject.geoObject.setColorHTML(e.pickingObject.properties.style.selectColor);
};
protected _onPlaneLayerMouseLeave = (e: IMouseState) => {
this.renderer!.handler!.canvas!.style.cursor = "default";
e.pickingObject.geoObject.setColorHTML(e.pickingObject.properties.style.color);
};
protected _onPlaneLayerLUp = (e: IMouseState) => {
this._selectedMove = null;
this._navActivate();
this._setAxisTrackVisibility(false);
};
protected _onPlaneLayerLDown = (e: IMouseState) => {
this._clickPos = e.pos.clone();
if (this._selectedEntity) {
this._selectedEntityCart = this._selectedEntity.getAbsoluteCartesian();
this._setAxisTrackVisibility(true);
}
this._selectedMove = e.pickingObject.properties.opName;
this._navDeactivate();
};
protected _onRotateLayerMouseEnter = (e: IMouseState) => {
this.renderer!.handler!.canvas!.style.cursor = "pointer";
e.pickingObject.polyline!.setColorHTML(e.pickingObject.properties.style.selectColor);
};
protected _onRotateLayerMouseLeave = (e: IMouseState) => {
this.renderer!.handler!.canvas!.style.cursor = "default";
e.pickingObject.polyline!.setColorHTML(e.pickingObject.properties.style.color);
};
protected _onRotateLayerLUp = (e: IMouseState) => {
this._selectedMove = null;
this._navActivate();
};
protected _onRotateLayerLDown = (e: IMouseState) => {
this._clickPos = e.pos.clone();
if (this._selectedEntity) {
this._selectedEntityCart = this._selectedEntity.getAbsoluteCartesian();
this._selectedEntityRotation = this._getEntityRotation(this._selectedEntity, this._selectedEntityCart);
if (this._selectedEntity) {
this._selectedEntityPitch = this._selectedEntity.getAbsolutePitch();
this._selectedEntityYaw = this._selectedEntity.getAbsoluteYaw();
this._selectedEntityRoll = this._selectedEntity.getAbsoluteRoll();
}
}
this._selectedMove = e.pickingObject.properties.opName;
this._navDeactivate();
};
protected _onMouseMove = (e: IMouseState) => {
if (this._selectedEntity && this._selectedMove && this._ops[this._selectedMove]) {
this._ops[this._selectedMove](e);
}
};
protected _removeAxisLayers() {
this._moveLayer.remove();
this._planeLayer.remove();
this._rotateLayer.remove();
}
public activate() {
this.renderer!.events.on("lclick", this._onLclick);
this.renderer!.events.on("mousemove", this._onMouseMove);
this.renderer!.events.on("forwardpass", this._onForwardpass, this);
this._addAxisLayers();
}
protected deactivate() {
this.renderer!.events.off("forwardpass", this._onForwardpass);
this.renderer!.events.off("lclick", this._onLclick);
this.renderer!.events.off("mousemove", this._onMouseMove);
this._removeAxisLayers();
this.clear();
}
protected _setAxisTrackVisibility(visibility: boolean) {
if (visibility !== this._axisTrackVisibility) {
this._axisTrackVisibility = visibility;
this._axisTrackLayer.setVisibility(visibility);
}
}
public setVisibility(visibility: boolean) {
this._moveLayer.setVisibility(visibility);
this._planeLayer.setVisibility(visibility);
this._rotateLayer.setVisibility(visibility);
this.unlockView();
}
public readyToEdit(entity: Entity): boolean {
return !entity.properties || !entity.properties.noEdit;
}
public select(entity: Entity) {
if (
(!this._selectedEntity || (this._selectedEntity && !entity.isEqual(this._selectedEntity))) &&
this.readyToEdit(entity)
) {
if (this._selectedEntity) {
this.unselect();
}
this._selectedEntity = entity;
this.renderer && this.renderer.setRelativeCenter();
this.setVisibility(true);
this.events.dispatch(this.events.select, this._selectedEntity);
}
}
public unselect() {
this.setVisibility(false);
let selectedEntity = this._selectedEntity;
this._selectedEntity = null;
this.events.dispatch(this.events.unselect, selectedEntity);
}
protected _onLclick = (e: IMouseState) => {
if (e.pickingObject && e.pickingObject instanceof Entity) {
this.select(e.pickingObject);
}
};
public clear() {
this.removeEntityCollection(this._moveLayer);
this.removeEntityCollection(this._planeLayer);
this.removeEntityCollection(this._rotateLayer);
}
protected _onForwardpass = () => {
if (this._selectedEntity) {
let cart = this._selectedEntity.getAbsoluteCartesian();
this._axisEntity.setCartesian3v(cart);
this._planeEntity.setCartesian3v(cart);
this._setRotateEntityCartesian3v(this._selectedEntity, cart);
this._axisTrackEntity.setCartesian3v(cart);
}
};
protected _moveX = (e: IMouseState) => {
if (!this._selectedEntity) return;
let cam = this.renderer!.activeCamera;
let p0 = this._selectedEntityCart;
let clickRay = cam.getRay2v(this._clickPos);
let currRay = cam.getRay2v(e.pos);
let px = new Vec3();
if (this.planet) {
let clickCart = clickRay.hitSphere(new Sphere(p0.length(), new Vec3()))!;
let currCart = currRay.hitSphere(new Sphere(p0.length(), new Vec3()))!;
if (!currCart) return;
let rot = Quat.getRotationBetweenVectors(clickCart.normal(), currCart.normal());
px = rot.mulVec3(p0);
if (this.ellipsoid) {
let p0_lonLat = this.ellipsoid.cartesianToLonLat(p0)!;
let px_lonLat = this.ellipsoid.cartesianToLonLat(px)!;
this.ellipsoid.lonLatToCartesianRes(new LonLat(px_lonLat.lon, p0_lonLat.lat, p0_lonLat.height), px);
}
} else {
dragSimpleRes(Vec3.UNIT_X, clickRay, currRay, p0, px);
}
this._selectedEntity.setAbsoluteCartesian3v(px);
this.events.dispatch(this.events.position, px, this._selectedEntity);
this.events.dispatch(this.events.change, this._selectedEntity);
};
protected _moveY = (e: IMouseState) => {
if (!this._selectedEntity) return;
let cam = this.renderer!.activeCamera;
let p0 = this._selectedEntityCart;
let groundNormal = Vec3.UP;
if (this.planet) {
groundNormal = this._axisEntity.getY();
}
let p1 = p0.add(groundNormal);
let p2 = p0.add(cam.getRight());
let px = new Vec3();
let clickRay = cam.getRay2v(this._clickPos);
let currRay = cam.getRay2v(e.pos);
if (clickRay.hitPlaneRes(Plane.fromPoints(p0, p1, p2), px) === Ray.INSIDE) {
let clickCart = Vec3.proj_b_to_a(px, groundNormal);
if (currRay.hitPlaneRes(Plane.fromPoints(p0, p1, p2), px) === Ray.INSIDE) {
let dragCart = Vec3.proj_b_to_a(px, groundNormal);
let dragVec = dragCart.sub(clickCart);
let pos = this._selectedEntityCart.add(dragVec);
this._selectedEntity.setAbsoluteCartesian3v(pos);
this.events.dispatch(this.events.position, px, this._selectedEntity);
this.events.dispatch(this.events.change, this._selectedEntity);
}
}
};
protected _moveZ = (e: IMouseState) => {
if (!this._selectedEntity) return;
let cam = this.renderer!.activeCamera;
let p0 = this._selectedEntityCart;
let clickRay = cam.getRay2v(this._clickPos);
let currRay = cam.getRay2v(e.pos);
let px = new Vec3();
if (this.planet) {
let clickCart = clickRay.hitSphere(new Sphere(p0.length(), new Vec3()))!;
let currCart = currRay.hitSphere(new Sphere(p0.length(), new Vec3()))!;
if (!currCart) return;
let rot = Quat.getRotationBetweenVectors(clickCart.normal(), currCart.normal());
px = rot.mulVec3(p0);
if (this.ellipsoid) {
let p0_lonLat = this.ellipsoid.cartesianToLonLat(p0)!;
let px_lonLat = this.ellipsoid.cartesianToLonLat(px)!;
this.ellipsoid.lonLatToCartesianRes(new LonLat(p0_lonLat.lon, px_lonLat.lat, p0_lonLat.height), px);
}
} else {
dragSimpleRes(Vec3.UNIT_Z, clickRay, currRay, p0, px);
}
this._selectedEntity.setAbsoluteCartesian3v(px);
this.events.dispatch(this.events.position, px, this._selectedEntity);
this.events.dispatch(this.events.change, this._selectedEntity);
};
protected _moveXZ = (e: IMouseState) => {
if (!this._selectedEntity) return;
let cam = this.renderer!.activeCamera;
let p0 = this._selectedEntityCart;
let clickRay = cam.getRay2v(this._clickPos);
let currRay = cam.getRay2v(e.pos);
let px = new Vec3();
if (this.planet) {
let clickCart = clickRay.hitSphere(new Sphere(p0.length(), new Vec3()))!;
let currCart = currRay.hitSphere(new Sphere(p0.length(), new Vec3()))!;
if (!currCart) return;
let rot = Quat.getRotationBetweenVectors(clickCart.normal(), currCart.normal());
px = rot.mulVec3(p0);
if (this.ellipsoid) {
let lonLat = this.ellipsoid.cartesianToLonLat(px)!;
let height = this.ellipsoid.cartesianToLonLat(p0)!.height;
this.ellipsoid.lonLatToCartesianRes(new LonLat(lonLat.lon, lonLat.lat, height), px);
}
} else {
let p1 = p0.add(Vec3.UNIT_X),
p2 = p0.add(Vec3.UNIT_Z);
let clickCart = new Vec3(),
dragCart = new Vec3();
if (clickRay.hitPlaneRes(Plane.fromPoints(p0, p1, p2), clickCart) === Ray.INSIDE) {
if (currRay.hitPlaneRes(Plane.fromPoints(p0, p1, p2), dragCart) === Ray.INSIDE) {
let dragVec = dragCart.sub(clickCart);
px = p0.add(dragVec);
}
}
}
this._selectedEntity.setAbsoluteCartesian3v(px);
this.events.dispatch(this.events.position, px, this._selectedEntity);
this.events.dispatch(this.events.change, this._selectedEntity);
};
protected _moveXY = (e: IMouseState) => {
console.log("moveXY");
};
protected _moveZY = (e: IMouseState) => {
console.log("moveZY");
};
public override getFrameRotation(cartesian: Vec3): Quat {
return this._planet ? this._planet.getFrameRotation(cartesian) : super.getFrameRotation(cartesian);
}
protected _isPlanetEntity(entity: Entity): boolean {
const scene = entity.entityCollection?.scene as Planet | undefined;
const hasPlanetScene = Boolean(scene?.ellipsoid);
const hasFallbackPlanet = Boolean(this._planet);
return hasPlanetScene || hasFallbackPlanet;
}
protected _isYawMode(): boolean {
return this.editMode === YAW_MODE;
}
protected _getYawModeFrameRotation(entity: Entity, cart: Vec3): Quat {
const scene = entity.entityCollection?.scene as Planet | undefined;
if (scene?.ellipsoid) {
return scene.getFrameRotation(cart);
}
if (this._planet) {
return this._planet.getFrameRotation(cart);
}
return Quat.getLookRotation(Vec3.FORWARD, Vec3.UP);
}
protected _getEntityRotation(entity: Entity, cart: Vec3): Quat {
return this._isYawMode()
? new Quat().setPitchYawRoll(0, entity.getAbsoluteYaw(), 0, this._getYawModeFrameRotation(entity, cart))
: entity.getAbsoluteRotation();
}
protected _setRotateEntityCartesian3v(entity: Entity, cart: Vec3) {
if (this._isYawMode()) {
this._rotateEntity.setYawCartesian3v(cart, entity.getAbsoluteYaw());
} else {
this._rotateEntity.setCartesian3v(cart, this._getEntityRotation(entity, cart));
}
}
protected _setEntityRotation(entity: Entity, rotation: Quat, cart: Vec3) {
if (entity.parent && entity.relativePosition) {
entity.setAbsoluteRotation(rotation);
return;
}
let rot = this._isPlanetEntity(entity)
? this.getFrameRotation(cart).conjugate().inverse().mul(rotation)
: rotation;
entity.setAbsolutePitch(rot.getPitch());
entity.setAbsoluteYaw(rot.getYaw());
entity.setAbsoluteRoll(rot.getRoll());
}
protected _rotatePitch = (e: IMouseState) => {
if (!this._selectedEntity) return;
let cam = this.renderer!.activeCamera;
let p0 = this._selectedEntityCart;
let norm = this._selectedEntityRotation.mulVec3(new Vec3(1, 0, 0)).normalize();
let pl = new Plane(p0, norm);
let clickCart = new Vec3(),
dragCart = new Vec3();
if (cam.getRay2v(this._clickPos).hitPlaneRes(pl, clickCart) === Ray.INSIDE) {
if (cam.getRay2v(e.pos).hitPlaneRes(pl, dragCart) === Ray.INSIDE) {
let c0 = clickCart.sub(p0).normalize(),
c1 = dragCart.sub(p0).normalize();
let sig = Math.sign(c0.cross(c1).dot(norm));
let angle = Math.acos(c0.dot(c1));
let deg = this._selectedEntityPitch + sig * angle;
if (this._isYawMode()) {
this._selectedEntity.setAbsolutePitch(deg);
} else {
let rot = Quat.axisAngleToQuat(norm, sig * angle).mul(this._selectedEntityRotation);
this._setEntityRotation(this._selectedEntity, rot, p0);
}
this.events.dispatch(this.events.pitch, deg, this._selectedEntity);
this.events.dispatch(this.events.change, this._selectedEntity);
}
}
};
protected _rotateYaw = (e: IMouseState) => {
if (!this._selectedEntity) return;
let cam = this.renderer!.activeCamera;
let p0 = this._selectedEntityCart;
let norm = this._selectedEntityRotation.mulVec3(new Vec3(0, 1, 0)).normalize();
let pl = new Plane(p0, norm);
let clickCart = new Vec3(),
dragCart = new Vec3();
if (cam.getRay2v(this._clickPos).hitPlaneRes(pl, clickCart) === Ray.INSIDE) {
if (cam.getRay2v(e.pos).hitPlaneRes(pl, dragCart) === Ray.INSIDE) {
let c0 = clickCart.sub(p0).normalize(),
c1 = dragCart.sub(p0).normalize();
let sig = Math.sign(c1.cross(c0).dot(norm));
let angle = Math.acos(c0.dot(c1));
let deg = this._selectedEntityYaw + sig * angle;
if (this._isYawMode()) {
this._selectedEntity.setAbsoluteYaw(deg);
} else {
let rot = Quat.axisAngleToQuat(norm, -sig * angle).mul(this._selectedEntityRotation);
this._setEntityRotation(this._selectedEntity, rot, p0);
}
this.events.dispatch(this.events.yaw, deg, this._selectedEntity);
this.events.dispatch(this.events.change, this._selectedEntity);
}
}
};
protected _rotateRoll = (e: IMouseState) => {
if (!this._selectedEntity) return;
let cam = this.renderer!.activeCamera;
let p0 = this._selectedEntityCart;
let norm = this._selectedEntityRotation.mulVec3(new Vec3(0, 0, 1)).normalize();
let pl = new Plane(p0, norm);
let clickCart = new Vec3(),
dragCart = new Vec3();
if (cam.getRay2v(this._clickPos).hitPlaneRes(pl, clickCart) === Ray.INSIDE) {
if (cam.getRay2v(e.pos).hitPlaneRes(pl, dragCart) === Ray.INSIDE) {
let c0 = clickCart.sub(p0).normalize(),
c1 = dragCart.sub(p0).normalize();
let sig = Math.sign(c0.cross(c1).dot(norm));
let angle = Math.acos(c0.dot(c1));
let deg = this._selectedEntityRoll + sig * angle;
if (this._isYawMode()) {
this._selectedEntity.setAbsoluteRoll(deg);
} else {
let rot = Quat.axisAngleToQuat(norm, sig * angle).mul(this._selectedEntityRotation);
this._setEntityRotation(this._selectedEntity, rot, p0);
}
this.events.dispatch(this.events.roll, deg, this._selectedEntity);
this.events.dispatch(this.events.change, this._selectedEntity);
}
}
};
protected _scale = (e: IMouseState) => {
let scale = 1;
this.events.dispatch(this.events.scale, scale, this._selectedEntity);
this.events.dispatch(this.events.change, this._selectedEntity);
};
protected _scaleX = (e: IMouseState) => {};
protected _scaleY = (e: IMouseState) => {};
protected _scaleZ = (e: IMouseState) => {};
public getSelectedEntity(): Entity | null {
return this._selectedEntity;
}
public lockView() {
if (this.renderer && this._selectedEntity) {
let camLock = this.renderer.controls.CameraLock as CameraLock;
camLock.lockView(this._selectedEntity);
}
}
public unlockView() {
if (this.renderer && this._selectedEntity) {
let camLock = this.renderer.controls.CameraLock as CameraLock;
if (camLock) {
camLock.unlockView();
}
}
}
}
const ENTITY_EDITOR_SCENE_EVENTS: EntityEditorSceneEventsList = [
"mousemove",
"mouseenter",
"mouseleave",
"lclick",
"rclick",
"mclick",
"ldblclick",
"rdblclick",
"mdblclick",
"lup",
"rup",
"mup",
"ldown",
"rdown",
"mdown",
"lhold",
"rhold",
"mhold",
"mousewheel",
"touchmove",
"touchstart",
"touchend",
"doubletouch",
"touchleave",
"touchenter",
"select",
"unselect",
"change",
"position",
"pitch",
"yaw",
"roll",
"scale"
];
export { EntityEditorScene };