dragonbones-runtime
Version:
the tools to build dragonbones file for diffrent framework
583 lines (539 loc) • 25.9 kB
text/typescript
/**
* The MIT License (MIT)
*
* Copyright (c) 2012-2017 DragonBones team and other contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
namespace dragonBones {
/**
* @internal
* @private
*/
export class Surface extends Bone {
public static toString(): string {
return "[class dragonBones.Surface]";
}
private _dX: number;
private _dY: number;
private _k: number;
private _kX: number;
private _kY: number;
/**
* For debug draw.
* @internal
* @private
*/
public readonly _vertices: Array<number> = [];
/**
* For timeline state.
* @internal
* @private
*/
public readonly _deformVertices: Array<number> = [];
/**
* x1, y1, x2, y2, x3, y3, x4, y4, d1X, d1Y, d2X, d2Y
*/
private readonly _hullCache: Array<number> = [];
/**
* Inside [flag, a, b, c, d, tx, ty], Outside [flag, a, b, c, d, tx, ty]
*/
private readonly _matrixCahce: Array<number> = [];
/**
* @inheritDoc
*/
protected _onClear(): void {
super._onClear();
this._dX = 0.0;
this._dY = 0.0;
this._k = 0.0;
this._kX = 0.0;
this._kY = 0.0;
this._vertices.length = 0;
this._deformVertices.length = 0;
this._matrixCahce.length = 0;
this._hullCache.length = 0;
}
private _getAffineTransform(
x: number, y: number, lX: number, lY: number,
aX: number, aY: number, bX: number, bY: number, cX: number, cY: number,
transform: Transform, matrix: Matrix, isDown: boolean
): void {
const dabX = bX - aX;
const dabY = bY - aY;
const dacX = cX - aX;
const dacY = cY - aY;
transform.rotation = Math.atan2(dabY, dabX);
transform.skew = Math.atan2(dacY, dacX) - Math.PI * 0.5 - transform.rotation;
if (isDown) {
transform.rotation += Math.PI;
}
transform.scaleX = Math.sqrt(dabX * dabX + dabY * dabY) / lX;
transform.scaleY = Math.sqrt(dacX * dacX + dacY * dacY) / lY;
transform.toMatrix(matrix);
transform.x = matrix.tx = aX - (matrix.a * x + matrix.c * y);
transform.y = matrix.ty = aY - (matrix.b * x + matrix.d * y);
}
private _updateVertices(): void {
const originalVertices = (this._boneData as SurfaceData).vertices;
const vertices = this._vertices;
const animationVertices = this._deformVertices;
if (this._parent !== null) {
if (this._parent._boneData.type === BoneType.Surface) {
for (let i = 0, l = originalVertices.length; i < l; i += 2) {
const x = originalVertices[i] + animationVertices[i];
const y = originalVertices[i + 1] + animationVertices[i];
const matrix = (this._parent as Surface)._getGlobalTransformMatrix(x, y);
//
vertices[i] = matrix.a * x + matrix.c * y + matrix.tx;
vertices[i + 1] = matrix.b * x + matrix.d * y + matrix.ty;
}
}
else {
const parentMatrix = this._parent.globalTransformMatrix;
for (let i = 0, l = originalVertices.length; i < l; i += 2) {
const x = originalVertices[i] + animationVertices[i];
const y = originalVertices[i + 1] + animationVertices[i + 1];
//
vertices[i] = parentMatrix.a * x + parentMatrix.c * y + parentMatrix.tx;
vertices[i + 1] = parentMatrix.b * x + parentMatrix.d * y + parentMatrix.ty;
}
}
}
else {
for (let i = 0, l = originalVertices.length; i < l; i += 2) {
vertices[i] = originalVertices[i] + animationVertices[i];
vertices[i + 1] = originalVertices[i + 1] + animationVertices[i + 1];
}
}
}
/**
* @private
*/
protected _updateGlobalTransformMatrix(isCache: boolean): void {
// tslint:disable-next-line:no-unused-expression
isCache;
const segmentXD = (this._boneData as SurfaceData).segmentX * 2;
const lastIndex = this._vertices.length - 2;
const lA = 200.0;
//
const raX = this._vertices[0];
const raY = this._vertices[1];
const rbX = this._vertices[segmentXD];
const rbY = this._vertices[segmentXD + 1];
const rcX = this._vertices[lastIndex];
const rcY = this._vertices[lastIndex + 1];
const rdX = this._vertices[lastIndex - segmentXD];
const rdY = this._vertices[lastIndex - segmentXD + 1];
//
const dacX = raX + (rcX - raX) * 0.5;
const dacY = raY + (rcY - raY) * 0.5;
const dbdX = rbX + (rdX - rbX) * 0.5;
const dbdY = rbY + (rdY - rbY) * 0.5;
const aX = dacX + (dbdX - dacX) * 0.5;
const aY = dacY + (dbdY - dacY) * 0.5;
const bX = rbX + (rcX - rbX) * 0.5;
const bY = rbY + (rcY - rbY) * 0.5;
const cX = rdX + (rcX - rdX) * 0.5;
const cY = rdY + (rcY - rdY) * 0.5;
//
this._globalDirty = false;
this._getAffineTransform(0.0, 0.0, lA, lA, aX, aY, bX, bY, cX, cY, this.global, this.globalTransformMatrix, false);
}
public _getGlobalTransformMatrix(x: number, y: number): Matrix {
const lB = 1000.0;
if (x < -lB || lB < x || y < -lB || lB < y) {
return this.globalTransformMatrix;
}
let isDown = false;
const lA = 200.0;
const surfaceData = this._boneData as SurfaceData;
const segmentX = surfaceData.segmentX;
const segmentY = surfaceData.segmentY;
const segmentXD = surfaceData.segmentX * 2;
const dX = this._dX;
const dY = this._dY;
const indexX = Math.floor((x + lA) / dX);
const indexY = Math.floor((y + lA) / dY);
let matrixIndex = 0;
let pX = indexX * dX - lA;
let pY = indexY * dY - lA;
const matrices = this._matrixCahce;
const helpMatrix = Surface._helpMatrix;
if (x < -lA) {
if (y < -lA || y > lA) {
return this.globalTransformMatrix;
}
isDown = y > this._kX * (x + lA) + pY;
matrixIndex = ((segmentX * (segmentY + 1) + segmentX * 2 + segmentY + indexY) * 2 + (isDown ? 1 : 0)) * 7;
if (this._matrixCahce[matrixIndex] > 0.0) {
helpMatrix.copyFromArray(matrices, matrixIndex + 1);
}
else {
const vertexIndex = indexY * (segmentXD + 2);
const ddX = this._hullCache[4];
const ddY = this._hullCache[5];
const sX = this._hullCache[2] - (segmentY - indexY) * ddX;
const sY = this._hullCache[3] - (segmentY - indexY) * ddY;
const vertices = this._vertices;
if (isDown) {
this._getAffineTransform(
-lA, pY + dY, lB - lA, dY,
vertices[vertexIndex + segmentXD + 2],
vertices[vertexIndex + segmentXD + 3],
sX + ddX,
sY + ddY,
vertices[vertexIndex],
vertices[vertexIndex + 1],
Surface._helpTransform, helpMatrix, true);
}
else {
this._getAffineTransform(
-lB, pY, lB - lA, dY,
sX,
sY,
vertices[vertexIndex],
vertices[vertexIndex + 1],
sX + ddX,
sY + ddY,
Surface._helpTransform, helpMatrix, false);
}
matrices[matrixIndex] = 1.0;
matrices[matrixIndex + 1] = helpMatrix.a;
matrices[matrixIndex + 2] = helpMatrix.b;
matrices[matrixIndex + 3] = helpMatrix.c;
matrices[matrixIndex + 4] = helpMatrix.d;
matrices[matrixIndex + 5] = helpMatrix.tx;
matrices[matrixIndex + 6] = helpMatrix.ty;
}
}
else if (x > lA) {
if (y < -lA || y > lA) {
return this.globalTransformMatrix;
}
isDown = y > this._kX * (x - lB) + pY;
matrixIndex = ((segmentX * (segmentY + 1) + segmentX + indexY) * 2 + (isDown ? 1 : 0)) * 7;
if (this._matrixCahce[matrixIndex] > 0.0) {
helpMatrix.copyFromArray(matrices, matrixIndex + 1);
}
else {
const vertexIndex = (indexY + 1) * (segmentXD + 2) - 2;
const ddX = this._hullCache[4];
const ddY = this._hullCache[5];
const sX = this._hullCache[0] + indexY * ddX;
const sY = this._hullCache[1] + indexY * ddY;
const vertices = this._vertices;
if (isDown) {
this._getAffineTransform(
lB, pY + dY, lB - lA, dY,
sX + ddX,
sY + ddY,
vertices[vertexIndex + segmentXD + 2],
vertices[vertexIndex + segmentXD + 3],
sX,
sY,
Surface._helpTransform, helpMatrix, true);
}
else {
this._getAffineTransform(
lA, pY, lB - lA, dY,
vertices[vertexIndex],
vertices[vertexIndex + 1],
sX,
sY,
vertices[vertexIndex + segmentXD + 2],
vertices[vertexIndex + segmentXD + 3],
Surface._helpTransform, helpMatrix, false);
}
matrices[matrixIndex] = 1.0;
matrices[matrixIndex + 1] = helpMatrix.a;
matrices[matrixIndex + 2] = helpMatrix.b;
matrices[matrixIndex + 3] = helpMatrix.c;
matrices[matrixIndex + 4] = helpMatrix.d;
matrices[matrixIndex + 5] = helpMatrix.tx;
matrices[matrixIndex + 6] = helpMatrix.ty;
}
}
else if (y < -lA) {
if (x < -lA || x > lA) {
return this.globalTransformMatrix;
}
isDown = y > this._kY * (x - pX - dX) - lB;
matrixIndex = (segmentX * (segmentY + 1) + indexX * 2 + (isDown ? 1 : 0)) * 7;
if (this._matrixCahce[matrixIndex] > 0.0) {
helpMatrix.copyFromArray(matrices, matrixIndex + 1);
}
else {
const vertexIndex = indexX * 2;
const ddX = this._hullCache[10];
const ddY = this._hullCache[11];
const sX = this._hullCache[8] + indexX * ddX;
const sY = this._hullCache[9] + indexX * ddY;
const vertices = this._vertices;
if (isDown) {
this._getAffineTransform(
pX + dX, -lA, dX, lB - lA,
vertices[vertexIndex + 2],
vertices[vertexIndex + 3],
vertices[vertexIndex],
vertices[vertexIndex + 1],
sX + ddX,
sY + ddY,
Surface._helpTransform, helpMatrix, true);
}
else {
this._getAffineTransform(
pX, -lB, dX, lB - lA,
sX,
sY,
sX + ddX,
sY + ddY,
vertices[vertexIndex],
vertices[vertexIndex + 1],
Surface._helpTransform, helpMatrix, false);
}
matrices[matrixIndex] = 1.0;
matrices[matrixIndex + 1] = helpMatrix.a;
matrices[matrixIndex + 2] = helpMatrix.b;
matrices[matrixIndex + 3] = helpMatrix.c;
matrices[matrixIndex + 4] = helpMatrix.d;
matrices[matrixIndex + 5] = helpMatrix.tx;
matrices[matrixIndex + 6] = helpMatrix.ty;
}
}
else if (y > lA) {
if (x < -lA || x > lA) {
return this.globalTransformMatrix;
}
isDown = y > this._kY * (x - pX - dX) + lA;
matrixIndex = ((segmentX * (segmentY + 1) + segmentX + segmentY + indexY) * 2 + (isDown ? 1 : 0)) * 7;
if (this._matrixCahce[matrixIndex] > 0.0) {
helpMatrix.copyFromArray(matrices, matrixIndex + 1);
}
else {
const vertexIndex = segmentY * (segmentXD + 2) + indexX * 2;
const ddX = this._hullCache[10];
const ddY = this._hullCache[11];
const sX = this._hullCache[6] - (segmentX - indexX) * ddX;
const sY = this._hullCache[7] - (segmentX - indexX) * ddY;
const vertices = this._vertices;
if (isDown) {
this._getAffineTransform(
pX + dX, lB, dX, lB - lA,
sX + ddX,
sY + ddY,
sX,
sY,
vertices[vertexIndex + 2],
vertices[vertexIndex + 3],
Surface._helpTransform, helpMatrix, true);
}
else {
this._getAffineTransform(
pX, lA, dX, lB - lA,
vertices[vertexIndex],
vertices[vertexIndex + 1],
vertices[vertexIndex + 2],
vertices[vertexIndex + 3],
sX,
sY,
Surface._helpTransform, helpMatrix, false);
}
matrices[matrixIndex] = 1.0;
matrices[matrixIndex + 1] = helpMatrix.a;
matrices[matrixIndex + 2] = helpMatrix.b;
matrices[matrixIndex + 3] = helpMatrix.c;
matrices[matrixIndex + 4] = helpMatrix.d;
matrices[matrixIndex + 5] = helpMatrix.tx;
matrices[matrixIndex + 6] = helpMatrix.ty;
}
}
else {
isDown = y > this._k * (x - pX - dX) + pY;
matrixIndex = ((segmentX * indexY + indexX) * 2 + (isDown ? 1 : 0)) * 7;
if (this._matrixCahce[matrixIndex] > 0.0) {
helpMatrix.copyFromArray(matrices, matrixIndex + 1);
}
else {
const vertexIndex = indexX * 2 + indexY * (segmentXD + 2);
const vertices = this._vertices;
if (isDown) {
this._getAffineTransform(
pX + dX, pY + dY, dX, dY,
vertices[vertexIndex + segmentXD + 4],
vertices[vertexIndex + segmentXD + 5],
vertices[vertexIndex + segmentXD + 2],
vertices[vertexIndex + segmentXD + 3],
vertices[vertexIndex + 2],
vertices[vertexIndex + 3],
Surface._helpTransform, helpMatrix, true);
}
else {
this._getAffineTransform(
pX, pY, dX, dY,
vertices[vertexIndex],
vertices[vertexIndex + 1],
vertices[vertexIndex + 2],
vertices[vertexIndex + 3],
vertices[vertexIndex + segmentXD + 2],
vertices[vertexIndex + segmentXD + 3],
Surface._helpTransform, helpMatrix, false);
}
matrices[matrixIndex] = 1.0;
matrices[matrixIndex + 1] = helpMatrix.a;
matrices[matrixIndex + 2] = helpMatrix.b;
matrices[matrixIndex + 3] = helpMatrix.c;
matrices[matrixIndex + 4] = helpMatrix.d;
matrices[matrixIndex + 5] = helpMatrix.tx;
matrices[matrixIndex + 6] = helpMatrix.ty;
}
}
return helpMatrix;
}
public init(surfaceData: SurfaceData): void {
if (this._boneData !== null) {
return;
}
super.init(surfaceData);
const segmentX = surfaceData.segmentX;
const segmentY = surfaceData.segmentY;
const vertexCount = surfaceData.vertices.length;
const lB = 1000.0;
const lA = 200.0;
//
this._dX = lA * 2.0 / segmentX;
this._dY = lA * 2.0 / segmentY;
this._k = -this._dY / this._dX;
this._kX = -this._dY / (lB - lA);
this._kY = -(lB - lA) / this._dX;
this._vertices.length = vertexCount;
this._deformVertices.length = vertexCount;
this._matrixCahce.length = (segmentX * segmentY + segmentX * 2 + segmentY * 2) * 2 * 7;
this._hullCache.length = 10;
for (let i = 0; i < vertexCount; ++i) {
this._deformVertices[i] = 0.0;
}
}
/**
* @internal
* @private
*/
public update(cacheFrameIndex: number): void {
this._blendState.dirty = false;
if (cacheFrameIndex >= 0 && this._cachedFrameIndices !== null) {
const cachedFrameIndex = this._cachedFrameIndices[cacheFrameIndex];
if (cachedFrameIndex >= 0 && this._cachedFrameIndex === cachedFrameIndex) { // Same cache.
this._transformDirty = false;
}
else if (cachedFrameIndex >= 0) { // Has been Cached.
this._transformDirty = true;
this._cachedFrameIndex = cachedFrameIndex;
}
else {
if (this._hasConstraint) { // Update constraints.
for (const constraint of this._armature._constraints) {
if (constraint._root === this) {
constraint.update();
}
}
}
if (
this._transformDirty ||
(this._parent !== null && this._parent._childrenTransformDirty)
) { // Dirty.
this._transformDirty = true;
this._cachedFrameIndex = -1;
}
else if (this._cachedFrameIndex >= 0) { // Same cache, but not set index yet.
this._transformDirty = false;
this._cachedFrameIndices[cacheFrameIndex] = this._cachedFrameIndex;
}
else { // Dirty.
this._transformDirty = true;
this._cachedFrameIndex = -1;
}
}
}
else {
if (this._hasConstraint) { // Update constraints.
for (const constraint of this._armature._constraints) {
if (constraint._root === this) {
constraint.update();
}
}
}
if (this._transformDirty || (this._parent !== null && this._parent._childrenTransformDirty)) { // Dirty.
cacheFrameIndex = -1;
this._transformDirty = true;
this._cachedFrameIndex = -1;
}
}
if (this._transformDirty) {
this._transformDirty = false;
this._childrenTransformDirty = true;
//
for (let i = 0, l = this._matrixCahce.length; i < l; i += 7) {
this._matrixCahce[i] = -1.0;
}
//
this._updateVertices();
//
if (this._cachedFrameIndex < 0) {
const isCache = cacheFrameIndex >= 0;
if (this._localDirty) {
this._updateGlobalTransformMatrix(isCache);
}
if (isCache && this._cachedFrameIndices !== null) {
this._cachedFrameIndex = this._cachedFrameIndices[cacheFrameIndex] = this._armature._armatureData.setCacheFrame(this.globalTransformMatrix, this.global);
}
}
else {
this._armature._armatureData.getCacheFrame(this.globalTransformMatrix, this.global, this._cachedFrameIndex);
}
// Update hull vertices.
const lB = 1000.0;
const lA = 200.0;
const ddX = 2 * this.global.x;
const ddY = 2 * this.global.y;
//
const helpPoint = Surface._helpPoint;
this.globalTransformMatrix.transformPoint(lB, -lA, helpPoint);
this._hullCache[0] = helpPoint.x;
this._hullCache[1] = helpPoint.y;
this._hullCache[2] = ddX - helpPoint.x;
this._hullCache[3] = ddY - helpPoint.y;
this.globalTransformMatrix.transformPoint(0.0, this._dY, helpPoint, true);
this._hullCache[4] = helpPoint.x;
this._hullCache[5] = helpPoint.y;
//
this.globalTransformMatrix.transformPoint(lA, lB, helpPoint);
this._hullCache[6] = helpPoint.x;
this._hullCache[7] = helpPoint.y;
this._hullCache[8] = ddX - helpPoint.x;
this._hullCache[9] = ddY - helpPoint.y;
this.globalTransformMatrix.transformPoint(this._dX, 0.0, helpPoint, true);
this._hullCache[10] = helpPoint.x;
this._hullCache[11] = helpPoint.y;
}
else if (this._childrenTransformDirty) {
this._childrenTransformDirty = false;
}
this._localDirty = true;
}
}
}