From 1402394d077d8fc0cb96a27feb34aef3ab7deb67 Mon Sep 17 00:00:00 2001 From: jdescottes Date: Thu, 18 Dec 2014 23:57:34 +0100 Subject: [PATCH 1/3] Animation pauses when FPS slider at 0FPS + slight perf improvement --- src/js/Events.js | 1 + .../controller/AnimatedPreviewController.js | 67 ++++++++++++++----- src/js/controller/DrawingController.js | 4 +- src/js/model/frame/CachedFrameProcessor.js | 2 +- src/js/rendering/frame/FrameRenderer.js | 14 ++-- src/js/utils/core.js | 13 +++- src/templates/preview.html | 2 +- 7 files changed, 72 insertions(+), 31 deletions(-) diff --git a/src/js/Events.js b/src/js/Events.js index fb2203a3..21eb133b 100644 --- a/src/js/Events.js +++ b/src/js/Events.js @@ -5,6 +5,7 @@ var Events = { SELECT_TOOL : "SELECT_TOOL", TOOL_RELEASED : "TOOL_RELEASED", + TOOL_PRESSED : "TOOL_PRESSED", SELECT_PRIMARY_COLOR: "SELECT_PRIMARY_COLOR", SELECT_SECONDARY_COLOR: "SELECT_SECONDARY_COLOR", PRIMARY_COLOR_SELECTED : 'PRIMARY_COLOR_SELECTED', diff --git a/src/js/controller/AnimatedPreviewController.js b/src/js/controller/AnimatedPreviewController.js index 43269e4a..9d5f2eb4 100644 --- a/src/js/controller/AnimatedPreviewController.js +++ b/src/js/controller/AnimatedPreviewController.js @@ -1,5 +1,5 @@ (function () { - var ns = $.namespace("pskl.controller"); + var ns = $.namespace('pskl.controller'); // Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE var PREVIEW_SIZE = 200; @@ -11,6 +11,11 @@ this.elapsedTime = 0; this.currentIndex = 0; + this.renderFlag = true; + + this.fpsRangeInput = $('#preview-fps'); + this.fpsCounterDisplay = $('#display-fps'); + this.setFPS(Constants.DEFAULT.FPS); var frame = this.piskelController.getCurrentFrame(); @@ -22,10 +27,10 @@ // the oninput event won't work on IE10 unfortunately, but at least will provide a // consistent behavior across all other browsers that support the input type range // see https://bugzilla.mozilla.org/show_bug.cgi?id=853670 - $("#preview-fps").on('input change', this.onFPSSliderChange.bind(this)); - document.querySelector(".right-column").style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px'; + this.fpsRangeInput.on('input change', this.onFPSSliderChange.bind(this)); + document.querySelector('.right-column').style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px'; - this.toggleOnionSkinEl = document.querySelector(".preview-toggle-onion-skin"); + this.toggleOnionSkinEl = document.querySelector('.preview-toggle-onion-skin'); this.toggleOnionSkinEl.addEventListener('click', this.toggleOnionSkin_.bind(this)); pskl.app.shortcutService.addShortcut('alt+O', this.toggleOnionSkin_.bind(this)); @@ -33,6 +38,9 @@ $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this)); $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); + $.subscribe(Events.TOOL_RELEASED, this.setRenderFlag_.bind(this, true)); + $.subscribe(Events.TOOL_PRESSED, this.setRenderFlag_.bind(this, false)); + this.updateZoom_(); this.updateOnionSkinPreview_(); this.updateContainerDimensions_(); @@ -78,14 +86,16 @@ }; ns.AnimatedPreviewController.prototype.onFPSSliderChange = function (evt) { - this.setFPS(parseInt($("#preview-fps")[0].value, 10)); + this.setFPS(parseInt(this.fpsRangeInput[0].value, 10)); + }; ns.AnimatedPreviewController.prototype.setFPS = function (fps) { - if (fps) { + if (typeof fps === 'number') { this.fps = fps; - $("#preview-fps").val(this.fps); - $("#display-fps").html(this.fps + " FPS"); + this.fpsRangeInput.val(this.fps); + this.fpsRangeInput.blur(); + this.fpsCounterDisplay.html(this.fps + ' FPS'); } }; @@ -94,7 +104,24 @@ }; ns.AnimatedPreviewController.prototype.render = function (delta) { - this.elapsedTime += delta; + if (this.renderFlag) { + this.elapsedTime += delta; + if (this.fps === 0) { + this._renderSelectedFrame(); + } else { + this._renderCurrentAnimationFrame(); + } + } + }; + + ns.AnimatedPreviewController.prototype._renderSelectedFrame = function (delta) { + // the selected frame is the currentFrame from the PiskelController perspective + var selectedFrameIndex = this.piskelController.getCurrentFrameIndex(); + var selectedFrame = this.piskelController.getFrameAt(selectedFrameIndex); + this.renderer.render(selectedFrame); + }; + + ns.AnimatedPreviewController.prototype._renderCurrentAnimationFrame = function (delta) { var index = Math.floor(this.elapsedTime / (1000/this.fps)); if (index != this.currentIndex) { this.currentIndex = index; @@ -112,9 +139,8 @@ */ ns.AnimatedPreviewController.prototype.calculateZoom_ = function () { var frame = this.piskelController.getCurrentFrame(); - var previewSize = 200, - hZoom = previewSize / frame.getHeight(), - wZoom = previewSize / frame.getWidth(); + var hZoom = PREVIEW_SIZE / frame.getHeight(), + wZoom = PREVIEW_SIZE / frame.getWidth(); return Math.min(hZoom, wZoom); }; @@ -139,16 +165,21 @@ width = frame.getWidth() * zoom; } - containerEl.style.height = height + "px"; - containerEl.style.width = width + "px"; + containerEl.style.height = height + 'px'; + containerEl.style.width = width + 'px'; var horizontalPadding = (PREVIEW_SIZE - height) / 2; - containerEl.style.marginTop = horizontalPadding + "px"; - containerEl.style.marginBottom = horizontalPadding + "px"; + containerEl.style.marginTop = horizontalPadding + 'px'; + containerEl.style.marginBottom = horizontalPadding + 'px'; var verticalPadding = (PREVIEW_SIZE - width) / 2; - containerEl.style.marginLeft = verticalPadding + "px"; - containerEl.style.marginRight = verticalPadding + "px"; + containerEl.style.marginLeft = verticalPadding + 'px'; + containerEl.style.marginRight = verticalPadding + 'px'; + }; + + ns.AnimatedPreviewController.prototype.setRenderFlag_ = function (bool) { + console.log('setRenderFlag_', bool); + this.renderFlag = bool; }; ns.AnimatedPreviewController.prototype.toggleOnionSkin_ = function () { diff --git a/src/js/controller/DrawingController.js b/src/js/controller/DrawingController.js index f8fa153f..f6ed0653 100644 --- a/src/js/controller/DrawingController.js +++ b/src/js/controller/DrawingController.js @@ -31,8 +31,6 @@ "yOffset" : 0 }; - console.log('DrawingController:getContainerWidth_', this.getContainerWidth_()); - this.overlayRenderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["canvas-overlay"]); this.renderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["drawing-canvas"]); this.onionSkinRenderer = new pskl.rendering.OnionSkinRenderer(this.container, renderingOptions, piskelController); @@ -153,7 +151,7 @@ this.dragHandler.startDrag(event.clientX, event.clientY); } else { this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame); - + $.publish(Events.TOOL_PRESSED); this.currentToolBehavior.applyToolAt( coords.x, coords.y, diff --git a/src/js/model/frame/CachedFrameProcessor.js b/src/js/model/frame/CachedFrameProcessor.js index 4f884b91..7e20b9d4 100644 --- a/src/js/model/frame/CachedFrameProcessor.js +++ b/src/js/model/frame/CachedFrameProcessor.js @@ -65,7 +65,7 @@ if (cache[cacheKey]) { processedFrame = cache[cacheKey]; } else { - var frameAsString = JSON.stringify(frame.getPixels()); + var frameAsString = pskl.utils.hashCode(JSON.stringify(frame.getPixels())); if (cache[frameAsString]) { processedFrame = this.outputCloner(cache[frameAsString], frame); } else { diff --git a/src/js/rendering/frame/FrameRenderer.js b/src/js/rendering/frame/FrameRenderer.js index ee746b75..9a0eaa74 100644 --- a/src/js/rendering/frame/FrameRenderer.js +++ b/src/js/rendering/frame/FrameRenderer.js @@ -164,13 +164,6 @@ } }; - ns.FrameRenderer.prototype.renderPixel_ = function (color, x, y, context) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(x, y, 1, 1); - } - }; - /** * Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered * frame) into a sprite coordinate in column and row. @@ -264,4 +257,11 @@ } displayContext.restore(); }; + + ns.FrameRenderer.prototype.renderPixel_ = function (color, x, y, context) { + if(color != Constants.TRANSPARENT_COLOR) { + context.fillStyle = color; + context.fillRect(x, y, 1, 1); + } + }; })(); \ No newline at end of file diff --git a/src/js/utils/core.js b/src/js/utils/core.js index 2fd92c14..af71c3de 100644 --- a/src/js/utils/core.js +++ b/src/js/utils/core.js @@ -89,6 +89,18 @@ if (!Function.prototype.bind) { } }; + ns.hashCode = function(str) { + var hash = 0; + if (str.length !== 0) { + for (var i = 0, l = str.length; i < l; i++) { + var chr = str.charCodeAt(i); + hash = ((hash << 5) - hash) + chr; + hash |= 0; // Convert to 32bit integer + } + } + return hash; + }; + var entityMap = { "&": "&", "<": "<", @@ -97,7 +109,6 @@ if (!Function.prototype.bind) { "'": ''', "/": '/' }; - ns.escapeHtml= function (string) { return String(string).replace(/[&<>"'\/]/g, function (s) { return entityMap[s]; diff --git a/src/templates/preview.html b/src/templates/preview.html index b0bfe93e..7c01cca4 100644 --- a/src/templates/preview.html +++ b/src/templates/preview.html @@ -10,6 +10,6 @@ data-placement="bottom" class="piskel-icon-onion preview-toggle-onion-skin"> - + \ No newline at end of file From 0642e17aa8d2e1fa72a648ea836bf91b6b144b6c Mon Sep 17 00:00:00 2001 From: jdescottes Date: Fri, 19 Dec 2014 08:28:15 +0100 Subject: [PATCH 2/3] Draw lines of pixels instead of single pixels --- .../controller/AnimatedPreviewController.js | 1 - src/js/rendering/CanvasRenderer.js | 22 ++++++++++++++++--- src/js/rendering/frame/FrameRenderer.js | 14 +++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/js/controller/AnimatedPreviewController.js b/src/js/controller/AnimatedPreviewController.js index 9d5f2eb4..2ada9fad 100644 --- a/src/js/controller/AnimatedPreviewController.js +++ b/src/js/controller/AnimatedPreviewController.js @@ -178,7 +178,6 @@ }; ns.AnimatedPreviewController.prototype.setRenderFlag_ = function (bool) { - console.log('setRenderFlag_', bool); this.renderFlag = bool; }; diff --git a/src/js/rendering/CanvasRenderer.js b/src/js/rendering/CanvasRenderer.js index c124c73b..3108419e 100644 --- a/src/js/rendering/CanvasRenderer.js +++ b/src/js/rendering/CanvasRenderer.js @@ -19,9 +19,18 @@ ns.CanvasRenderer.prototype.render = function () { var canvas = this.createCanvas_(); var context = canvas.getContext('2d'); - this.frame.forEachPixel(function (color, x, y) { - this.renderPixel_(color, x, y, context); - }.bind(this)); + + for(var x = 0, width = this.frame.getWidth(); x < width; x++) { + for(var y = 0, height = this.frame.getHeight(); y < height; y++) { + var color = this.frame.getPixel(x, y); + var w = 1; + while (color === this.frame.getPixel(x, y+w)) { + w++; + } + this.renderLine_(color, x, y, w, context); + y = y + w - 1; + } + } var scaledCanvas = this.createCanvas_(this.zoom); var scaledContext = scaledCanvas.getContext('2d'); @@ -40,6 +49,13 @@ context.fillRect(x, y, 1, 1); }; + ns.CanvasRenderer.prototype.renderLine_ = function (color, x, y, width, context) { + if(color != Constants.TRANSPARENT_COLOR) { + context.fillStyle = color; + context.fillRect(x, y, 1, width); + } + }; + ns.CanvasRenderer.prototype.createCanvas_ = function (zoom) { zoom = zoom || 1; var width = this.frame.getWidth() * zoom; diff --git a/src/js/rendering/frame/FrameRenderer.js b/src/js/rendering/frame/FrameRenderer.js index 9a0eaa74..d8291a5f 100644 --- a/src/js/rendering/frame/FrameRenderer.js +++ b/src/js/rendering/frame/FrameRenderer.js @@ -223,7 +223,12 @@ for(var x = 0, width = frame.getWidth(); x < width; x++) { for(var y = 0, height = frame.getHeight(); y < height; y++) { var color = frame.getPixel(x, y); - this.renderPixel_(color, x, y, context); + var w = 1; + while (color === frame.getPixel(x, y+w)) { + w++; + } + this.renderLine_(color, x, y, w, context); + y = y + w - 1; } } @@ -264,4 +269,11 @@ context.fillRect(x, y, 1, 1); } }; + + ns.FrameRenderer.prototype.renderLine_ = function (color, x, y, width, context) { + if(color != Constants.TRANSPARENT_COLOR) { + context.fillStyle = color; + context.fillRect(x, y, 1, width); + } + }; })(); \ No newline at end of file From df5aef363b3e9ae942fbf1a284c1091cee68c29a Mon Sep 17 00:00:00 2001 From: jdescottes Date: Sun, 21 Dec 2014 16:44:10 +0100 Subject: [PATCH 3/3] Move to imgstore-b, change body bg --- src/css/style.css | 6 +---- src/js/Constants.js | 31 +++++------------------ src/js/service/AppEngineStorageService.js | 2 +- 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/src/css/style.css b/src/css/style.css index d1aa309d..37b0da2e 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -1,9 +1,5 @@ body { - background: radial-gradient(circle, #000, #373737); - /* 16/06/2013 : -webkit still needed for - safari, safari mobile and android browser and chrome for android - cf http://caniuse.com/css-gradients */ - background: -webkit-radial-gradient(circle, #000, #373737); + background: #1D1D1D; } /* Browser fixes */ diff --git a/src/js/Constants.js b/src/js/Constants.js index 0ce59ab4..d8480e79 100644 --- a/src/js/Constants.js +++ b/src/js/Constants.js @@ -21,16 +21,8 @@ var Constants = { DEFAULT_PEN_COLOR : '#000000', TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)', - OVERLAY_ONION_SKIN : 'onion-skin', - OVERLAY_LAYER_PREVIEW : 'layer-preview', - OVERLAY_DISABLED : 'no-overlay', - - NO_PALETTE_ID : '__no-palette', CURRENT_COLORS_PALETTE_ID : '__current-colors', - // Used for Spectrum input - PREFERRED_COLOR_FORMAT : 'rgb', - /* * Fake semi-transparent color used to highlight transparent * strokes and rectangles: @@ -43,22 +35,6 @@ var Constants = { */ TOOL_TARGET_HIGHLIGHT_COLOR: 'rgba(255, 255, 255, 0.2)', - /* - * Default entry point for piskel web service: - */ - STATIC : { - URL : { - SAVE : 'http://3.piskel-app.appspot.com/store', - GET : 'http://3.piskel-app.appspot.com/get' - } - }, - APPENGINE : { - URL : { - SAVE : 'save' - } - }, - IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-a.appspot.com/__/upload', - IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-a.appspot.com/img/', ZOOMED_OUT_BACKGROUND_COLOR : '#A0A0A0', @@ -71,5 +47,10 @@ var Constants = { EMPTY_FUNCTION : function () {}, // TESTS - DRAWING_TEST_FOLDER : 'drawing' + DRAWING_TEST_FOLDER : 'drawing', + + // SERVICE URLS + APPENGINE_SAVE_URL : 'save', + IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-b.appspot.com/__/upload', + IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-b.appspot.com/img/' }; \ No newline at end of file diff --git a/src/js/service/AppEngineStorageService.js b/src/js/service/AppEngineStorageService.js index 4d377139..4e51c08e 100644 --- a/src/js/service/AppEngineStorageService.js +++ b/src/js/service/AppEngineStorageService.js @@ -35,6 +35,6 @@ callbacks.after(); }; - pskl.utils.Xhr.post(Constants.APPENGINE.URL.SAVE, data, success, error); + pskl.utils.Xhr.post(Constants.APPENGINE_SAVE_URL, data, success, error); }; })(); \ No newline at end of file