From aa9b4fa3b07dedfe254e44d4d7e59f39e8f1bf37 Mon Sep 17 00:00:00 2001 From: Ulric Wilfred Date: Thu, 17 Dec 2015 17:38:57 +0100 Subject: [PATCH 1/3] reorderings in element.render() to make masks render once for a frame --- src/anm/animation/element.js | 111 ++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 41 deletions(-) diff --git a/src/anm/animation/element.js b/src/anm/animation/element.js index 39b0f564..0bd3a8de 100644 --- a/src/anm/animation/element.js +++ b/src/anm/animation/element.js @@ -744,32 +744,22 @@ Element.prototype._checkSwitcher = function(next) { */ // > Element.render % (ctx: Context, gtime: Float, dt: Float) Element.prototype.render = function(ctx) { - if (this.disabled || !this.active || this.isMask) return; + if (this.disabled || !this.active) return; this.rendering = true; if (this.visible) { - ctx.save(); - if (!this.$mask) { - // draw directly to context, if has no mask - this.transform(ctx); - this.painters(ctx); - this.each(function(child) { - child.render(ctx); - }); - } else { - // FIXME: the complete mask process should be a Painter. - var mask = this.$mask; + if (this.isMask) { + + this.ensureHasMaskCanvas(); - mask.ensureHasMaskCanvas(); - var mcvs = mask.__maskCvs, - mctx = mask.__maskCtx, - bcvs = mask.__backCvs, - bctx = mask.__backCtx; + var mcvs = this.__maskCvs, + mctx = this.__maskCtx, + bcvs = this.__backCvs; // FIXME: test if bounds are not empty - var bounds_pts = mask.bounds().toPoints(); + var bounds_pts = this.bounds().toPoints(); var minX = Number.MAX_VALUE, minY = Number.MAX_VALUE, maxX = Number.MIN_VALUE, maxY = Number.MIN_VALUE; @@ -790,6 +780,8 @@ Element.prototype.render = function(ctx) { var last_cvs_size = this._maskCvsSize || engine.getCanvasSize(mcvs); + var scale = ratio; // multiple by global scale when it's known + if ((last_cvs_size[0] < width) || (last_cvs_size[1] < height)) { // mcvs/bcvs both always have the same size, so we save/check only one of them @@ -799,42 +791,79 @@ Element.prototype.render = function(ctx) { this._maskCvsSize = last_cvs_size; } - var scale = ratio; // multiple by global scale when it's known + this._maskCvsPos = [ x, y ]; - bctx.clearRect(0, 0, width*scale, height*scale); mctx.clearRect(0, 0, width*scale, height*scale); - bctx.save(); mctx.save(); - - bctx.setTransform(scale, 0, 0, scale, -x*scale, -y*scale); mctx.setTransform(scale, 0, 0, scale, -x*scale, -y*scale); - this.transform(bctx); - this.painters(bctx); - this.each(function(child) { - child.render(bctx, dt); - }); - // FIXME: this should be performed one time for all masked elements! - mask.transform(mctx); - mask.painters(mctx); - mask.each(function(child) { + this.transform(mctx); + this.painters(mctx); + this.each(function(child) { child.render(mctx); }); - bctx.globalCompositeOperation = 'destination-in'; - bctx.setTransform(1, 0, 0, 1, 0, 0); - bctx.drawImage(mcvs, 0, 0); + mctx.restore(); + + } else { - ctx.drawImage(bcvs, - 0, 0, Math.floor(width * scale), Math.floor(height * scale), - x, y, width, height); + ctx.save(); - mctx.restore(); - bctx.restore(); + if (!this.$mask) { + // draw directly to context, if has no mask + this.transform(ctx); + this.painters(ctx); + this.each(function(child) { + child.render(ctx); + }); + } else { // this element is masked + + // FIXME: the complete mask process should be a Painter. + var mask = this.$mask; + + var ratio = engine.PX_RATIO; + + if (!mask.__maskCvs) throw new Error('Mask canvas is not ready!'); + + var mcvs = mask.__maskCvs, + bcvs = mask.__backCvs, + bctx = mask.__backCtx; + + var maskSize = mask._maskCvsSize, + maskPos = mask._maskCvsPos; + + var width = maskSize[0], + height = maskSize[1], + x = maskPos[0], y = maskPos[1]; + + var scale = ratio; // multiple by global scale when it's known + + bctx.clearRect(0, 0, width*scale, height*scale); + + bctx.save(); + bctx.setTransform(scale, 0, 0, scale, -x*scale, -y*scale); + + this.transform(bctx); + this.painters(bctx); + this.each(function(child) { + child.render(bctx); + }); + + bctx.globalCompositeOperation = 'destination-in'; + bctx.setTransform(1, 0, 0, 1, 0, 0); + bctx.drawImage(mcvs, 0, 0); + + ctx.drawImage(bcvs, + 0, 0, Math.floor(width * scale), Math.floor(height * scale), + x, y, width, height); + + bctx.restore(); + } + + ctx.restore(); } - ctx.restore(); } this.__postRender(); this.rendering = false; From 987e59c4cc66bcaa324d18ec06e82ab99e70f271 Mon Sep 17 00:00:00 2001 From: Ulric Wilfred Date: Thu, 17 Dec 2015 17:44:30 +0100 Subject: [PATCH 2/3] simplify Element.render() into mask and masked logical branches --- src/anm/animation/element.js | 185 +++++++++++++++++++---------------- 1 file changed, 98 insertions(+), 87 deletions(-) diff --git a/src/anm/animation/element.js b/src/anm/animation/element.js index 0bd3a8de..4c0eb465 100644 --- a/src/anm/animation/element.js +++ b/src/anm/animation/element.js @@ -750,124 +750,135 @@ Element.prototype.render = function(ctx) { if (this.visible) { - if (this.isMask) { + if (!this.isMask && !this.$mask) { - this.ensureHasMaskCanvas(); + ctx.save(); - var mcvs = this.__maskCvs, - mctx = this.__maskCtx, - bcvs = this.__backCvs; + this.transform(ctx); + this.painters(ctx); + this.each(function(child) { + child.render(ctx); + }); - // FIXME: test if bounds are not empty - var bounds_pts = this.bounds().toPoints(); + ctx.restore(); - var minX = Number.MAX_VALUE, minY = Number.MAX_VALUE, - maxX = Number.MIN_VALUE, maxY = Number.MIN_VALUE; + } else if (this.isMask) { // this element is a mask - var pt; - for (var i = 0, il = bounds_pts.length; i < il; i++) { - pt = bounds_pts[i]; - if (pt.x < minX) minX = pt.x; - if (pt.y < minY) minY = pt.y; - if (pt.x > maxX) maxX = pt.x; - if (pt.y > maxY) maxY = pt.y; - } + this._renderAsMask(); - var ratio = engine.PX_RATIO, - x = minX, y = minY, - width = Math.round(maxX - minX), - height = Math.round(maxY - minY); + } else if (this.$mask) { // this element is masked - var last_cvs_size = this._maskCvsSize || engine.getCanvasSize(mcvs); + ctx.save(); + this._renderAsMasked(ctx); + ctx.restore(); - var scale = ratio; // multiple by global scale when it's known + } - if ((last_cvs_size[0] < width) || - (last_cvs_size[1] < height)) { - // mcvs/bcvs both always have the same size, so we save/check only one of them - this._maskCvsSize = engine.setCanvasSize(mcvs, width, height); - engine.setCanvasSize(bcvs, width, height); - } else { - this._maskCvsSize = last_cvs_size; - } + } - this._maskCvsPos = [ x, y ]; + this.__postRender(); + this.rendering = false; + return this; +}; - mctx.clearRect(0, 0, width*scale, height*scale); +Element.prorotype._renderAsMask = function() { + this.ensureHasMaskCanvas(); - mctx.save(); - mctx.setTransform(scale, 0, 0, scale, -x*scale, -y*scale); + var mcvs = this.__maskCvs, + mctx = this.__maskCtx, + bcvs = this.__backCvs; - // FIXME: this should be performed one time for all masked elements! - this.transform(mctx); - this.painters(mctx); - this.each(function(child) { - child.render(mctx); - }); + // FIXME: test if bounds are not empty + var bounds_pts = this.bounds().toPoints(); - mctx.restore(); + var minX = Number.MAX_VALUE, minY = Number.MAX_VALUE, + maxX = Number.MIN_VALUE, maxY = Number.MIN_VALUE; - } else { + var pt; + for (var i = 0, il = bounds_pts.length; i < il; i++) { + pt = bounds_pts[i]; + if (pt.x < minX) minX = pt.x; + if (pt.y < minY) minY = pt.y; + if (pt.x > maxX) maxX = pt.x; + if (pt.y > maxY) maxY = pt.y; + } - ctx.save(); + var ratio = engine.PX_RATIO, + x = minX, y = minY, + width = Math.round(maxX - minX), + height = Math.round(maxY - minY); - if (!this.$mask) { - // draw directly to context, if has no mask - this.transform(ctx); - this.painters(ctx); - this.each(function(child) { - child.render(ctx); - }); - } else { // this element is masked + var last_cvs_size = this._maskCvsSize || engine.getCanvasSize(mcvs); - // FIXME: the complete mask process should be a Painter. - var mask = this.$mask; + var scale = ratio; // multiple by global scale when it's known - var ratio = engine.PX_RATIO; + if ((last_cvs_size[0] < width) || + (last_cvs_size[1] < height)) { + // mcvs/bcvs both always have the same size, so we save/check only one of them + this._maskCvsSize = engine.setCanvasSize(mcvs, width, height); + engine.setCanvasSize(bcvs, width, height); + } else { + this._maskCvsSize = last_cvs_size; + } - if (!mask.__maskCvs) throw new Error('Mask canvas is not ready!'); + this._maskCvsPos = [ x, y ]; - var mcvs = mask.__maskCvs, - bcvs = mask.__backCvs, - bctx = mask.__backCtx; + mctx.clearRect(0, 0, width*scale, height*scale); - var maskSize = mask._maskCvsSize, - maskPos = mask._maskCvsPos; + mctx.save(); + mctx.setTransform(scale, 0, 0, scale, -x*scale, -y*scale); - var width = maskSize[0], - height = maskSize[1], - x = maskPos[0], y = maskPos[1]; + // FIXME: this should be performed one time for all masked elements! + this.transform(mctx); + this.painters(mctx); + this.each(function(child) { + child.render(mctx); + }); - var scale = ratio; // multiple by global scale when it's known + mctx.restore(); +}; - bctx.clearRect(0, 0, width*scale, height*scale); +Element.prorotype._renderAsMasked = function(ctx) { + // FIXME: the complete mask process should be a Painter. + var mask = this.$mask; - bctx.save(); - bctx.setTransform(scale, 0, 0, scale, -x*scale, -y*scale); + var ratio = engine.PX_RATIO; - this.transform(bctx); - this.painters(bctx); - this.each(function(child) { - child.render(bctx); - }); + if (!mask.__maskCvs) throw new Error('Mask canvas is not ready!'); - bctx.globalCompositeOperation = 'destination-in'; - bctx.setTransform(1, 0, 0, 1, 0, 0); - bctx.drawImage(mcvs, 0, 0); + var mcvs = mask.__maskCvs, + bcvs = mask.__backCvs, + bctx = mask.__backCtx; - ctx.drawImage(bcvs, - 0, 0, Math.floor(width * scale), Math.floor(height * scale), - x, y, width, height); + var maskSize = mask._maskCvsSize, + maskPos = mask._maskCvsPos; - bctx.restore(); - } + var width = maskSize[0], + height = maskSize[1], + x = maskPos[0], y = maskPos[1]; - ctx.restore(); - } - } - this.__postRender(); - this.rendering = false; - return this; + var scale = ratio; // multiple by global scale when it's known + + bctx.clearRect(0, 0, width*scale, height*scale); + + bctx.save(); + bctx.setTransform(scale, 0, 0, scale, -x*scale, -y*scale); + + this.transform(bctx); + this.painters(bctx); + this.each(function(child) { + child.render(bctx); + }); + + bctx.globalCompositeOperation = 'destination-in'; + bctx.setTransform(1, 0, 0, 1, 0, 0); + bctx.drawImage(mcvs, 0, 0); + + ctx.drawImage(bcvs, + 0, 0, Math.floor(width * scale), Math.floor(height * scale), + x, y, width, height); + + bctx.restore(); }; /** From 17059282b113e163144356b716c017c6629d6abb Mon Sep 17 00:00:00 2001 From: Ulric Wilfred Date: Thu, 17 Dec 2015 17:50:29 +0100 Subject: [PATCH 3/3] fix Element.prorotype -> Element.prototype --- src/anm/animation/element.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/anm/animation/element.js b/src/anm/animation/element.js index 4c0eb465..4bee9092 100644 --- a/src/anm/animation/element.js +++ b/src/anm/animation/element.js @@ -781,7 +781,7 @@ Element.prototype.render = function(ctx) { return this; }; -Element.prorotype._renderAsMask = function() { +Element.prototype._renderAsMask = function() { this.ensureHasMaskCanvas(); var mcvs = this.__maskCvs, @@ -838,7 +838,7 @@ Element.prorotype._renderAsMask = function() { mctx.restore(); }; -Element.prorotype._renderAsMasked = function(ctx) { +Element.prototype._renderAsMasked = function(ctx) { // FIXME: the complete mask process should be a Painter. var mask = this.$mask;