@awayjs/view
Version:
View for AwayJS
380 lines (379 loc) • 16.5 kB
JavaScript
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 };