UNPKG

@awayjs/view

Version:
380 lines (379 loc) 16.5 kB
import { __extends } from "tslib"; import { Vector3D, AbstractionBase, Point, WeakAssetSet } from '@awayjs/core'; import { PickingCollision } from '../pick/PickingCollision'; import { BoundingVolumePool } from '../bounds/BoundingVolumePool'; /** * @class away.pool.PickEntity */ var PickEntity = /** @class */ (function (_super) { __extends(PickEntity, _super); function PickEntity() { var _this = _super !== null && _super.apply(this, arguments) || this; _this._orientedBoxBounds = []; _this._orientedBoxBoundsDirty = [true, true]; _this._orientedSphereBounds = []; _this._orientedSphereBoundsDirty = [true, true]; _this._activePickables = []; _this.shapeFlag = false; return _this; } Object.defineProperty(PickEntity.prototype, "pickingCollision", { get: function () { return this._pickingCollision; }, enumerable: false, configurable: true }); Object.defineProperty(PickEntity.prototype, "node", { /** * */ get: function () { return this._asset; }, enumerable: false, configurable: true }); Object.defineProperty(PickEntity.prototype, "pickGroup", { /** * */ get: function () { return this._pool; }, enumerable: false, configurable: true }); /** * //TODO */ PickEntity.prototype.init = function (node, pickGroup) { _super.prototype.init.call(this, node, pickGroup); this._pickingCollision = new PickingCollision(this.node, this.pickGroup); this._boundingVolumes = new WeakAssetSet('BoundingVolumeBase'); this._boundingVolumePools = {}; this._pickables = new WeakAssetSet('_Pick_PickableBase'); }; PickEntity.prototype.getBoundingVolume = function (target, type) { if (target === void 0) { target = null; } if (type === void 0) { type = null; } if (target == null) target = this._asset; if (type == null) type = this._asset.container.defaultBoundingVolume; var pool = this._boundingVolumePools[type] || (this._boundingVolumePools[type] = new BoundingVolumePool(this, type)); return target.getAbstraction(pool); }; /** * Evaluates the display object to see if it overlaps or intersects with the * point specified by the <code>x</code> and <code>y</code> parameters. The * <code>x</code> and <code>y</code> parameters specify a point in the * coordinate space of the Scene, not the display object container that * contains the display object(unless that display object container is the * Scene). * * @param x The <i>x</i> coordinate to test against this object. * @param y The <i>y</i> coordinate to test against this object. * @param shapeFlag Whether to check against the actual pixels of the object * (<code>true</code>) or the bounding box * (<code>false</code>). * @param maskFlag Whether to check against the object when it is used as * mask (<code>false</code>). * @return <code>true</code> if the display object overlaps or intersects * with the specified point; <code>false</code> otherwise. */ PickEntity.prototype.hitTestPoint = function (x, y, shapeFlag) { if (shapeFlag === void 0) { shapeFlag = false; } return this._hitTestPointInternal(this._asset, x, y, shapeFlag, false); }; PickEntity.prototype._hitTestPointInternal = function (rootEntity, x, y, shapeFlag, maskFlag) { if (shapeFlag === void 0) { shapeFlag = false; } if (maskFlag === void 0) { maskFlag = false; } if (this._asset.getMaskId() != -1 && (!maskFlag || !shapeFlag)) //allow masks for bounds hit tests return false; if (this._invalid) this._update(); //set local tempPoint for later reference var tempPoint = new Point(x, y); this._asset.globalToLocal(tempPoint, tempPoint); //early out for box test var box = this._getBoxBoundsInternal(null, false, true); if (box == null || !box.contains(tempPoint.x, tempPoint.y, 0)) return false; //early out for non-shape tests if (!shapeFlag || this._asset.container.assetType == '[asset TextField]' || this._asset.container.assetType == '[asset Billboard]') return true; var shapeHit = false; for (var i = this._activePickables.length - 1; i >= 0; i--) { if (this._activePickables[i].hitTestPoint(tempPoint.x, tempPoint.y, 0)) { shapeHit = true; break; } } if (!shapeHit) return false; //do the mask thang var maskOwners = this._asset.getMaskOwners(); if (maskOwners) { var numOwners = maskOwners.length; var node = void 0; var masks = void 0; var numMasks = void 0; var maskHit = void 0; for (var i = 0; i < numOwners; i++) { node = maskOwners[i]; if (!node.isDescendant(rootEntity)) continue; masks = node.getMasks(); numMasks = masks.length; maskHit = false; for (var j = 0; j < numMasks; j++) { node = masks[j]; if (!node.isDescendant(rootEntity)) continue; // todo: figure out why a mask can be null here! if (node && this.pickGroup .getBoundsPicker(node) ._hitTestPointInternal(rootEntity, x, y, shapeFlag, true)) { maskHit = true; break; } } if (!maskHit) return false; } } return true; }; PickEntity.prototype.isInFrustum = function (planes, numPlanes) { return this._isInFrustumInternal(this._asset, planes, numPlanes); }; PickEntity.prototype._isInFrustumInternal = function (rootEntity, planes, numPlanes) { return this.getBoundingVolume(rootEntity).isInFrustum(planes, numPlanes); }; /** * @inheritDoc */ PickEntity.prototype.isIntersectingRay = function (globalRayPosition, globalRayDirection) { return this._isIntersectingRayInternal(this._asset, globalRayPosition, globalRayDirection); }; /** * @inheritDoc */ PickEntity.prototype._isIntersectingRayInternal = function (rootEntity, globalRayPosition, globalRayDirection) { var invMatrix = this._asset.getInverseMatrix3D(); invMatrix.transformVector(globalRayPosition, this._pickingCollision.rayPosition); invMatrix.deltaTransformVector(globalRayDirection, this._pickingCollision.rayDirection); //early out for bounds test var boundVolume = this.getBoundingVolume(); var rayEntryDistance = boundVolume.rayIntersection(this._pickingCollision.rayPosition, this._pickingCollision.rayDirection, this._pickingCollision.normal); //check masks if (rayEntryDistance < 0 || !this._isIntersectingMasks(rootEntity, globalRayPosition, globalRayDirection)) return false; this._pickingCollision.rayEntryDistance = rayEntryDistance; this._pickingCollision.globalRayPosition = globalRayPosition; this._pickingCollision.globalRayDirection = globalRayDirection; this._pickingCollision.rayOriginIsInsideBounds = rayEntryDistance == 0; return true; }; PickEntity.prototype.isIntersectingShape = function (findClosestCollision) { var shapeHit = false; for (var i = this._activePickables.length - 1; i >= 0; i--) { if (this._activePickables[i].testCollision(this._pickingCollision, findClosestCollision)) { if (!findClosestCollision) return true; else shapeHit = true; } } return shapeHit; }; PickEntity.prototype._getBoxBoundsInternal = function (matrix3D, strokeFlag, fastFlag, cache, target) { if (matrix3D === void 0) { matrix3D = null; } if (strokeFlag === void 0) { strokeFlag = true; } if (fastFlag === void 0) { fastFlag = true; } if (cache === void 0) { cache = null; } if (target === void 0) { target = null; } //TODO: this is required to reset invalidation on HierarchicalProperty.SCENE_TRANSFORM //Should no longer be required once BoundsPicker uses isolated node trees this._asset.getMatrix3D(); if (this._invalid) this._update(); var numPickables = this._activePickables.length; if (numPickables) { if (fastFlag) { var obb = void 0; var strokeIndex = strokeFlag ? 1 : 0; if (this._orientedBoxBoundsDirty[strokeIndex]) { this._orientedBoxBoundsDirty[strokeIndex] = false; for (var i = 0; i < numPickables; i++) { obb = this._activePickables[i].getBoxBounds(null, strokeFlag, this._orientedBoxBounds[strokeIndex], obb); } this._orientedBoxBounds[strokeIndex] = obb; } else { obb = this._orientedBoxBounds[strokeIndex]; } if (obb != null) { target = (matrix3D) ? matrix3D.transformBox(obb).union(target, target || cache) : obb.union(target, target || cache); } } else { for (var i = 0; i < numPickables; i++) target = this._activePickables[i].getBoxBounds(matrix3D, strokeFlag, cache, target); } } return target; }; PickEntity.prototype._getSphereBoundsInternal = function (center, matrix3D, strokeFlag, fastFlag, cache, target) { if (center === void 0) { center = null; } if (matrix3D === void 0) { matrix3D = null; } if (strokeFlag === void 0) { strokeFlag = true; } if (fastFlag === void 0) { fastFlag = true; } if (cache === void 0) { cache = null; } if (target === void 0) { target = null; } if (this._invalid) this._update(); var box = this._getBoxBoundsInternal(matrix3D, strokeFlag); if (box == null) return; if (!center) { center = new Vector3D(); center.x = box.x + box.width / 2; center.y = box.y + box.height / 2; center.z = box.z + box.depth / 2; } var numPickables = this._activePickables.length; if (numPickables) { if (fastFlag) { var osb = void 0; var strokeIndex = strokeFlag ? 1 : 0; if (this._orientedSphereBoundsDirty[strokeIndex]) { this._orientedSphereBoundsDirty[strokeIndex] = false; for (var i = 0; i < numPickables; i++) { osb = this._activePickables[i].getSphereBounds(center, null, strokeFlag, this._orientedSphereBounds[strokeIndex], osb); } this._orientedSphereBounds[strokeIndex] = osb; } else { osb = this._orientedSphereBounds[strokeIndex]; } if (osb != null) { target = (matrix3D) ? matrix3D.transformSphere(osb).union(target, target || cache) : osb.union(target, target || cache); } } else { for (var i = 0; i < numPickables; i++) target = this._activePickables[i].getSphereBounds(center, matrix3D, strokeFlag, cache, target); } } return target; }; PickEntity.prototype.applyTraversable = function (traversable) { //is the traversable a mask? this._activePickables.push(traversable.getAbstraction(this)); }; PickEntity.prototype.addBoundingVolume = function (boundingVolume) { this._boundingVolumes.add(boundingVolume); }; PickEntity.prototype.removeBoundingVolume = function (boundingVolume) { this._boundingVolumes.remove(boundingVolume); }; PickEntity.prototype.addPickable = function (pickable) { this._pickables.add(pickable); }; PickEntity.prototype.removePickable = function (pickable) { this._pickables.remove(pickable); }; PickEntity.prototype.onInvalidate = function (event) { _super.prototype.onInvalidate.call(this, event); this._activePickables = []; this._orientedBoxBoundsDirty[0] = true; this._orientedBoxBoundsDirty[1] = true; this._orientedSphereBoundsDirty[0] = true; this._orientedSphereBoundsDirty[1] = true; this._boundingVolumes.forEach(function (boundingVolume) { return boundingVolume.onInvalidate(event); }); }; PickEntity.prototype.onClear = function (event) { _super.prototype.onClear.call(this, event); this._boundingVolumes.forEach(function (boundingVolume) { return boundingVolume.onClear(event); }); this._boundingVolumePools = null; this._pickables.forEach(function (pickable) { return pickable.onClear(event); }); this._pickingCollision = null; this._pickables = null; this._activePickables = []; this._orientedBoxBoundsDirty[0] = true; this._orientedBoxBoundsDirty[1] = true; this._orientedSphereBoundsDirty[0] = true; this._orientedSphereBoundsDirty[1] = true; }; PickEntity.prototype.requestAbstraction = function (asset) { var store = PickEntity._store[asset.assetType]; return store.length ? store.pop() : new PickEntity._pickPickableClassPool[asset.assetType](); }; PickEntity.prototype.storeAbstraction = function (abstraction) { PickEntity._store[abstraction.asset.assetType].push(abstraction); }; /** * * @param imageObjectClass */ PickEntity.registerPickable = function (pickClass, assetClass) { PickEntity._pickPickableClassPool[assetClass.assetType] = pickClass; PickEntity._store[assetClass.assetType] = []; }; PickEntity.prototype._update = function () { this._invalid = false; var entity = this._asset.container.getEntity(); entity._acceptTraverser(this); }; PickEntity.prototype._isIntersectingMasks = function (rootEntity, globalRayPosition, globalRayDirection) { //horrible hack for 2d masks //do the mask thang var maskOwners = this._asset.getMaskOwners(); if (maskOwners) { var numOwners = maskOwners.length; var node = void 0; var masks = void 0; var numMasks = void 0; var maskHit = void 0; for (var i = 0; i < numOwners; i++) { node = maskOwners[i]; if (!node.isDescendant(rootEntity)) continue; masks = node.getMasks(); numMasks = masks.length; maskHit = false; for (var j = 0; j < numMasks; j++) { node = masks[j]; if (!node.isDescendant(rootEntity)) continue; // todo: figure out why a mask can be null here! if (node && this.pickGroup .getRaycastPicker(node) ._getCollisionInternal(globalRayPosition, globalRayDirection, true, true, null)) { maskHit = true; break; } } if (!maskHit) return false; } } return true; }; PickEntity._store = {}; PickEntity.MINIMAL_SCALE = 0.00001; PickEntity._pickPickableClassPool = new Object(); return PickEntity; }(AbstractionBase)); export { PickEntity };