UNPKG

@animech-public/playcanvas

Version:
2 lines (1 loc) 5.63 kB
import{math as t}from"../../core/math/math.js";import{Vec3 as e}from"../../core/math/vec3.js";import{Mat4 as i}from"../../core/math/mat4.js";import{Ray as o}from"../../core/shape/ray.js";import{EventHandler as s}from"../../core/event-handler.js";import{SORTMODE_NONE as r,PROJECTION_PERSPECTIVE as n}from"../../scene/constants.js";import{Entity as a}from"../../framework/entity.js";import{Layer as h}from"../../scene/layer.js";import{GIZMOSPACE_WORLD as c,GIZMOSPACE_LOCAL as d}from"./constants.js";const p=new e,_=new e,l=new i,E=new i,f=new o,m=1e-6;class u extends s{static createLayer(t,e="Gizmo",i){const o=new h({name:e,clearDepthBuffer:!0,opaqueSortMode:r,transparentSortMode:r});return t.scene.layers.insert(o,null!=i?i:t.scene.layers.layerList.length),o}constructor(t,e){super(),this._size=1,this._scale=1,this._coordSpace=c,this._app=void 0,this._device=void 0,this._camera=void 0,this._layer=void 0,this.nodes=[],this.root=void 0,this.intersectShapes=[],this._camera=t,this._app=t.system.app,this._device=this._app.graphicsDevice,this._layer=e,t.layers=t.layers.concat(e.id),this.root=new a("gizmo"),this._app.root.addChild(this.root),this.root.enabled=!1,this._updateScale(),this._onPointerDown=this._onPointerDown.bind(this),this._onPointerMove=this._onPointerMove.bind(this),this._onPointerUp=this._onPointerUp.bind(this),this._device.canvas.addEventListener("pointerdown",this._onPointerDown),this._device.canvas.addEventListener("pointermove",this._onPointerMove),this._device.canvas.addEventListener("pointerup",this._onPointerUp),this._app.on("update",(()=>{this._updatePosition(),this._updateRotation(),this._updateScale()})),this._app.on("destroy",(()=>this.destroy()))}get layer(){return this._layer}set coordSpace(t){this._coordSpace=null!=t?t:c,this._updateRotation()}get coordSpace(){return this._coordSpace}set size(t){this._size=t,this._updateScale()}get size(){return this._size}get facing(){if(this._camera.projection===n){const t=this.root.getPosition(),e=this._camera.entity.getPosition();return _.sub2(e,t).normalize()}return _.copy(this._camera.entity.forward).mulScalar(-1)}_onPointerDown(t){if(!this.root.enabled||document.pointerLockElement)return;const e=this._getSelection(t.offsetX,t.offsetY);e[0]&&(t.preventDefault(),t.stopPropagation());const{canvas:i}=this._device;i.setPointerCapture(t.pointerId),this.fire(u.EVENT_POINTERDOWN,t.offsetX,t.offsetY,e[0])}_onPointerMove(t){if(!this.root.enabled||document.pointerLockElement)return;const e=this._getSelection(t.offsetX,t.offsetY);e[0]&&(t.preventDefault(),t.stopPropagation()),this.fire(u.EVENT_POINTERMOVE,t.offsetX,t.offsetY,e[0])}_onPointerUp(t){if(!this.root.enabled||document.pointerLockElement)return;const e=this._getSelection(t.offsetX,t.offsetY);e[0]&&(t.preventDefault(),t.stopPropagation());const{canvas:i}=this._device;i.releasePointerCapture(t.pointerId),this.fire(u.EVENT_POINTERUP,t.offsetX,t.offsetY,e[0])}_updatePosition(){p.set(0,0,0);for(let t=0;t<this.nodes.length;t++){const e=this.nodes[t];p.add(e.getPosition())}p.mulScalar(1/(this.nodes.length||1)),p.distance(this.root.getPosition())<m||(this.root.setPosition(p),this.fire(u.EVENT_POSITIONUPDATE,p))}_updateRotation(){p.set(0,0,0),this._coordSpace===d&&0!==this.nodes.length&&p.copy(this.nodes[this.nodes.length-1].getEulerAngles()),p.distance(this.root.getEulerAngles())<m||(this.root.setEulerAngles(p),this.fire(u.EVENT_ROTATIONUPDATE,p))}_updateScale(){if(this._camera.projection===n){const e=this.root.getPosition(),i=this._camera.entity.getPosition(),o=e.distance(i);this._scale=Math.tan(.5*this._camera.fov*t.DEG_TO_RAD)*o*.3}else this._scale=.32*this._camera.orthoHeight;this._scale=Math.max(this._scale*this._size,1e-4),Math.abs(this._scale-this.root.getLocalScale().x)<m||(this.root.setLocalScale(this._scale,this._scale,this._scale),this.fire(u.EVENT_SCALEUPDATE,this._scale))}_getSelection(t,e){const i=this._camera.screenToWorld(t,e,0),o=this._camera.screenToWorld(t,e,this._camera.farClip-this._camera.nearClip),s=p.copy(o).sub(i).normalize(),r=[];for(let t=0;t<this.intersectShapes.length;t++){const e=this.intersectShapes[t];if(e.disabled||!e.entity.enabled)continue;const o=e.entity.getWorldTransform();for(let t=0;t<e.triData.length;t++){const{tris:n,transform:a,priority:h}=e.triData[t],c=l.copy(o).mul(a),d=E.copy(c).invert(),_=f;d.transformPoint(i,_.origin),d.transformVector(s,_.direction),_.direction.normalize();for(let t=0;t<n.length;t++)n[t].intersectsRay(_,p)&&r.push({dist:c.transformPoint(p).sub(i).length(),meshInstances:e.meshInstances,priority:h})}}return r.length?(r.sort(((t,e)=>0!==t.priority&&0!==e.priority?e.priority-t.priority:t.dist-e.dist)),r[0].meshInstances):[]}attach(t=[]){if(Array.isArray(t)){if(0===t.length)return;this.nodes=t}else this.nodes=[t];this._updatePosition(),this._updateRotation(),this._updateScale(),this.fire(u.EVENT_NODESATTACH),this.root.enabled=!0,this.fire(u.EVENT_RENDERUPDATE)}detach(){this.root.enabled=!1,this.fire(u.EVENT_RENDERUPDATE),this.fire(u.EVENT_NODESDETACH),this.nodes=[]}destroy(){this.detach(),this._device.canvas.removeEventListener("pointerdown",this._onPointerDown),this._device.canvas.removeEventListener("pointermove",this._onPointerMove),this._device.canvas.removeEventListener("pointerup",this._onPointerUp),this.root.destroy()}}u.EVENT_POINTERDOWN="pointer:down",u.EVENT_POINTERMOVE="pointer:move",u.EVENT_POINTERUP="pointer:up",u.EVENT_POSITIONUPDATE="position:update",u.EVENT_ROTATIONUPDATE="rotation:update",u.EVENT_SCALEUPDATE="scale:update",u.EVENT_NODESATTACH="nodes:attach",u.EVENT_NODESDETACH="nodes:detach",u.EVENT_RENDERUPDATE="render:update";export{u as Gizmo};