123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- import { Observer, Observable } from "../Misc/observable";
- import { Nullable } from "../types";
- import { PointerInfo } from "../Events/pointerEvents";
- import { Vector3, Color3 } from "../Maths/math";
- import { AbstractMesh } from "../Meshes/abstractMesh";
- import { Mesh } from "../Meshes/mesh";
- import { LinesMesh } from "../Meshes/linesMesh";
- import { BoxBuilder } from "../Meshes/Builders/boxBuilder";
- import { CylinderBuilder } from "../Meshes/Builders/cylinderBuilder";
- import { StandardMaterial } from "../Materials/standardMaterial";
- import { PointerDragBehavior } from "../Behaviors/Meshes/pointerDragBehavior";
- import { _TimeToken } from "../Instrumentation/timeToken";
- import { _DepthCullingState, _StencilState, _AlphaState } from "../States/index";
- import { Gizmo } from "./gizmo";
- import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
- import { ScaleGizmo } from "./scaleGizmo";
- /**
- * Single axis scale gizmo
- */
- export class AxisScaleGizmo extends Gizmo {
- /**
- * Drag behavior responsible for the gizmos dragging interactions
- */
- public dragBehavior: PointerDragBehavior;
- private _pointerObserver: Nullable<Observer<PointerInfo>> = null;
- /**
- * Scale distance in babylon units that the gizmo will snap to when dragged (Default: 0)
- */
- public snapDistance = 0;
- /**
- * Event that fires each time the gizmo snaps to a new location.
- * * snapDistance is the the change in distance
- */
- public onSnapObservable = new Observable<{ snapDistance: number }>();
- /**
- * If the scaling operation should be done on all axis (default: false)
- */
- public uniformScaling = false;
- private _isEnabled: boolean = true;
- private _parent: Nullable<ScaleGizmo> = null;
- private _arrow: AbstractMesh;
- private _coloredMaterial: StandardMaterial;
- private _hoverMaterial: StandardMaterial;
- /**
- * Creates an AxisScaleGizmo
- * @param gizmoLayer The utility layer the gizmo will be added to
- * @param dragAxis The axis which the gizmo will be able to scale on
- * @param color The color of the gizmo
- */
- constructor(dragAxis: Vector3, color: Color3 = Color3.Gray(), gizmoLayer: UtilityLayerRenderer = UtilityLayerRenderer.DefaultUtilityLayer, parent: Nullable<ScaleGizmo> = null) {
- super(gizmoLayer);
- this._parent = parent;
- // Create Material
- this._coloredMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
- this._coloredMaterial.diffuseColor = color;
- this._coloredMaterial.specularColor = color.subtract(new Color3(0.1, 0.1, 0.1));
- this._hoverMaterial = new StandardMaterial("", gizmoLayer.utilityLayerScene);
- this._hoverMaterial.diffuseColor = color.add(new Color3(0.3, 0.3, 0.3));
- // Build mesh on root node
- this._arrow = new AbstractMesh("", gizmoLayer.utilityLayerScene);
- var arrowMesh = BoxBuilder.CreateBox("yPosMesh", { size: 0.4 }, gizmoLayer.utilityLayerScene);
- var arrowTail = CylinderBuilder.CreateCylinder("cylinder", { diameterTop: 0.005, height: 0.275, diameterBottom: 0.005, tessellation: 96 }, gizmoLayer.utilityLayerScene);
- arrowTail.material = this._coloredMaterial;
- this._arrow.addChild(arrowMesh);
- this._arrow.addChild(arrowTail);
- // Position arrow pointing in its drag axis
- arrowMesh.scaling.scaleInPlace(0.1);
- arrowMesh.material = this._coloredMaterial;
- arrowMesh.rotation.x = Math.PI / 2;
- arrowMesh.position.z += 0.3;
- arrowTail.position.z += 0.275 / 2;
- arrowTail.rotation.x = Math.PI / 2;
- this._arrow.lookAt(this._rootMesh.position.add(dragAxis));
- this._rootMesh.addChild(this._arrow);
- this._arrow.scaling.scaleInPlace(1 / 3);
- // Add drag behavior to handle events when the gizmo is dragged
- this.dragBehavior = new PointerDragBehavior({ dragAxis: dragAxis });
- this.dragBehavior.moveAttached = false;
- this._rootMesh.addBehavior(this.dragBehavior);
- var currentSnapDragDistance = 0;
- var tmpVector = new Vector3();
- var tmpSnapEvent = { snapDistance: 0 };
- this.dragBehavior.onDragObservable.add((event) => {
- if (this.attachedMesh) {
- // Drag strength is modified by the scale of the gizmo (eg. for small objects like boombox the strength will be increased to match the behavior of larger objects)
- var dragStrength = event.dragDistance * ((this.scaleRatio * 3) / this._rootMesh.scaling.length());
- // Snapping logic
- var snapped = false;
- var dragSteps = 0;
- if (this.uniformScaling) {
- this.attachedMesh.scaling.normalizeToRef(tmpVector);
- if (tmpVector.y < 0) {
- tmpVector.scaleInPlace(-1);
- }
- } else {
- tmpVector.copyFrom(dragAxis);
- }
- if (this.snapDistance == 0) {
- tmpVector.scaleToRef(dragStrength, tmpVector);
- } else {
- currentSnapDragDistance += dragStrength;
- if (Math.abs(currentSnapDragDistance) > this.snapDistance) {
- dragSteps = Math.floor(Math.abs(currentSnapDragDistance) / this.snapDistance);
- if (currentSnapDragDistance < 0) {
- dragSteps *= -1;
- }
- currentSnapDragDistance = currentSnapDragDistance % this.snapDistance;
- tmpVector.scaleToRef(this.snapDistance * dragSteps, tmpVector);
- snapped = true;
- } else {
- tmpVector.scaleInPlace(0);
- }
- }
- this.attachedMesh.scaling.addInPlace(tmpVector);
- if (snapped) {
- tmpSnapEvent.snapDistance = this.snapDistance * dragSteps;
- this.onSnapObservable.notifyObservers(tmpSnapEvent);
- }
- }
- });
- this._pointerObserver = gizmoLayer.utilityLayerScene.onPointerObservable.add((pointerInfo) => {
- if (this._customMeshSet) {
- return;
- }
- var isHovered = pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1);
- var material = isHovered ? this._hoverMaterial : this._coloredMaterial;
- this._rootMesh.getChildMeshes().forEach((m) => {
- m.material = material;
- if ((<LinesMesh>m).color) {
- (<LinesMesh>m).color = material.diffuseColor;
- }
- });
- });
- var light = gizmoLayer._getSharedGizmoLight();
- light.includedOnlyMeshes = light.includedOnlyMeshes.concat(this._rootMesh.getChildMeshes());
- }
- protected _attachedMeshChanged(value: Nullable<AbstractMesh>) {
- if (this.dragBehavior) {
- this.dragBehavior.enabled = value ? true : false;
- }
- }
- /**
- * If the gizmo is enabled
- */
- public set isEnabled(value: boolean) {
- this._isEnabled = value;
- if (!value) {
- this.attachedMesh = null;
- }
- else {
- if (this._parent) {
- this.attachedMesh = this._parent.attachedMesh;
- }
- }
- }
- public get isEnabled(): boolean {
- return this._isEnabled;
- }
- /**
- * Disposes of the gizmo
- */
- public dispose() {
- this.onSnapObservable.clear();
- this.gizmoLayer.utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
- this.dragBehavior.detach();
- if (this._arrow) {
- this._arrow.dispose();
- }
- [this._coloredMaterial, this._hoverMaterial].forEach((matl) => {
- if (matl) {
- matl.dispose();
- }
- });
- super.dispose();
- }
- /**
- * Disposes and replaces the current meshes in the gizmo with the specified mesh
- * @param mesh The mesh to replace the default mesh of the gizmo
- * @param useGizmoMaterial If the gizmo's default material should be used (default: false)
- */
- public setCustomMesh(mesh: Mesh, useGizmoMaterial: boolean = false) {
- super.setCustomMesh(mesh);
- if (useGizmoMaterial) {
- this._rootMesh.getChildMeshes().forEach((m) => {
- m.material = this._coloredMaterial;
- if ((<LinesMesh>m).color) {
- (<LinesMesh>m).color = this._coloredMaterial.diffuseColor;
- }
- });
- this._customMeshSet = false;
- }
- }
- }
|