@awayjs/graphics
Version:
AwayJS graphics classes
445 lines (444 loc) • 18 kB
JavaScript
import { __extends } from "tslib";
import { Box, AssetBase } from '@awayjs/core';
import { PickEntity, _Pick_PickableBase, PickGroup } from '@awayjs/view';
import { RenderableEvent, StyleEvent, ElementsEvent, TriangleElements } from '@awayjs/renderer';
/**
* Graphic wraps a Elements as a scene graph instantiation. A Graphic is owned by a Sprite object.
*
*
* @see away.base.ElementsBase
* @see away.entities.Sprite
*
* @class away.base.Graphic
*/
var Shape = /** @class */ (function (_super) {
__extends(Shape, _super);
/**
* Creates a new Shape object
*/
function Shape(elements, material, style, count, offset) {
if (material === void 0) { material = null; }
if (style === void 0) { style = null; }
if (count === void 0) { count = 0; }
if (offset === void 0) { offset = 0; }
var _this = _super.call(this) || this;
_this.usages = 0;
_this.count = 0;
_this.offset = 0;
_this.particleCollection = null;
_this.originalFillStyle = null;
/**
* Process per-triangle hit test - superslow for huge elements
*/
_this.deepHitCheck = true;
_this._onInvalidatePropertiesDelegate = function (event) { return _this._onInvalidateProperties(event); };
_this._onInvalidateVerticesDelegate = function (event) { return _this._onInvalidateVertices(event); };
_this._elements = elements;
_this._elements.addEventListener(ElementsEvent.INVALIDATE_VERTICES, _this._onInvalidateVerticesDelegate);
_this._elements.usages++;
_this._material = material;
_this._style = style;
if (_this._style)
_this._style.addEventListener(StyleEvent.INVALIDATE_PROPERTIES, _this._onInvalidatePropertiesDelegate);
_this.count = count;
_this.offset = offset;
return _this;
}
Shape.getShape = function (elements, material, style, count, offset) {
if (material === void 0) { material = null; }
if (style === void 0) { style = null; }
if (count === void 0) { count = 0; }
if (offset === void 0) { offset = 0; }
if (Shape._pool.length) {
var shape = Shape._pool.pop();
shape.elements = elements;
shape.material = material;
shape.style = style;
shape.count = count;
shape.offset = offset;
return shape;
}
return new Shape(elements, material, style, count, offset);
};
Shape.clearPool = function () {
Shape._pool = [];
};
Shape.quadElement = function (rect, slices, genUv) {
if (slices === void 0) { slices = 1; }
if (genUv === void 0) { genUv = false; }
var verts = [];
var uvs = [];
var w = rect.width / slices;
var h = rect.height / slices;
var ix = rect.x;
var iy = rect.y;
for (var i = 0; i < slices; i++) {
for (var j = 0; j < slices; j++) {
var x = ix + j * w;
var y = iy + i * h;
var right = x + w;
var bottom = y + h;
verts.push(x, y, 0, right, bottom, 0, right, y, 0, x, y, 0, x, bottom, 0, right, bottom, 0);
if (uvs) {
uvs.push(j / slices, i / slices, (j + 1) / slices, (i + 1) / slices, (j + 1) / slices, i / slices, j / slices, i / slices, j / slices, (i + 1) / slices, (j + 1) / slices, (i + 1) / slices);
}
}
}
var elements = new TriangleElements();
elements.setPositions(verts);
genUv && elements.setUVs(uvs);
return elements;
};
// legacy
Shape.getElement = function (rectangle) {
var x = rectangle.x, y = rectangle.y, right = rectangle.right, bottom = rectangle.bottom;
var elements = new TriangleElements();
elements.setPositions([
x, y, 0,
right, y, 0,
right, bottom, 0,
x, y, 0,
x, bottom, 0,
right, bottom, 0,
]);
return elements;
};
Shape.getTriangleElement = function (rectangle, cache, uv, slices) {
var _this = this;
if (cache === void 0) { cache = true; }
if (uv === void 0) { uv = false; }
if (slices === void 0) { slices = 1; }
var id = rectangle.toString();
var elements = cache ? this._imageShapeElements[id] : null;
if (!elements) {
elements = Shape.quadElement(rectangle, slices, uv);
if (cache) {
this._imageShapeElements[id] = elements;
// remove it from pool, when forget about shared usage
elements.addEventListener(AssetEvent.CLEAR, function () {
delete _this._imageShapeElements[id];
elements.usages = 0;
});
elements.usages++;
}
}
return elements;
};
Object.defineProperty(Shape.prototype, "elements", {
/**
* The Elements object which provides the geometry data for this Shape.
*/
get: function () {
return this._elements;
},
set: function (value) {
if (this._elements == value)
return;
if (this._elements) {
this._elements.removeEventListener(ElementsEvent.INVALIDATE_VERTICES, this._onInvalidateVerticesDelegate);
this._elements.usages--;
if (!this._elements.usages)
this._elements.dispose();
}
this._elements = value;
if (this._elements) {
this._elements.addEventListener(ElementsEvent.INVALIDATE_VERTICES, this._onInvalidateVerticesDelegate);
this._elements.usages++;
}
this.invalidateElements();
},
enumerable: false,
configurable: true
});
Object.defineProperty(Shape.prototype, "assetType", {
/**
*
*/
get: function () {
return Shape.assetType;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Shape.prototype, "material", {
/**
* The material used to render the current Shape.
* If set to null, the containing Graphics's material will be used instead.
*/
get: function () {
return this._material;
},
set: function (value) {
if (this._material == value)
return;
this._material = value;
this.invalidateMaterial();
},
enumerable: false,
configurable: true
});
Object.defineProperty(Shape.prototype, "style", {
/**
* The style used to render the current Shape. If set to null, its parent Sprite's style will be used instead.
*/
get: function () {
return this._style;
},
set: function (value) {
if (this._style == value)
return;
if (this._style)
this._style.removeEventListener(StyleEvent.INVALIDATE_PROPERTIES, this._onInvalidatePropertiesDelegate);
this._style = value;
if (this._style)
this._style.addEventListener(StyleEvent.INVALIDATE_PROPERTIES, this._onInvalidatePropertiesDelegate);
this.invalidateStyle();
},
enumerable: false,
configurable: true
});
/**
*
*/
Shape.prototype.dispose = function () {
_super.prototype.clear.call(this);
this.usages = 0;
this.elements = null;
this.material = null;
this.style = null;
this.particleCollection = null;
Shape._pool.push(this);
};
Shape.prototype.invalidateElements = function () {
this.dispatchEvent(new RenderableEvent(RenderableEvent.INVALIDATE_ELEMENTS, this));
};
Shape.prototype.invalidateMaterial = function () {
this.dispatchEvent(new RenderableEvent(RenderableEvent.INVALIDATE_MATERIAL, this));
};
Shape.prototype.invalidateStyle = function () {
this.dispatchEvent(new RenderableEvent(RenderableEvent.INVALIDATE_STYLE, this));
};
Shape.prototype._onInvalidateProperties = function (event) {
this.invalidateStyle();
};
Shape.prototype._onInvalidateVertices = function (event) {
if (event.attributesView != event.target.positions)
return;
this.invalidate();
};
/**
* //TODO
*
* @param shortestCollisionDistance
* @param findClosest
* @returns {boolean}
*
* @internal
*/
Shape.prototype.applyTransformation = function (transform) {
this._elements.applyTransformation(transform, this.count, this.offset);
};
Shape.prototype.scale = function (scale) {
this._elements.scale(scale, this.count, this.offset);
};
Shape.prototype.scaleUV = function (scaleU, scaleV) {
if (scaleU === void 0) { scaleU = 1; }
if (scaleV === void 0) { scaleV = 1; }
this._elements.scaleUV(scaleU, scaleV, this.count, this.offset);
};
Shape._pool = new Array();
Shape.assetType = '[asset Shape]';
Shape._imageShapeElements = {};
return Shape;
}(AssetBase));
export { Shape };
import { AssetEvent } from '@awayjs/core';
import { _Render_RenderableBase, RenderEntity, MaterialUtils, LineElements } from '@awayjs/renderer';
import { BitmapFillStyle } from '../draw/fills/BitmapFillStyle';
/**
* @class away.pool._Render_Shape
*/
var _Render_Shape = /** @class */ (function (_super) {
__extends(_Render_Shape, _super);
function _Render_Shape() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this._globalBounds = new Box();
return _this;
}
_Render_Shape.prototype.globalBounds = function () {
return this.node.getMatrix3D().transformBox(PickGroup.getInstance().getBoundsPicker(this.node.partition).getBoxBounds(this.node, true, true), this._globalBounds);
};
/**
* //TODO
*
* @param renderEntity
* @param shape
* @param level
* @param indexOffset
*/
_Render_Shape.prototype.init = function (shape, renderEntity) {
_super.prototype.init.call(this, shape, renderEntity);
this.shape = shape;
};
_Render_Shape.prototype.onClear = function (event) {
_super.prototype.onClear.call(this, event);
this.shape = null;
this._scaleX = null;
this._scaleY = null;
this._scale9Elements = null;
};
/**
*
* @returns {ElementsBase}
* @protected
*/
_Render_Shape.prototype._getStageElements = function () {
this._offset = this.shape.offset;
this._count = this.shape.count;
var _scale9Container = this.node.getScale9Container();
if (_scale9Container) {
return this.updateScale9(_scale9Container.scale9Grid, _scale9Container.transform.scale.x, _scale9Container.transform.scale.y)
.getAbstraction(this._stage);
}
var container = this.node.container;
var elements = container.animator
? container.animator.getRenderableElements(this, this.shape.elements)
: this.shape.elements;
return elements.getAbstraction(this._stage);
};
_Render_Shape.prototype._getRenderMaterial = function () {
var material = this._asset.material ||
this.node.container.material ||
this.getDefaultMaterial();
return material.getAbstraction(this.renderer.getRenderElements(this.shape.elements));
};
_Render_Shape.prototype._getStyle = function () {
return this._asset.style || this.node.container.style;
};
_Render_Shape.prototype.getDefaultMaterial = function () {
return this.stageElements.elements instanceof LineElements
? MaterialUtils.getDefaultColorMaterial()
: MaterialUtils.getDefaultTextureMaterial();
};
_Render_Shape.prototype.updateScale9 = function (scale9Grid, scaleX, scaleY) {
if (!this._scale9Elements) {
var uvMatrix = null;
var generateUV = false;
if (this.shape.originalFillStyle instanceof BitmapFillStyle)
uvMatrix = this.shape.originalFillStyle.getUVMatrix();
if (this.shape.elements instanceof TriangleElements) {
generateUV = !this.shape.elements.uvs && !!uvMatrix;
}
// kill UV matrix if we will generate UV
if (generateUV) {
this.shape.style.uvMatrix = null;
}
var bounds = PickGroup.getInstance()
.getBoundsPicker(this.node.partition)
.getBoxBounds(this.node, true, true);
this._scale9Elements = this.shape.elements.prepareScale9(bounds, scale9Grid, true, generateUV, uvMatrix);
}
if (this._scaleX != scaleX || this._scaleY != scaleY) {
this._scaleX = scaleX;
this._scaleY = scaleY;
this._scale9Elements.updateScale9(scaleX, scaleY);
}
return this._scale9Elements;
};
return _Render_Shape;
}(_Render_RenderableBase));
export { _Render_Shape };
/**
* @class away.pool._Render_Shape
*/
var _Pick_Shape = /** @class */ (function (_super) {
__extends(_Pick_Shape, _super);
function _Pick_Shape() {
var _this = _super.call(this) || this;
_this._orientedBoxBoundsDirty = true;
_this._orientedSphereBoundsDirty = true;
_this._onInvalidateElementsDelegate = function (event) { return _this._onInvalidateElements(event); };
return _this;
}
/**
* //TODO
*
* @param renderEntity
* @param shape
* @param level
* @param indexOffset
*/
_Pick_Shape.prototype.init = function (shape, pickEntity) {
_super.prototype.init.call(this, shape, pickEntity);
this._asset.addEventListener(RenderableEvent.INVALIDATE_ELEMENTS, this._onInvalidateElementsDelegate);
};
_Pick_Shape.prototype.onInvalidate = function (event) {
_super.prototype.onInvalidate.call(this, event);
this._orientedBoxBoundsDirty = true;
this._orientedSphereBoundsDirty = true;
};
_Pick_Shape.prototype._onInvalidateElements = function (_event) {
this._orientedBoxBoundsDirty = true;
this._orientedSphereBoundsDirty = true;
};
_Pick_Shape.prototype.onClear = function (event) {
this._asset.removeEventListener(RenderableEvent.INVALIDATE_ELEMENTS, this._onInvalidateElementsDelegate);
_super.prototype.onClear.call(this, event);
this._orientedBoxBounds = null;
this._orientedBoxBoundsDirty = true;
this._orientedSphereBounds = null;
this._orientedSphereBoundsDirty = true;
};
_Pick_Shape.prototype.hitTestPoint = function (x, y, z) {
var box = this.getBoxBounds();
//early out for box test
if (box == null || !box.contains(x, y, z))
return false;
return this._asset.elements.hitTestPoint(this._view, this._node, x, y, z, box, this._asset.count, this._asset.offset);
};
_Pick_Shape.prototype.getBoxBounds = function (matrix3D, strokeFlag, cache, target) {
if (matrix3D === void 0) { matrix3D = null; }
if (strokeFlag === void 0) { strokeFlag = true; }
if (cache === void 0) { cache = null; }
if (target === void 0) { target = null; }
if (matrix3D)
return this._asset.elements.getBoxBounds(this._view, this._node, strokeFlag, matrix3D, cache, target, this._asset.count, this._asset.offset);
if (this._orientedBoxBoundsDirty) {
this._orientedBoxBoundsDirty = false;
this._orientedBoxBounds = this._asset.elements.getBoxBounds(this._view, this._node, strokeFlag, null, this._orientedBoxBounds, null, this._asset.count, this._asset.offset);
}
if (this._orientedBoxBounds != null)
target = this._orientedBoxBounds.union(target, target || cache);
return target;
};
_Pick_Shape.prototype.getSphereBounds = function (center, matrix3D, strokeFlag, cache, target) {
if (matrix3D === void 0) { matrix3D = null; }
if (strokeFlag === void 0) { strokeFlag = true; }
if (cache === void 0) { cache = null; }
if (target === void 0) { target = null; }
if (matrix3D)
return this._asset.elements.getSphereBounds(this._view, center, matrix3D, strokeFlag, cache, target, this._asset.count, this._asset.offset);
if (this._orientedSphereBoundsDirty) {
this._orientedSphereBoundsDirty = false;
this._orientedSphereBounds = this._asset.elements.getSphereBounds(this._view, center, null, strokeFlag, this._orientedSphereBounds, null, this._asset.count, this._asset.offset);
}
if (this._orientedSphereBounds != null)
target = this._orientedSphereBounds.union(target, target || cache);
return target;
};
_Pick_Shape.prototype.testCollision = function (collision, findClosestCollision) {
var box = this.getBoxBounds();
var shape = this._asset;
//early out for box test
if (box == null || !box.rayIntersection(collision.rayPosition, collision.rayDirection))
return false;
if (!shape.deepHitCheck) {
return true;
}
return shape.elements.testCollision(this._view, collision, box, findClosestCollision, this._asset.material || collision.containerNode.container.material, this._asset.count || this._asset.elements.numVertices, this._asset.offset);
};
return _Pick_Shape;
}(_Pick_PickableBase));
export { _Pick_Shape };
RenderEntity.registerRenderable(_Render_Shape, Shape);
PickEntity.registerPickable(_Pick_Shape, Shape);