From e4373ad1333a7523222ef526e6aea1c80747dbbd Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Sat, 8 Sep 2012 23:10:05 +0200 Subject: [PATCH 1/3] Small updates to FrameRenderer for fun --- js/rendering/FrameRenderer.js | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/js/rendering/FrameRenderer.js b/js/rendering/FrameRenderer.js index 63b96533..5809e784 100644 --- a/js/rendering/FrameRenderer.js +++ b/js/rendering/FrameRenderer.js @@ -1,16 +1,13 @@ (function () { var ns = $.namespace("pskl.rendering"); - this.dpi = null; - this.canvas = null; - ns.FrameRenderer = function (container, renderingOptions, className) { if(container == undefined) { throw "Bad FrameRenderer initialization. undefined."; } this.container = container; - if(renderingOptions == undefined || renderingOptions.dpi == undefined || isNaN(dpi)) { + if(renderingOptions == undefined || renderingOptions.dpi == undefined) { throw "Bad FrameRenderer initialization. not well defined."; } @@ -66,24 +63,25 @@ ns.FrameRenderer.prototype.getCanvas_ = function (frame) { if(this.canvasConfigDirty) { $(this.canvas).remove(); - var width = frame.getWidth(), - height = frame.getHeight(); - - var canvas = document.createElement("canvas"); - canvas.setAttribute("width", width * this.dpi); - canvas.setAttribute("height", height * this.dpi); - - var canvasClassname = "canvas"; - if(this.className) { - canvasClassname += " " + this.className; - } - canvas.setAttribute("class", canvasClassname); - - this.canvas = canvas; + this.canvas = this.createCanvasForFrame_(frame); this.container.appendChild(this.canvas); this.canvasConfigDirty = false; } return this.canvas; }; + + /** + * @private + */ + ns.FrameRenderer.prototype.createCanvasForFrame_ = function (frame) { + var canvas = document.createElement("canvas"); + canvas.setAttribute("width", frame.getWidth() * this.dpi); + canvas.setAttribute("height", frame.getHeight() * this.dpi); + + canvas.classList.add("canvas"); + if(this.className) canvas.classList.add(this.className); + + return canvas; + }; })(); \ No newline at end of file From 6e7545a1d21cccbd50414b06df1f09da5e7e6f9b Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Sat, 8 Sep 2012 23:59:44 +0200 Subject: [PATCH 2/3] Added drawing loop, unplugged traditional renderers --- index.html | 1 + js/controller/AnimatedPreviewController.js | 18 ++---------- js/drawingtools/Move.js | 1 - js/drawingtools/PaintBucket.js | 4 --- js/drawingtools/Rectangle.js | 9 ++---- js/drawingtools/SimplePen.js | 4 --- js/piskel.js | 34 ++++++++++------------ 7 files changed, 21 insertions(+), 50 deletions(-) diff --git a/index.html b/index.html index 91efbe58..df46a720 100644 --- a/index.html +++ b/index.html @@ -89,6 +89,7 @@ + diff --git a/js/controller/AnimatedPreviewController.js b/js/controller/AnimatedPreviewController.js index c8b7f51a..7acb319b 100644 --- a/js/controller/AnimatedPreviewController.js +++ b/js/controller/AnimatedPreviewController.js @@ -6,7 +6,8 @@ this.animIndex = 0; this.fps = parseInt($("#preview-fps")[0].value, 10); - + this.deltaTime = 0; + this.previousTime = 0; var renderingOptions = { "dpi": dpi }; @@ -25,29 +26,16 @@ $("#preview-fps")[0].addEventListener('change', this.onFPSSliderChange.bind(this)); }; - ns.AnimatedPreviewController.prototype.startAnimationTimer = function () { - this.stopAnimationTimer(); - this.animationTimer = window.setTimeout(this.refreshAnimatedPreview.bind(this), 1000/this.fps); - }; - - ns.AnimatedPreviewController.prototype.stopAnimationTimer = function () { - if (this.animationTimer) { - window.clearInterval(this.animationTimer); - this.animationTimer = null; - } - }; - ns.AnimatedPreviewController.prototype.onFPSSliderChange = function(evt) { this.fps = parseInt($("#preview-fps")[0].value, 10); }; - ns.AnimatedPreviewController.prototype.refreshAnimatedPreview = function () { + ns.AnimatedPreviewController.prototype.render = function () { if (!this.framesheet.hasFrameAtIndex(this.animIndex)) { this.animIndex = 0; } this.renderer.render(this.framesheet.getFrameByIndex(this.animIndex)); this.animIndex++; - this.startAnimationTimer(); }; })(); \ No newline at end of file diff --git a/js/drawingtools/Move.js b/js/drawingtools/Move.js index 2ff9ca73..23b0f58f 100644 --- a/js/drawingtools/Move.js +++ b/js/drawingtools/Move.js @@ -29,7 +29,6 @@ var colDiff = col - this.startCol, rowDiff = row - this.startRow; if (colDiff != 0 || rowDiff != 0) { this.shiftFrame(colDiff, rowDiff, drawer.frame, this.frameClone); - drawer.renderFrame(); } }; diff --git a/js/drawingtools/PaintBucket.js b/js/drawingtools/PaintBucket.js index a4523bd7..f3c3ccfe 100644 --- a/js/drawingtools/PaintBucket.js +++ b/js/drawingtools/PaintBucket.js @@ -21,10 +21,6 @@ var targetColor = drawer.frame.getPixel(col, row); //this.recursiveFloodFill_(frame, col, row, targetColor, color); this.queueLinearFloodFill_(drawer.frame, col, row, targetColor, color); - - // Draw in canvas: - // TODO: Remove that when we have the centralized redraw loop - drawer.renderFrame(); }; /** diff --git a/js/drawingtools/Rectangle.js b/js/drawingtools/Rectangle.js index 36967878..5f2fa7c7 100644 --- a/js/drawingtools/Rectangle.js +++ b/js/drawingtools/Rectangle.js @@ -25,7 +25,6 @@ // Drawing the first point of the rectangle in the fake overlay canvas: drawer.overlayFrame.setPixel(col, row, color); - drawer.renderOverlay(); }; ns.Rectangle.prototype.moveToolAt = function(col, row, color, drawer) { @@ -44,13 +43,13 @@ } drawer.overlayFrame.setPixel(strokePoints[i].col, strokePoints[i].row, color); } - drawer.renderOverlay(); }; /** * @override */ ns.Rectangle.prototype.releaseToolAt = function(col, row, color, drawer) { + drawer.clearOverlay(); // If the stroke tool is released outside of the canvas, we cancel the stroke: if(drawer.frame.containsPixel(col, row)) { var strokePoints = this.getRectanglePixels_(this.startCol, col, this.startRow, row); @@ -59,12 +58,8 @@ drawer.frame.setPixel(strokePoints[i].col, strokePoints[i].row, color); } // The user released the tool to draw a line. We will compute the pixel coordinate, impact - // the model and draw them in the drawing canvas (not the fake overlay anymore) - // Draw in canvas: - // TODO: Remove that when we have the centralized redraw loop - drawer.renderFrame(); + // the model and draw them in the drawing canvas (not the fake overlay anymore) } - drawer.clearOverlay(); }; /** diff --git a/js/drawingtools/SimplePen.js b/js/drawingtools/SimplePen.js index 39a27363..86065d63 100644 --- a/js/drawingtools/SimplePen.js +++ b/js/drawingtools/SimplePen.js @@ -23,10 +23,6 @@ this.previousCol = col; this.previousRow = row; drawer.frame.setPixel(col, row, color); - - // Draw on canvas: - // TODO: Remove that when we have the centralized redraw loop - drawer.renderFramePixel(col, row); } }; diff --git a/js/piskel.js b/js/piskel.js index ba77acbf..f0610f5f 100644 --- a/js/piskel.js +++ b/js/piskel.js @@ -51,6 +51,7 @@ $.namespace("pskl"); piskel.initDPIs_(); + frameSheet = new pskl.model.FrameSheet(framePixelWidth, framePixelHeight); frameSheet.addEmptyFrame(); @@ -91,6 +92,16 @@ $.namespace("pskl"); this.finishInit(); pskl.LocalStorageService.displayRestoreNotification(); } + + var drawingLoop = new pskl.rendering.DrawingLoop(); + drawingLoop.addCallback(this.render, this); + drawingLoop.start(); + }, + + render : function (delta) { + this.drawingController.render(delta); + this.animationController.render(delta); + this.previewsController.render(delta); }, /** @@ -157,7 +168,7 @@ $.namespace("pskl"); }); $.subscribe(Events.REFRESH, function() { - piskel.setActiveFrameAndRedraw(0); + piskel.setActiveFrame(0); }); // TODO: Move this into their service or behavior files: @@ -186,13 +197,12 @@ $.namespace("pskl"); piskel.setActiveFrame(0); $.publish(Events.HIDE_NOTIFICATION); piskel.finishInit(); - piskel.setActiveFrameAndRedraw(0); }; xhr.onerror = function () { $.publish(Events.HIDE_NOTIFICATION); piskel.finishInit(); - piskel.setActiveFrameAndRedraw(0); + piskel.setActiveFrame(0); }; xhr.send(); @@ -203,18 +213,6 @@ $.namespace("pskl"); this.drawingController.frame = this.getCurrentFrame(); }, - setActiveFrameAndRedraw: function(index) { - this.setActiveFrame(index); - this.redraw(); - }, - - redraw : function () { - // Update drawing canvas: - this.drawingController.renderFrame(); - // Update slideshow: - this.previewsController.createPreviews(); - }, - getActiveFrameIndex: function() { if(-1 == activeFrameIndex) { throw "Bad active frame initialization." @@ -237,12 +235,12 @@ $.namespace("pskl"); removeFrame: function(frameIndex) { frameSheet.removeFrameByIndex(frameIndex); var activeFrameIndex = frameIndex ? frameIndex - 1 : 0; - this.setActiveFrameAndRedraw(activeFrameIndex); + this.setActiveFrame(activeFrameIndex); }, duplicateFrame: function(frameIndex) { frameSheet.duplicateFrameByIndex(frameIndex); - this.setActiveFrameAndRedraw(frameIndex + 1); + this.setActiveFrame(frameIndex + 1); }, getCurrentColor : function () { @@ -323,8 +321,6 @@ $.namespace("pskl"); $.publish(Events.TOOL_RELEASED); - // TODO: Remove that when we have the centralized redraw loop - this.previewsController.createPreviews(); } }, From 63d8cd7eb710dd532974949bee6dd13fd4db0bd7 Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Sun, 9 Sep 2012 01:12:54 +0200 Subject: [PATCH 3/3] Slight performance improvement, previewfilmcontroller still buggy --- js/controller/AnimatedPreviewController.js | 24 +++++++------ js/controller/DrawingController.js | 13 +++++-- js/controller/PreviewFilmController.js | 42 ++++++++++++---------- js/piskel.js | 2 +- 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/js/controller/AnimatedPreviewController.js b/js/controller/AnimatedPreviewController.js index 9c944a40..ee1e7f1c 100644 --- a/js/controller/AnimatedPreviewController.js +++ b/js/controller/AnimatedPreviewController.js @@ -3,7 +3,9 @@ ns.AnimatedPreviewController = function (framesheet, container, dpi) { this.framesheet = framesheet; this.container = container; - this.animIndex = 0; + + this.elapsedTime = 0; + this.currentIndex = 0; this.fps = parseInt($("#preview-fps")[0].value, 10); this.deltaTime = 0; @@ -15,11 +17,6 @@ }; ns.AnimatedPreviewController.prototype.init = function () { - this.initDom(); - this.renderer.init(this.framesheet.getFrameByIndex(this.animIndex)); - }; - - ns.AnimatedPreviewController.prototype.initDom = function () { $("#preview-fps")[0].addEventListener('change', this.onFPSSliderChange.bind(this)); }; @@ -27,12 +24,17 @@ this.fps = parseInt($("#preview-fps")[0].value, 10); }; - ns.AnimatedPreviewController.prototype.render = function () { - if (!this.framesheet.hasFrameAtIndex(this.animIndex)) { - this.animIndex = 0; + ns.AnimatedPreviewController.prototype.render = function (delta) { + this.elapsedTime += delta; + var index = Math.floor(this.elapsedTime / (1000/this.fps)); + if (index != this.currentIndex) { + this.currentIndex = index; + if (!this.framesheet.hasFrameAtIndex(this.currentIndex)) { + this.currentIndex = 0; + this.elapsedTime = 0; + } + this.renderer.render(this.framesheet.getFrameByIndex(this.currentIndex)); } - this.renderer.render(this.framesheet.getFrameByIndex(this.animIndex)); - this.animIndex++; }; })(); \ No newline at end of file diff --git a/js/controller/DrawingController.js b/js/controller/DrawingController.js index 4cdf3b61..a9a32e3e 100644 --- a/js/controller/DrawingController.js +++ b/js/controller/DrawingController.js @@ -212,6 +212,7 @@ ns.DrawingController.prototype.render = function () { try { + this.renderFrame(); this.renderOverlay(); } catch (e) { @@ -220,7 +221,11 @@ }; ns.DrawingController.prototype.renderFrame = function () { - this.renderer.render(this.frame); + var serializedFrame = this.frame.serialize(); + if (this.serializedFrame != serializedFrame) { + this.serializedFrame = serializedFrame + this.renderer.render(this.frame); + } }; ns.DrawingController.prototype.renderFramePixel = function (col, row) { @@ -228,7 +233,11 @@ }; ns.DrawingController.prototype.renderOverlay = function () { - this.overlayRenderer.render(this.overlayFrame); + var serializedOverlay = this.overlayFrame.serialize(); + if (this.serializedOverlay != serializedOverlay) { + this.serializedOverlay = serializedOverlay + this.renderer.render(this.overlayFrame); + } }; ns.DrawingController.prototype.clearOverlay = function () { diff --git a/js/controller/PreviewFilmController.js b/js/controller/PreviewFilmController.js index 4ec9b4b2..5ae04e03 100644 --- a/js/controller/PreviewFilmController.js +++ b/js/controller/PreviewFilmController.js @@ -6,37 +6,41 @@ this.framesheet = framesheet; this.container = container; + this.dirty = false; + $.subscribe(Events.REDRAW_PREVIEWFILM, $.proxy(function(evt) { - // this.render(); + this.dirty = true; }, this)); }; ns.PreviewFilmController.prototype.init = function() { - var addFrameButton = $('#add-frame-button')[0]; - addFrameButton.addEventListener('mousedown', this.addFrame.bind(this)); + var addFrameButton = $('#add-frame-button')[0]; + addFrameButton.addEventListener('mousedown', this.addFrame.bind(this)); }; ns.PreviewFilmController.prototype.addFrame = function () { this.framesheet.addEmptyFrame(); - piskel.setActiveFrameAndRedraw(this.framesheet.getFrameCount() - 1); + piskel.setActiveFrame(this.framesheet.getFrameCount() - 1); }; ns.PreviewFilmController.prototype.render = function () { - // TODO(vincz): Full redraw on any drawing modification, optimize. - this.container.html(""); + if (!this.dirty) return + // TODO(vincz): Full redraw on any drawing modification, optimize. + this.container.html(""); - var frameCount = this.framesheet.getFrameCount(); - - for (var i = 0, l = frameCount; i < l ; i++) { - this.container.append(this.createInterstitialTile_(i)); - this.container.append(this.createPreviewTile_(i, this.framesheet)); - } - this.container.append(this.createInterstitialTile_(frameCount)); + var frameCount = this.framesheet.getFrameCount(); - var needDragndropBehavior = !!(frameCount > 1); - if(needDragndropBehavior) { - this.initDragndropBehavior_(); - } + for (var i = 0, l = frameCount; i < l ; i++) { + this.container.append(this.createInterstitialTile_(i)); + this.container.append(this.createPreviewTile_(i, this.framesheet)); + } + this.container.append(this.createInterstitialTile_(frameCount)); + + var needDragndropBehavior = !!(frameCount > 1); + if(needDragndropBehavior) { + this.initDragndropBehavior_(); + } + this.dirty = false; }; /** @@ -132,7 +136,7 @@ $('#preview-list').removeClass("show-interstitial-tiles"); // TODO(vincz): deprecate. - piskel.setActiveFrameAndRedraw(activeFrame); + piskel.setActiveFrame(activeFrame); // TODO(vincz): move localstorage request to the model layer? $.publish(Events.LOCALSTORAGE_REQUEST); @@ -165,7 +169,7 @@ previewTileRoot.addEventListener('click', function(evt) { // has not class tile-action: if(!evt.target.classList.contains('tile-action')) { - piskel.setActiveFrameAndRedraw(tileNumber); + piskel.setActiveFrame(tileNumber); } }); diff --git a/js/piskel.js b/js/piskel.js index b442eb45..2aee3ebb 100644 --- a/js/piskel.js +++ b/js/piskel.js @@ -79,7 +79,7 @@ $.namespace("pskl"); } $.subscribe('SET_ACTIVE_FRAME', function(evt, frameId) { - piskel.setActiveFrameAndRedraw(frameId); + piskel.setActiveFrame(frameId); }); $.subscribe('FRAMESHEET_RESET', function(evt, frameId) {