From 51f86afe6e9a8b3e6a7682ef5fea25e722ff121c Mon Sep 17 00:00:00 2001 From: jdescottes Date: Fri, 1 Nov 2013 15:39:42 +0100 Subject: [PATCH] feature : zoom - Created AbstractRenderer in rendering package - Created CachedRenderer and CachedFrameRenderer to extract basic frame caching logic from DrawingController - Created RendererManager to synchronize updates made to several Renderer settings - Moved FrameRenderer from pskl.rendering to pskl.rendering.frame - Fixed the resize of the drawing area when the window is resized --- js/app.js | 6 +- js/controller/AnimatedPreviewController.js | 25 +- js/controller/DrawingController.js | 132 +++++------ js/controller/PreviewFilmController.js | 6 +- .../settings/ApplicationSettingsController.js | 35 +-- js/rendering/AbstractRenderer.js | 22 ++ js/rendering/CachedRenderer.js | 64 +++++ js/rendering/RendererManager.js | 30 +++ js/rendering/frame/CachedFrameRenderer.js | 18 ++ js/rendering/{ => frame}/FrameRenderer.js | 219 +++++++++--------- piskel-script-list.js | 6 +- 11 files changed, 345 insertions(+), 218 deletions(-) create mode 100644 js/rendering/AbstractRenderer.js create mode 100644 js/rendering/CachedRenderer.js create mode 100644 js/rendering/RendererManager.js create mode 100644 js/rendering/frame/CachedFrameRenderer.js rename js/rendering/{ => frame}/FrameRenderer.js (67%) diff --git a/js/app.js b/js/app.js index def736df..93444c84 100644 --- a/js/app.js +++ b/js/app.js @@ -232,9 +232,9 @@ getFirstFrameAsPng : function () { var firstFrame = this.piskelController.getFrameAt(0); - var frameRenderer = new pskl.rendering.CanvasRenderer(firstFrame, 1); - frameRenderer.drawTransparentAs('rgba(0,0,0,0)'); - var firstFrameCanvas = frameRenderer.render().canvas; + var canvasRenderer = new pskl.rendering.CanvasRenderer(firstFrame, 1); + canvasRenderer.drawTransparentAs('rgba(0,0,0,0)'); + var firstFrameCanvas = canvasRenderer.render().canvas; return firstFrameCanvas.toDataURL("image/png"); }, diff --git a/js/controller/AnimatedPreviewController.js b/js/controller/AnimatedPreviewController.js index e03154c1..14749608 100644 --- a/js/controller/AnimatedPreviewController.js +++ b/js/controller/AnimatedPreviewController.js @@ -9,14 +9,15 @@ this.setFPS(Constants.DEFAULT.FPS); + var zoom = this.calculateZoom_(); var renderingOptions = { - "zoom": this.calculateZoom_(), - "height" : "auto", - "width" : "auto" + "zoom": zoom, + "height" : this.piskelController.getCurrentFrame().getHeight() * zoom, + "width" : this.piskelController.getCurrentFrame().getWidth() * zoom }; - this.renderer = new pskl.rendering.FrameRenderer(this.container, renderingOptions); + this.renderer = new pskl.rendering.frame.FrameRenderer(this.container, renderingOptions); - $.subscribe(Events.FRAME_SIZE_CHANGED, this.updateDPI_.bind(this)); + $.subscribe(Events.FRAME_SIZE_CHANGED, this.updateZoom_.bind(this)); }; ns.AnimatedPreviewController.prototype.init = function () { @@ -58,16 +59,14 @@ */ ns.AnimatedPreviewController.prototype.calculateZoom_ = function () { var previewSize = 200, - framePixelHeight = this.piskelController.getCurrentFrame().getHeight(), - framePixelWidth = this.piskelController.getCurrentFrame().getWidth(); - // TODO (julz) : should have a utility to get a Size from framesheet easily (what about empty framesheets though ?) + hZoom = previewSize / this.piskelController.getCurrentFrame().getHeight(), + wZoom = previewSize / this.piskelController.getCurrentFrame().getWidth(); - //return pskl.PixelUtils.calculateDPIForContainer($(".preview-container"), framePixelHeight, framePixelWidth); - return pskl.PixelUtils.calculateDPI(previewSize, previewSize, framePixelHeight, framePixelWidth); + return Math.min(hZoom, wZoom); }; - ns.AnimatedPreviewController.prototype.updateDPI_ = function () { - this.dpi = this.calculateDPI_(); - this.renderer.setDPI(this.dpi); + ns.AnimatedPreviewController.prototype.updateZoom_ = function () { + var zoom = this.calculateZoom_(); + this.renderer.setZoom(zoom); }; })(); \ No newline at end of file diff --git a/js/controller/DrawingController.js b/js/controller/DrawingController.js index 637cd670..e3520975 100644 --- a/js/controller/DrawingController.js +++ b/js/controller/DrawingController.js @@ -16,25 +16,28 @@ */ this.container = container; - this.zoom = this.calculateZoom_(); - this.xOffset = 0; - this.yOffset = 0; - // TODO(vincz): Store user prefs in a localstorage string ? var renderingOptions = { - "zoom": this.zoom, + "zoom": this.calculateZoom_(), "supportGridRendering" : true, "height" : this.getContainerHeight_(), "width" : this.getContainerWidth_(), - "xOffset" : this.xOffset, - "yOffset" : this.yOffset + "xOffset" : 0, + "yOffset" : 0 }; - this.overlayRenderer = new pskl.rendering.FrameRenderer(this.container, renderingOptions, ["canvas-overlay"]); - this.renderer = new pskl.rendering.FrameRenderer(this.container, renderingOptions, ["drawing-canvas"]); - this.layersBelowRenderer = new pskl.rendering.FrameRenderer(this.container, renderingOptions, ["layers-canvas", "layers-below-canvas"]); - this.layersAboveRenderer = new pskl.rendering.FrameRenderer(this.container, renderingOptions, ["layers-canvas", "layers-above-canvas"]); + 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.layersBelowRenderer = new pskl.rendering.frame.FrameRenderer(this.container, renderingOptions, ["layers-canvas", "layers-below-canvas"]); + this.layersAboveRenderer = new pskl.rendering.frame.FrameRenderer(this.container, renderingOptions, ["layers-canvas", "layers-above-canvas"]); + + this.rendererManager = new pskl.rendering.RendererManager(); + this.rendererManager + .add(this.overlayRenderer) + .add(this.renderer) + .add(this.layersBelowRenderer) + .add(this.layersAboveRenderer); // State of drawing controller: this.isClicked = false; @@ -69,12 +72,12 @@ $.publish(Events.SECONDARY_COLOR_UPDATED, [color]); }, this)); - $(window).resize($.proxy(this.startDPIUpdateTimer_, this)); + $(window).resize($.proxy(this.startResizeTimer_, this)); $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, $.proxy(this.updateZoom_, this)); + $.subscribe(Events.FRAME_SIZE_CHANGED, $.proxy(this.onFrameSizeChanged_, this)); - this.updateZoom_(); + this.centerColumnWrapperHorizontally_(); }; ns.DrawingController.prototype.initMouseBehavior = function() { @@ -89,11 +92,15 @@ body.contextmenu(this.onCanvasContextMenu_); }; - ns.DrawingController.prototype.startDPIUpdateTimer_ = function () { - if (this.zoomUpdateTimer) { - window.clearInterval(this.zoomUpdateTimer); + ns.DrawingController.prototype.startResizeTimer_ = function () { + if (this.resizeTimer) { + window.clearInterval(this.resizeTimer); } - this.zoomUpdateTimer = window.setTimeout($.proxy(this.updateZoom_, this), 200); + this.resizeTimer = window.setTimeout($.proxy(this.afterWindowResize_, this), 200); + }, + + ns.DrawingController.prototype.afterWindowResize_ = function () { + this.rendererManager.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_()); }, /** @@ -101,7 +108,7 @@ */ ns.DrawingController.prototype.onUserSettingsChange_ = function (evt, settingsName, settingsValue) { if(settingsName == pskl.UserSettings.SHOW_GRID) { - this.updateZoom_(); + console.warn('DrawingController:onUserSettingsChange_ not implemented !'); } }, @@ -116,10 +123,11 @@ $.publish(Events.CANVAS_RIGHT_CLICKED); } - var coords = this.getSpriteCoordinates(event); + var coords = this.renderer.getCoordinates(event.clientX, event.clientY); this.currentToolBehavior.applyToolAt( - coords.col, coords.row, + coords.x, + coords.y, this.getCurrentColor_(), this.piskelController.getCurrentFrame(), this.overlayFrame, @@ -136,11 +144,13 @@ var currentTime = new Date().getTime(); // Throttling of the mousemove event: if ((currentTime - this.previousMousemoveTime) > 40 ) { - var coords = this.getSpriteCoordinates(event); + var coords = this.renderer.getCoordinates(event.clientX, event.clientY); + if (this.isClicked) { this.currentToolBehavior.moveToolAt( - coords.col, coords.row, + coords.x, + coords.y, this.getCurrentColor_(), this.piskelController.getCurrentFrame(), this.overlayFrame, @@ -154,7 +164,8 @@ } else { this.currentToolBehavior.moveUnactiveToolAt( - coords.col, coords.row, + coords.x, + coords.y, this.getCurrentColor_(), this.piskelController.getCurrentFrame(), this.overlayFrame, @@ -168,10 +179,11 @@ ns.DrawingController.prototype.onMousewheel_ = function (jQueryEvent) { var event = jQueryEvent.originalEvent; var delta = event.wheelDeltaY; + var currentZoom = this.renderer.getZoom(); if (delta > 0) { - this.setZoom(this.zoom + 1); + this.rendererManager.setZoom(currentZoom + 1); } else if (delta < 0) { - this.setZoom(this.zoom - 1); + this.rendererManager.setZoom(currentZoom - 1); } }; @@ -188,10 +200,11 @@ this.isClicked = false; this.isRightClicked = false; - var coords = this.getSpriteCoordinates(event); + var coords = this.renderer.getCoordinates(event.clientX, event.clientY); //console.log("mousemove: col: " + spriteCoordinate.col + " - row: " + spriteCoordinate.row); this.currentToolBehavior.releaseToolAt( - coords.col, coords.row, + coords.x, + coords.y, this.getCurrentColor_(), this.piskelController.getCurrentFrame(), this.overlayFrame, @@ -215,23 +228,12 @@ return evtInfo; }; - /** - * @private - */ - ns.DrawingController.prototype.getRelativeCoordinates = function (clientX, clientY) { - var canvasPageOffset = this.container.offset(); - return { - x : clientX - canvasPageOffset.left, - y : clientY - canvasPageOffset.top - }; - }; /** * @private */ ns.DrawingController.prototype.getSpriteCoordinates = function(event) { - var coords = this.getRelativeCoordinates(event.clientX, event.clientY); - return this.renderer.convertPixelCoordinatesIntoSpriteCoordinate(coords); + return this.renderer.getCoordinates(event.clientX, event.clientY); }; /** @@ -265,23 +267,15 @@ }; ns.DrawingController.prototype.renderFrame = function () { - var frame = this.piskelController.getCurrentFrame(); - var serializedFrame = [this.zoom, this.xOffset, this.yOffset, frame.serialize()].join('-'); - if (this.serializedFrame != serializedFrame) { - if (!frame.isSameSize(this.overlayFrame)) { - this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(frame); - } - this.serializedFrame = serializedFrame; - this.renderer.render(frame); - } + this.renderer.render(this.piskelController.getCurrentFrame()); }; ns.DrawingController.prototype.renderOverlay = function () { - var serializedOverlay = [this.zoom, this.xOffset, this.yOffset, this.overlayFrame.serialize()].join('-'); - if (this.serializedOverlay != serializedOverlay) { - this.serializedOverlay = serializedOverlay; - this.overlayRenderer.render(this.overlayFrame); + var currentFrame = this.piskelController.getCurrentFrame(); + if (!currentFrame.isSameSize(this.overlayFrame)) { + this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(currentFrame); } + this.overlayRenderer.render(this.overlayFrame); }; ns.DrawingController.prototype.renderLayers = function () { @@ -349,39 +343,19 @@ ns.DrawingController.prototype.getContainerWidth_ = function () { return this.calculateZoom_() * this.piskelController.getCurrentFrame().getWidth(); }; + /** * @private */ - ns.DrawingController.prototype.updateZoom_ = function() { - this.setZoom(this.calculateZoom_()); - - var currentFrameHeight = this.piskelController.getCurrentFrame().getHeight(); - var canvasHeight = currentFrameHeight * this.zoom; - if (pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID)) { - canvasHeight += Constants.GRID_STROKE_WIDTH * currentFrameHeight; - } - - var verticalGapInPixel = Math.floor(($('#main-wrapper').height() - canvasHeight) / 2); + ns.DrawingController.prototype.centerColumnWrapperHorizontally_ = function() { + var containerHeight = this.getContainerHeight_(); + var verticalGapInPixel = Math.floor(($('#main-wrapper').height() - containerHeight) / 2); $('#column-wrapper').css({ - 'top': verticalGapInPixel + 'px', - 'height': canvasHeight + 'px' + 'top': verticalGapInPixel + 'px' }); }; - ns.DrawingController.prototype.setZoom = function (zoom) { - this.zoom = zoom; - this.overlayRenderer.setZoom(this.zoom); - this.renderer.setZoom(this.zoom); - this.layersAboveRenderer.setZoom(this.zoom); - this.layersBelowRenderer.setZoom(this.zoom); - }; - ns.DrawingController.prototype.moveOffset = function (xOffset, yOffset) { - this.xOffset = xOffset; - this.yOffset = yOffset; - this.overlayRenderer.setDisplayOffset(xOffset, yOffset); - this.renderer.setDisplayOffset(xOffset, yOffset); - this.layersAboveRenderer.setDisplayOffset(xOffset, yOffset); - this.layersBelowRenderer.setDisplayOffset(xOffset, yOffset); + this.rendererManager.moveOffset(xOffset, yOffset); }; })(); \ No newline at end of file diff --git a/js/controller/PreviewFilmController.js b/js/controller/PreviewFilmController.js index c231adbb..64aa1925 100644 --- a/js/controller/PreviewFilmController.js +++ b/js/controller/PreviewFilmController.js @@ -155,10 +155,10 @@ // is to make this update function (#createPreviewTile) less aggressive. var renderingOptions = { "zoom" : this.zoom, - "height" : "auto", - "width" : "auto" + "height" : this.piskelController.getCurrentFrame().getHeight() * this.zoom, + "width" : this.piskelController.getCurrentFrame().getWidth() * this.zoom }; - var currentFrameRenderer = new pskl.rendering.FrameRenderer($(canvasContainer), renderingOptions, ["tile-view"]); + var currentFrameRenderer = new pskl.rendering.frame.FrameRenderer($(canvasContainer), renderingOptions, ["tile-view"]); currentFrameRenderer.render(currentFrame); previewTileRoot.appendChild(canvasContainer); diff --git a/js/controller/settings/ApplicationSettingsController.js b/js/controller/settings/ApplicationSettingsController.js index 7329b596..27183642 100644 --- a/js/controller/settings/ApplicationSettingsController.js +++ b/js/controller/settings/ApplicationSettingsController.js @@ -1,6 +1,6 @@ (function () { var ns = $.namespace("pskl.controller.settings"); - + ns.ApplicationSettingsController = function () {}; /** @@ -18,21 +18,26 @@ $('#show-grid').prop('checked', show_grid); // Handle grid display changes: - $('#show-grid').change($.proxy(function(evt) { - var checked = $('#show-grid').prop('checked'); - pskl.UserSettings.set(pskl.UserSettings.SHOW_GRID, checked); - }, this)); + $('#show-grid').change(this.onShowGridClick.bind(this)); // Handle canvas background changes: - $('#background-picker-wrapper').click(function(evt) { - var target = $(evt.target).closest('.background-picker'); - if (target.length) { - var backgroundClass = target.data('background-class'); - pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, backgroundClass); - - $('.background-picker').removeClass('selected'); - target.addClass('selected'); - } - }); + $('#background-picker-wrapper').click(this.onBackgroundClick.bind(this)); }; + + ns.ApplicationSettingsController.prototype.onShowGridClick = function (evt) { + var checked = $('#show-grid').prop('checked'); + pskl.UserSettings.set(pskl.UserSettings.SHOW_GRID, checked); + }; + + ns.ApplicationSettingsController.prototype.onBackgroundClick = function (evt) { + var target = $(evt.target).closest('.background-picker'); + if (target.length) { + var backgroundClass = target.data('background-class'); + pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, backgroundClass); + + $('.background-picker').removeClass('selected'); + target.addClass('selected'); + } + }; + })(); \ No newline at end of file diff --git a/js/rendering/AbstractRenderer.js b/js/rendering/AbstractRenderer.js new file mode 100644 index 00000000..cb54169c --- /dev/null +++ b/js/rendering/AbstractRenderer.js @@ -0,0 +1,22 @@ +(function () { + var ns = $.namespace('pskl.rendering'); + + ns.AbstractRenderer = function () {}; + + ns.AbstractRenderer.prototype.render = function (frame) {throw 'abstract method should be implemented';}; + ns.AbstractRenderer.prototype.clear = function () {throw 'abstract method should be implemented';}; + + ns.AbstractRenderer.prototype.getCoordinates = function (x, y) {throw 'abstract method should be implemented';}; + + ns.AbstractRenderer.prototype.setGridEnabled = function (b) {throw 'abstract method should be implemented';}; + ns.AbstractRenderer.prototype.isGridEnabled = function () {throw 'abstract method should be implemented';}; + + ns.AbstractRenderer.prototype.setZoom = function (zoom) {throw 'abstract method should be implemented';}; + ns.AbstractRenderer.prototype.getZoom = function () {throw 'abstract method should be implemented';}; + + ns.AbstractRenderer.prototype.moveOffset = function (x, y) {throw 'abstract method should be implemented';}; + ns.AbstractRenderer.prototype.getOffset = function () {throw 'abstract method should be implemented';}; + + ns.AbstractRenderer.prototype.setDisplaySize = function (w, h) {throw 'abstract method should be implemented';}; + ns.AbstractRenderer.prototype.getDisplaySize = function () {throw 'abstract method should be implemented';}; +})(); \ No newline at end of file diff --git a/js/rendering/CachedRenderer.js b/js/rendering/CachedRenderer.js new file mode 100644 index 00000000..e02040f5 --- /dev/null +++ b/js/rendering/CachedRenderer.js @@ -0,0 +1,64 @@ +(function () { + var ns = $.namespace('pskl.rendering'); + + /** + * Decorator on a renderer that will only render the frame if something has changed in the frame itself or in the renderer's configuration + * @param {pskl.rendering.AbstractRenderer} renderer + */ + ns.CachedRenderer = function (renderer) { + this.decoratedRenderer = renderer; + this.serializedFrame = ''; + }; + + pskl.utils.inherit(ns.CachedRenderer, ns.AbstractRenderer); + + ns.CachedRenderer.prototype.render = function (frame) { + var offset = this.getOffset(); + var size = this.getDisplaySize(); + var serializedFrame = [this.getZoom(), offset.x, offset.y, size.width, size.height, frame.serialize()].join('-'); + if (this.serializedFrame != serializedFrame) { + this.serializedFrame = serializedFrame; + this.decoratedRenderer.render(frame); + } + }; + + ns.CachedRenderer.prototype.clear = function () { + this.decoratedRenderer.clear(); + }; + + ns.CachedRenderer.prototype.getCoordinates = function (x, y) { + return this.decoratedRenderer.getCoordinates(x, y); + }; + + ns.CachedRenderer.prototype.setGridEnabled = function (b) { + this.decoratedRenderer.setGridEnabled(b); + }; + + ns.CachedRenderer.prototype.isGridEnabled = function () { + return this.decoratedRenderer.isGridEnabled(); + }; + + ns.CachedRenderer.prototype.getZoom = function () { + return this.decoratedRenderer.getZoom(); + }; + + ns.CachedRenderer.prototype.setZoom = function (zoom) { + return this.decoratedRenderer.setZoom(zoom); + }; + + ns.CachedRenderer.prototype.moveOffset = function (x, y) { + this.decoratedRenderer.moveOffset(x, y); + }; + + ns.CachedRenderer.prototype.getOffset = function () { + return this.decoratedRenderer.getOffset(); + }; + + ns.CachedRenderer.prototype.setDisplaySize = function (w, h) { + this.decoratedRenderer.setDisplaySize(w, h); + }; + + ns.CachedRenderer.prototype.getDisplaySize = function () { + return this.decoratedRenderer.getDisplaySize(); + }; +})(); \ No newline at end of file diff --git a/js/rendering/RendererManager.js b/js/rendering/RendererManager.js new file mode 100644 index 00000000..f7a9dd1f --- /dev/null +++ b/js/rendering/RendererManager.js @@ -0,0 +1,30 @@ +(function () { + var ns = $.namespace('pskl.rendering'); + + ns.RendererManager = function () { + this.renderers = []; + }; + + ns.RendererManager.prototype.add = function (renderer) { + this.renderers.push(renderer); + return this; + }; + + ns.RendererManager.prototype.setZoom = function (zoom) { + this.renderers.forEach(function (renderer) { + renderer.setZoom(zoom); + }); + }; + + ns.RendererManager.prototype.setDisplaySize = function (w, h) { + this.renderers.forEach(function (renderer) { + renderer.setDisplaySize(w, h); + }); + }; + + ns.RendererManager.prototype.moveOffset = function (offsetX, offsetY) { + this.renderers.forEach(function (renderer) { + renderer.moveOffset(offsetX, offsetY); + }); + }; +})(); \ No newline at end of file diff --git a/js/rendering/frame/CachedFrameRenderer.js b/js/rendering/frame/CachedFrameRenderer.js new file mode 100644 index 00000000..4949549d --- /dev/null +++ b/js/rendering/frame/CachedFrameRenderer.js @@ -0,0 +1,18 @@ +(function () { + var ns = $.namespace('pskl.rendering.frame'); + + /** + * Cached renderer that can uses the same constructor as pskl.rendering.FrameRenderer + * It will build a FrameRenderer on the fly to use as decorated renderer + * @param {HtmlElement} container HtmlElement to use as parentNode of the Frame + * @param {Object} renderingOptions + * @param {Array} classes array of strings to use for css classes + */ + ns.CachedFrameRenderer = function (container, renderingOptions, classes) { + var frameRenderer = new pskl.rendering.frame.FrameRenderer(container, renderingOptions, classes); + pskl.rendering.CachedRenderer.call(this, frameRenderer); + }; + + pskl.utils.inherit(pskl.rendering.frame.CachedFrameRenderer, pskl.rendering.CachedRenderer); + +})(); diff --git a/js/rendering/FrameRenderer.js b/js/rendering/frame/FrameRenderer.js similarity index 67% rename from js/rendering/FrameRenderer.js rename to js/rendering/frame/FrameRenderer.js index 7e49416f..3308ea68 100644 --- a/js/rendering/FrameRenderer.js +++ b/js/rendering/frame/FrameRenderer.js @@ -1,5 +1,5 @@ (function () { - var ns = $.namespace("pskl.rendering"); + var ns = $.namespace("pskl.rendering.frame"); /** * FrameRenderer will display a given frame inside a canvas element. @@ -27,11 +27,15 @@ this.zoom = renderingOptions.zoom; - this.frameOffsetX = 0; - this.frameOffsetY = 0; + this.offset = { + x : 0, + y : 0 + }; - this.marginY = 0; - this.marginX = 0; + this.margin = { + x : 0, + y : 0 + }; this.supportGridRendering = renderingOptions.supportGridRendering; @@ -51,93 +55,12 @@ this.displayCanvas = null; this.setDisplaySize(renderingOptions.width, renderingOptions.height); - this.enableGrid(pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID)); + this.setGridEnabled(pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID)); this.updateBackgroundClass_(pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); }; - ns.FrameRenderer.prototype.setZoom = function (zoom) { - this.zoom = zoom; - }; - - ns.FrameRenderer.prototype.isAutoSized_ = function () { - return this.displayHeight === 'auto' && this.displayWidth === 'auto'; - }; - - ns.FrameRenderer.prototype.setDisplaySize = function (width, height) { - this.displayHeight = height; - this.displayWidth = width; - if (this.displayCanvas) { - $(this.displayCanvas).remove(); - this.displayCanvas = null; - } - }; - - ns.FrameRenderer.prototype.updateMargins_ = function () { - if (!this.isAutoSized_()) { - var deltaX = this.displayWidth - (this.zoom * this.canvas.width); - this.marginX = Math.max(0, deltaX) / 2; - - var deltaY = this.displayHeight - (this.zoom * this.canvas.height); - this.marginY = Math.max(0, deltaY) / 2; - } - }; - - ns.FrameRenderer.prototype.createDisplayCanvas_ = function () { - var height = this.displayHeight; - var width = this.displayWidth; - - if (this.isAutoSized_()) { - height = this.zoom * this.canvas.height; - width = this.zoom * this.canvas.width; - } - - this.displayCanvas = pskl.CanvasUtils.createCanvas(width, height, this.classes); - if (true || this.zoom > 2) { - pskl.CanvasUtils.disableImageSmoothing(this.displayCanvas); - } - this.container.append(this.displayCanvas); - }; - - ns.FrameRenderer.prototype.setDisplayOffset = function (frameOffsetX, frameOffsetY) { - this.frameOffsetX = frameOffsetX; - this.frameOffsetY = frameOffsetY; - }; - - ns.FrameRenderer.prototype.moveOffset = function (frameOffsetX, frameOffsetY) { - this.setDisplayOffset(this.frameOffsetX + frameOffsetX, this.frameOffsetY + frameOffsetY); - }; - - /** - * @private - */ - ns.FrameRenderer.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { - if(settingName == pskl.UserSettings.SHOW_GRID) { - this.enableGrid(settingValue); - } - else if (settingName == pskl.UserSettings.CANVAS_BACKGROUND) { - this.updateBackgroundClass_(settingValue); - } - }; - - /** - * @private - */ - ns.FrameRenderer.prototype.updateBackgroundClass_ = function (newClass) { - var currentClass = this.container.data('current-background-class'); - if (currentClass) { - this.container.removeClass(currentClass); - } - this.container.addClass(newClass); - this.container.data('current-background-class', newClass); - }; - - ns.FrameRenderer.prototype.enableGrid = function (flag) { - this.gridStrokeWidth = (flag && this.supportGridRendering) ? Constants.GRID_STROKE_WIDTH : 0; - this.canvasConfigDirty = true; - }; - ns.FrameRenderer.prototype.render = function (frame) { if (frame) { this.clear(); @@ -150,10 +73,92 @@ pskl.CanvasUtils.clear(this.displayCanvas); }; - ns.FrameRenderer.prototype.renderPixel_ = function (color, col, row, context) { + ns.FrameRenderer.prototype.setZoom = function (zoom) { + this.zoom = zoom; + }; + + ns.FrameRenderer.prototype.getZoom = function () { + return this.zoom; + }; + + ns.FrameRenderer.prototype.setDisplaySize = function (width, height) { + this.displayWidth = width; + this.displayHeight = height; + if (this.displayCanvas) { + $(this.displayCanvas).remove(); + this.displayCanvas = null; + } + this.createDisplayCanvas_(); + }; + + ns.FrameRenderer.prototype.getDisplaySize = function () { + return { + height : this.displayHeight, + width : this.displayWidth + }; + }; + + ns.FrameRenderer.prototype.getOffset = function () { + return { + x : this.offset.x, + y : this.offset.y + }; + }, + + ns.FrameRenderer.prototype.moveOffset = function (x, y) { + this.setOffset_(this.offset.x + x, this.offset.y + y); + }; + + ns.FrameRenderer.prototype.setGridEnabled = function (flag) { + this.gridStrokeWidth = (flag && this.supportGridRendering) ? Constants.GRID_STROKE_WIDTH : 0; + this.canvasConfigDirty = true; + }; + + ns.FrameRenderer.prototype.updateMargins_ = function () { + var deltaX = this.displayWidth - (this.zoom * this.canvas.width); + this.margin.x = Math.max(0, deltaX) / 2; + + var deltaY = this.displayHeight - (this.zoom * this.canvas.height); + this.margin.y = Math.max(0, deltaY) / 2; + }; + + ns.FrameRenderer.prototype.createDisplayCanvas_ = function () { + var height = this.displayHeight; + var width = this.displayWidth; + + this.displayCanvas = pskl.CanvasUtils.createCanvas(width, height, this.classes); + if (true || this.zoom > 2) { + pskl.CanvasUtils.disableImageSmoothing(this.displayCanvas); + } + this.container.append(this.displayCanvas); + }; + + ns.FrameRenderer.prototype.setOffset_ = function (x, y) { + this.offset.x = x; + this.offset.y = y; + }; + + ns.FrameRenderer.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { + if(settingName == pskl.UserSettings.SHOW_GRID) { + this.setGridEnabled(settingValue); + } else if (settingName == pskl.UserSettings.CANVAS_BACKGROUND) { + this.updateBackgroundClass_(settingValue); + } + }; + + ns.FrameRenderer.prototype.updateBackgroundClass_ = function (newClass) { + var currentClass = this.container.data('current-background-class'); + if (currentClass) { + this.container.removeClass(currentClass); + } + this.container.addClass(newClass); + this.container.data('current-background-class', newClass); + }; + + ns.FrameRenderer.prototype.renderPixel_ = function (color, x, y, context) { if(color != Constants.TRANSPARENT_COLOR) { context.fillStyle = color; - context.fillRect(col, row, 1, 1); + context.fillRect(x, y, 1, 1); } }; @@ -162,13 +167,23 @@ * frame) into a sprite coordinate in column and row. * @public */ - ns.FrameRenderer.prototype.convertPixelCoordinatesIntoSpriteCoordinate = function(coords) { + ns.FrameRenderer.prototype.getCoordinates = function(x, y) { + var containerOffset = this.container.offset(); + x = x - containerOffset.left; + y = y - containerOffset.top; + + // apply margins + x = x - this.margin.x; + y = y - this.margin.y; + var cellSize = this.zoom + this.gridStrokeWidth; - var xCoord = (coords.x - this.marginX) + (this.frameOffsetX * cellSize), - yCoord = (coords.y - this.marginY) + (this.frameOffsetY * cellSize); + // apply frame offset + x = x + this.offset.x * cellSize; + y = y + this.offset.y * cellSize; + return { - "col" : (xCoord - xCoord % cellSize) / cellSize, - "row" : (yCoord - yCoord % cellSize) / cellSize + x : (x / cellSize) | 0, + y : (y / cellSize) | 0 }; }; @@ -188,17 +203,13 @@ } var context = this.canvas.getContext('2d'); - for(var col = 0, width = frame.getWidth(); col < width; col++) { - for(var row = 0, height = frame.getHeight(); row < height; row++) { - var color = frame.getPixel(col, row); - this.renderPixel_(color, col, row, context); + 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); } } - if (!this.displayCanvas) { - this.createDisplayCanvas_(); - } - this.updateMargins_(); context = this.displayCanvas.getContext('2d'); @@ -207,9 +218,9 @@ context.fillStyle = "#aaa"; // zoom < 1 context.fillRect(0,0,this.displayCanvas.width, this.displayCanvas.height); - context.translate(this.marginX, this.marginY); + context.translate(this.margin.x, this.margin.y); context.scale(this.zoom, this.zoom); - context.translate(-this.frameOffsetX, -this.frameOffsetY); + context.translate(-this.offset.x, -this.offset.y); // zoom < 1 context.clearRect(0, 0, this.canvas.width, this.canvas.height); context.drawImage(this.canvas, 0, 0); diff --git a/piskel-script-list.js b/piskel-script-list.js index a35ebdcf..9ab2f1b2 100644 --- a/piskel-script-list.js +++ b/piskel-script-list.js @@ -36,8 +36,12 @@ exports.scripts = [ "js/selection/ShapeSelection.js", // Rendering + "js/rendering/RendererManager.js", + "js/rendering/AbstractRenderer.js", + "js/rendering/CachedRenderer.js", + "js/rendering/frame/FrameRenderer.js", + "js/rendering/frame/CachedFrameRenderer.js", "js/rendering/CanvasRenderer.js", - "js/rendering/FrameRenderer.js", "js/rendering/SpritesheetRenderer.js", // Controllers