Merge pull request #482 from juliandescottes/feature-tiled-drawing

Feature tiled drawing
This commit is contained in:
Julian Descottes 2016-06-04 17:07:28 +02:00
commit 014a1d418f
9 changed files with 82 additions and 66 deletions

View File

@ -3,42 +3,37 @@
/*******************************/ /*******************************/
.background-picker-wrapper { .background-picker-wrapper {
display: inline-block;
width: 130px;
overflow: hidden; overflow: hidden;
padding: 5px 5px 2px 5px; vertical-align: middle;
margin-left: 5px;
} }
.background-picker { .background-picker {
cursor: pointer; cursor: pointer;
float: left; float: left;
height: 35px; height: 14px;
width: 35px; width: 14px;
background-color: transparent; background-color: transparent;
margin-right: 15px; margin-right: 5px;
padding: 1px; padding: 1px;
position: relative; position: relative;
border: #888 2px solid;
} }
.background-picker:after { .background-picker:hover {
content: " "; border-color: #eee;
position: absolute;
top: -2px;
right: -2px;
bottom: -2px;
left: -2px;
} }
.background-picker:hover:after { .background-picker.selected {
border: #eee 1px solid; border-color: gold;
}
.background-picker.selected:after {
border: gold 1px solid;
} }
.layer-opacity-input { .layer-opacity-input {
margin: 5px; margin: 5px;
vertical-align: middle; vertical-align: middle;
width: 145px; width: 100px;
} }
.layer-opacity-text { .layer-opacity-text {
@ -53,9 +48,10 @@
} }
.grid-width-select { .grid-width-select {
margin: 5px; margin: 5px 5px 0 5px;
} }
.settings-section-application > .settings-item > label { .settings-section-application > .settings-title {
display: block; /* Override the default 10px margin bottom for this panel */
margin-bottom: 15px;
} }

View File

@ -21,6 +21,7 @@ var Constants = {
DEFAULT_PEN_COLOR : '#000000', DEFAULT_PEN_COLOR : '#000000',
TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)', TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)',
SEAMLESS_MODE_OVERLAY_COLOR : 'rgba(255, 255, 255, 0.5)',
CURRENT_COLORS_PALETTE_ID : '__current-colors', CURRENT_COLORS_PALETTE_ID : '__current-colors',

View File

@ -116,8 +116,8 @@
ns.PreviewController.prototype.updateZoom_ = function () { ns.PreviewController.prototype.updateZoom_ = function () {
var originalSizeEnabled = pskl.UserSettings.get(pskl.UserSettings.ORIGINAL_SIZE_PREVIEW); var originalSizeEnabled = pskl.UserSettings.get(pskl.UserSettings.ORIGINAL_SIZE_PREVIEW);
var tiledPreviewEnabled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); var seamlessModeEnabled = pskl.UserSettings.get(pskl.UserSettings.SEAMLESS_MODE);
var useOriginalSize = originalSizeEnabled || tiledPreviewEnabled; var useOriginalSize = originalSizeEnabled || seamlessModeEnabled;
var zoom = useOriginalSize ? 1 : this.calculateZoom_(); var zoom = useOriginalSize ? 1 : this.calculateZoom_();
this.renderer.setZoom(zoom); this.renderer.setZoom(zoom);
@ -208,12 +208,12 @@
}; };
ns.PreviewController.prototype.updateContainerDimensions_ = function () { ns.PreviewController.prototype.updateContainerDimensions_ = function () {
var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); var isSeamless = pskl.UserSettings.get(pskl.UserSettings.SEAMLESS_MODE);
this.renderer.setRepeated(isTiled); this.renderer.setRepeated(isSeamless);
var height, width; var height, width;
if (isTiled) { if (isSeamless) {
height = PREVIEW_SIZE; height = PREVIEW_SIZE;
width = PREVIEW_SIZE; width = PREVIEW_SIZE;
} else { } else {

View File

@ -26,13 +26,13 @@
this.addEventListener(gridSelect, 'change', this.onGridWidthChange_); this.addEventListener(gridSelect, 'change', this.onGridWidthChange_);
// Tiled preview // Seamless mode
var tiledPreview = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); var seamlessMode = pskl.UserSettings.get(pskl.UserSettings.SEAMLESS_MODE);
var tiledPreviewCheckbox = document.querySelector('.tiled-preview-checkbox'); var seamlessModeCheckbox = document.querySelector('.seamless-mode-checkbox');
if (tiledPreview) { if (seamlessMode) {
tiledPreviewCheckbox.setAttribute('checked', tiledPreview); seamlessModeCheckbox.setAttribute('checked', seamlessMode);
} }
this.addEventListener(tiledPreviewCheckbox, 'change', this.onTiledPreviewChange_); this.addEventListener(seamlessModeCheckbox, 'change', this.onSeamlessModeChange_);
// Max FPS // Max FPS
var maxFpsInput = document.querySelector('.max-fps-input'); var maxFpsInput = document.querySelector('.max-fps-input');
@ -55,8 +55,8 @@
pskl.UserSettings.set(pskl.UserSettings.GRID_WIDTH, width); pskl.UserSettings.set(pskl.UserSettings.GRID_WIDTH, width);
}; };
ns.ApplicationSettingsController.prototype.onTiledPreviewChange_ = function (evt) { ns.ApplicationSettingsController.prototype.onSeamlessModeChange_ = function (evt) {
pskl.UserSettings.set(pskl.UserSettings.TILED_PREVIEW, evt.currentTarget.checked); pskl.UserSettings.set(pskl.UserSettings.SEAMLESS_MODE, evt.currentTarget.checked);
}; };
ns.ApplicationSettingsController.prototype.onBackgroundClick_ = function (evt) { ns.ApplicationSettingsController.prototype.onBackgroundClick_ = function (evt) {

View File

@ -34,6 +34,7 @@
var serializedFrame = [ var serializedFrame = [
this.getZoom(), this.getZoom(),
this.getGridWidth(), this.getGridWidth(),
pskl.UserSettings.get('SEAMLESS_MODE'),
offset.x, offset.y, offset.x, offset.y,
size.width, size.height, size.width, size.height,
frame.getHash() frame.getHash()

View File

@ -237,6 +237,10 @@
this.canvas = pskl.utils.CanvasUtils.createCanvas(frame.getWidth(), frame.getHeight()); this.canvas = pskl.utils.CanvasUtils.createCanvas(frame.getWidth(), frame.getHeight());
} }
var w = this.canvas.width;
var h = this.canvas.height;
var z = this.zoom;
// Draw in canvas // Draw in canvas
pskl.utils.FrameUtils.drawToCanvas(frame, this.canvas); pskl.utils.FrameUtils.drawToCanvas(frame, this.canvas);
@ -245,31 +249,51 @@
var displayContext = this.displayCanvas.getContext('2d'); var displayContext = this.displayCanvas.getContext('2d');
displayContext.save(); displayContext.save();
var smallerHeight = this.canvas.height * this.zoom < this.displayCanvas.height; // Draw background
var smallerWidth = this.canvas.width * this.zoom < this.displayCanvas.width; displayContext.fillStyle = Constants.ZOOMED_OUT_BACKGROUND_COLOR;
if (smallerHeight || smallerWidth) { displayContext.fillRect(0, 0, this.displayCanvas.width - 1, this.displayCanvas.height - 1);
displayContext.fillStyle = Constants.ZOOMED_OUT_BACKGROUND_COLOR;
displayContext.fillRect(0, 0, this.displayCanvas.width - 1, this.displayCanvas.height - 1);
}
displayContext.translate( displayContext.translate(
this.margin.x - this.offset.x * this.zoom, this.margin.x - this.offset.x * z,
this.margin.y - this.offset.y * this.zoom this.margin.y - this.offset.y * z
); );
displayContext.clearRect(0, 0, this.canvas.width * this.zoom, this.canvas.height * this.zoom); if (pskl.UserSettings.get('SEAMLESS_MODE')) {
displayContext.clearRect(-1 * w * z, -1 * h * z, 3 * w * z, 3 * h * z);
var isIE10 = pskl.utils.UserAgent.isIE && pskl.utils.UserAgent.version === 10; } else {
displayContext.clearRect(0, 0, w * z, h * z);
}
var gridWidth = this.computeGridWidthForDisplay_(); var gridWidth = this.computeGridWidthForDisplay_();
var isGridEnabled = gridWidth > 0; if (gridWidth > 0) {
if (isGridEnabled || isIE10) { var scaled = pskl.utils.ImageResizer.resizeNearestNeighbour(this.canvas, z, gridWidth);
var scaled = pskl.utils.ImageResizer.resizeNearestNeighbour(this.canvas, this.zoom, gridWidth);
if (pskl.UserSettings.get('SEAMLESS_MODE')) {
this.drawTiledFrames_(displayContext, scaled, w, h, z);
}
displayContext.drawImage(scaled, 0, 0); displayContext.drawImage(scaled, 0, 0);
} else { } else {
displayContext.scale(this.zoom, this.zoom); displayContext.scale(z, z);
if (pskl.UserSettings.get('SEAMLESS_MODE')) {
this.drawTiledFrames_(displayContext, this.canvas, w, h, 1);
}
displayContext.drawImage(this.canvas, 0, 0); displayContext.drawImage(this.canvas, 0, 0);
} }
displayContext.restore(); displayContext.restore();
}; };
/**
* Draw repeatedly the provided image around the main drawing area. Used for seamless
* drawing mode, to easily create seamless textures. A colored overlay is applied to
* differentiate those additional frames from the main frame.
*/
ns.FrameRenderer.prototype.drawTiledFrames_ = function (context, image, w, h, z) {
context.fillStyle = Constants.SEAMLESS_MODE_OVERLAY_COLOR;
[[0, -1], [0, 1], [-1, -1], [-1, 0], [-1, 1], [1, -1], [1, 0], [1, 1]].forEach(function (d) {
context.drawImage(image, d[0] * w * z, d[1] * h * z);
context.fillRect(d[0] * w * z, d[1] * h * z, w * z, h * z);
});
};
})(); })();

View File

@ -7,7 +7,7 @@
DEFAULT_SIZE : 'DEFAULT_SIZE', DEFAULT_SIZE : 'DEFAULT_SIZE',
CANVAS_BACKGROUND : 'CANVAS_BACKGROUND', CANVAS_BACKGROUND : 'CANVAS_BACKGROUND',
SELECTED_PALETTE : 'SELECTED_PALETTE', SELECTED_PALETTE : 'SELECTED_PALETTE',
TILED_PREVIEW : 'TILED_PREVIEW', SEAMLESS_MODE : 'SEAMLESS_MODE',
ORIGINAL_SIZE_PREVIEW : 'ORIGINAL_SIZE_PREVIEW', ORIGINAL_SIZE_PREVIEW : 'ORIGINAL_SIZE_PREVIEW',
ONION_SKIN : 'ONION_SKIN', ONION_SKIN : 'ONION_SKIN',
LAYER_PREVIEW : 'LAYER_PREVIEW', LAYER_PREVIEW : 'LAYER_PREVIEW',
@ -26,7 +26,7 @@
}, },
'CANVAS_BACKGROUND' : 'lowcont-dark-canvas-background', 'CANVAS_BACKGROUND' : 'lowcont-dark-canvas-background',
'SELECTED_PALETTE' : Constants.CURRENT_COLORS_PALETTE_ID, 'SELECTED_PALETTE' : Constants.CURRENT_COLORS_PALETTE_ID,
'TILED_PREVIEW' : false, 'SEAMLESS_MODE' : false,
'ORIGINAL_SIZE_PREVIEW' : false, 'ORIGINAL_SIZE_PREVIEW' : false,
'ONION_SKIN' : false, 'ONION_SKIN' : false,
'LAYER_OPACITY' : 0.2, 'LAYER_OPACITY' : 0.2,

View File

@ -4,6 +4,7 @@
<div class="settings-title"> <div class="settings-title">
General General
</div> </div>
<div class="settings-item"> <div class="settings-item">
<label>Background</label> <label>Background</label>
<div class="background-picker-wrapper"> <div class="background-picker-wrapper">
@ -23,7 +24,7 @@
</div> </div>
<div class="settings-item"> <div class="settings-item">
<label for="grid-width">Grid</label> <label for="grid-width">Pixel Grid</label>
<select id="grid-width" class="grid-width-select"> <select id="grid-width" class="grid-width-select">
<option value="0">Disabled</option> <option value="0">Disabled</option>
<option value="1">1px</option> <option value="1">1px</option>
@ -34,31 +35,24 @@
</div> </div>
<div class="settings-item"> <div class="settings-item">
<label for="tiled-preview">Layer Preview Opacity</label> <label>Layer Opacity</label>
<input type="range" class="layer-opacity-input" name="layer-opacity" min="0" max="1" step="0.05"/> <input type="range" class="layer-opacity-input" name="layer-opacity" min="0" max="1" step="0.05"/>
<span class="layer-opacity-text"></span> <span class="layer-opacity-text"></span>
</div> </div>
</div>
<div class="settings-section">
<div class="settings-title">
Preview
</div>
<div class="settings-item"> <div class="settings-item">
<label> <label>
<input type="checkbox" value="1" class="tiled-preview-checkbox checkbox-fix" name="tiled-preview-checkbox"/> Seamless drawing mode
Repeated preview <input type="checkbox" value="1" class="seamless-mode-checkbox" name="seamless-mode-checkbox"/>
</label> </label>
</div> </div>
<div class="settings-item"> <div class="settings-item">
<label for="tiled-preview">Maximum FPS </label> <label>Maximum FPS</label>
<input type="text" class="textfield textfield-small max-fps-input" autocomplete="off" name="max-fps"/> <input type="text" class="textfield textfield-small max-fps-input" autocomplete="off" name="max-fps"/>
</div> </div>
<input type="submit" class="button button-primary" value="Save" /> <input type="submit" class="button button-primary" value="Apply settings" />
</div> </div>
</form> </form>
</script> </script>

View File

@ -1,7 +1,7 @@
<script type="text/html" id="templates/settings/export.html"> <script type="text/html" id="templates/settings/export.html">
<div class="settings-section settings-section-export"> <div class="settings-section settings-section-export">
<div class="settings-title">Export</div> <div class="settings-title">Export</div>
<div class="settings-item export-scale" title="Scale the exported PNG spritesheet" <div class="settings-item export-scale" title="Scale the animation for export"
rel="tooltip" rel="tooltip"
data-placement="top"> data-placement="top">
<label for="scale-input">Scale</label> <label for="scale-input">Scale</label>