Merge pull request #235 from mzgoddard/calc-transform-cache

Drawable _calculateTransform cache and inline work
This commit is contained in:
Chris Willis-Ford
2018-01-24 15:41:31 -08:00
committed by GitHub

View File

@@ -51,6 +51,12 @@ class Drawable {
this._scale = twgl.v3.create(100, 100); this._scale = twgl.v3.create(100, 100);
this._direction = 90; this._direction = 90;
this._transformDirty = true; this._transformDirty = true;
this._rotationMatrix = twgl.m4.identity();
this._rotationTransformDirty = true;
this._rotationAdjusted = twgl.v3.create();
this._rotationCenterDirty = true;
this._skinScale = twgl.v3.create(0, 0, 0);
this._skinScaleDirty = true;
this._inverseMatrix = twgl.m4.identity(); this._inverseMatrix = twgl.m4.identity();
this._inverseTransformDirty = true; this._inverseTransformDirty = true;
this._visible = true; this._visible = true;
@@ -156,6 +162,7 @@ class Drawable {
} }
if ('direction' in properties && this._direction !== properties.direction) { if ('direction' in properties && this._direction !== properties.direction) {
this._direction = properties.direction; this._direction = properties.direction;
this._rotationTransformDirty = true;
dirty = true; dirty = true;
} }
if ('scale' in properties && ( if ('scale' in properties && (
@@ -163,6 +170,8 @@ class Drawable {
this._scale[1] !== properties.scale[1])) { this._scale[1] !== properties.scale[1])) {
this._scale[0] = properties.scale[0]; this._scale[0] = properties.scale[0];
this._scale[1] = properties.scale[1]; this._scale[1] = properties.scale[1];
this._rotationCenterDirty = true;
this._skinScaleDirty = true;
dirty = true; dirty = true;
} }
if ('visible' in properties) { if ('visible' in properties) {
@@ -197,26 +206,141 @@ class Drawable {
* @private * @private
*/ */
_calculateTransform () { _calculateTransform () {
const modelMatrix = this._uniforms.u_modelMatrix; if (this._rotationTransformDirty) {
const rotation = (270 - this._direction) * Math.PI / 180;
twgl.m4.identity(modelMatrix); // Calling rotationZ sets the destination matrix to a rotation
twgl.m4.translate(modelMatrix, this._position, modelMatrix); // around the Z axis setting matrix components 0, 1, 4 and 5 with
// cosine and sine values of the rotation.
// twgl.m4.rotationZ(rotation, this._rotationMatrix);
const rotation = (270 - this._direction) * Math.PI / 180; // twgl assumes the last value set to the matrix was anything.
twgl.m4.rotateZ(modelMatrix, rotation, modelMatrix); // Drawable knows, it was another rotationZ matrix, so we can skip
// assigning the values that will never change.
const c = Math.cos(rotation);
const s = Math.sin(rotation);
this._rotationMatrix[0] = c;
this._rotationMatrix[1] = s;
// this._rotationMatrix[2] = 0;
// this._rotationMatrix[3] = 0;
this._rotationMatrix[4] = -s;
this._rotationMatrix[5] = c;
// this._rotationMatrix[6] = 0;
// this._rotationMatrix[7] = 0;
// this._rotationMatrix[8] = 0;
// this._rotationMatrix[9] = 0;
// this._rotationMatrix[10] = 1;
// this._rotationMatrix[11] = 0;
// this._rotationMatrix[12] = 0;
// this._rotationMatrix[13] = 0;
// this._rotationMatrix[14] = 0;
// this._rotationMatrix[15] = 1;
this._rotationTransformDirty = false;
}
// Adjust rotation center relative to the skin. // Adjust rotation center relative to the skin.
let rotationAdjusted = twgl.v3.subtract(this.skin.rotationCenter, twgl.v3.divScalar(this.skin.size, 2)); if (this._rotationCenterDirty && this.skin !== null) {
rotationAdjusted = twgl.v3.multiply(rotationAdjusted, this.scale); // twgl version of the following in function work.
rotationAdjusted = twgl.v3.divScalar(rotationAdjusted, 100); // let rotationAdjusted = twgl.v3.subtract(
rotationAdjusted[1] *= -1; // Y flipped to Scratch coordinate. // this.skin.rotationCenter,
rotationAdjusted[2] = 0; // Z coordinate is 0. // twgl.v3.divScalar(this.skin.size, 2, this._rotationAdjusted),
// this._rotationAdjusted
// );
// rotationAdjusted = twgl.v3.multiply(
// rotationAdjusted, this._scale, rotationAdjusted
// );
// rotationAdjusted = twgl.v3.divScalar(
// rotationAdjusted, 100, rotationAdjusted
// );
// rotationAdjusted[1] *= -1; // Y flipped to Scratch coordinate.
// rotationAdjusted[2] = 0; // Z coordinate is 0.
twgl.m4.translate(modelMatrix, rotationAdjusted, modelMatrix); // Locally assign rotationCenter and skinSize to keep from having
// the Skin getter properties called twice while locally assigning
// their components for readability.
const rotationCenter = this.skin.rotationCenter;
const skinSize = this.skin.size;
const center0 = rotationCenter[0];
const center1 = rotationCenter[1];
const skinSize0 = skinSize[0];
const skinSize1 = skinSize[1];
const scale0 = this._scale[0];
const scale1 = this._scale[1];
const scaledSize = twgl.v3.divScalar(twgl.v3.multiply(this.skin.size, this._scale), 100); const rotationAdjusted = this._rotationAdjusted;
scaledSize[2] = 0; // was NaN because the vectors have only 2 components. rotationAdjusted[0] = (center0 - (skinSize0 / 2)) * scale0 / 100;
twgl.m4.scale(modelMatrix, scaledSize, modelMatrix); rotationAdjusted[1] = ((center1 - (skinSize1 / 2)) * scale1 / 100) * -1;
// rotationAdjusted[2] = 0;
this._rotationCenterDirty = false;
}
if (this._skinScaleDirty && this.skin !== null) {
// twgl version of the following in function work.
// const scaledSize = twgl.v3.divScalar(
// twgl.v3.multiply(this.skin.size, this._scale),
// 100
// );
// // was NaN because the vectors have only 2 components.
// scaledSize[2] = 0;
// Locally assign skinSize to keep from having the Skin getter
// properties called twice.
const skinSize = this.skin.size;
const scaledSize = this._skinScale;
scaledSize[0] = skinSize[0] * this._scale[0] / 100;
scaledSize[1] = skinSize[1] * this._scale[1] / 100;
// scaledSize[2] = 0;
this._skinScaleDirty = false;
}
const modelMatrix = this._uniforms.u_modelMatrix;
// twgl version of the following in function work.
// twgl.m4.identity(modelMatrix);
// twgl.m4.translate(modelMatrix, this._position, modelMatrix);
// twgl.m4.multiply(modelMatrix, this._rotationMatrix, modelMatrix);
// twgl.m4.translate(modelMatrix, this._rotationAdjusted, modelMatrix);
// twgl.m4.scale(modelMatrix, scaledSize, modelMatrix);
// Drawable configures a 3D matrix for drawing in WebGL, but most values
// will never be set because the inputs are on the X and Y position axis
// and the Z rotation axis. Drawable can bring the work inside
// _calculateTransform and greatly reduce the ammount of math and array
// assignments needed.
const scale0 = this._skinScale[0];
const scale1 = this._skinScale[1];
const rotation00 = this._rotationMatrix[0];
const rotation01 = this._rotationMatrix[1];
const rotation10 = this._rotationMatrix[4];
const rotation11 = this._rotationMatrix[5];
const adjusted0 = this._rotationAdjusted[0];
const adjusted1 = this._rotationAdjusted[1];
const position0 = this._position[0];
const position1 = this._position[1];
// Commented assignments show what the values are when the matrix was
// instantiated. Those values will never change so they do not need to
// be reassigned.
modelMatrix[0] = scale0 * rotation00;
modelMatrix[1] = scale0 * rotation01;
// modelMatrix[2] = 0;
// modelMatrix[3] = 0;
modelMatrix[4] = scale1 * rotation10;
modelMatrix[5] = scale1 * rotation11;
// modelMatrix[6] = 0;
// modelMatrix[7] = 0;
// modelMatrix[8] = 0;
// modelMatrix[9] = 0;
// modelMatrix[10] = 1;
// modelMatrix[11] = 0;
modelMatrix[12] = (rotation00 * adjusted0) + (rotation10 * adjusted1) + position0;
modelMatrix[13] = (rotation01 * adjusted0) + (rotation11 * adjusted1) + position1;
// modelMatrix[14] = 0;
// modelMatrix[15] = 1;
this._transformDirty = false; this._transformDirty = false;
} }
@@ -369,6 +493,8 @@ class Drawable {
* @private * @private
*/ */
_skinWasAltered () { _skinWasAltered () {
this._rotationCenterDirty = true;
this._skinScaleDirty = true;
this.setConvexHullDirty(); this.setConvexHullDirty();
this.setTransformDirty(); this.setTransformDirty();
} }