diff --git a/js/interface/menu_bar.js b/js/interface/menu_bar.js index 1fa2bf65..364244e8 100644 --- a/js/interface/menu_bar.js +++ b/js/interface/menu_bar.js @@ -311,6 +311,7 @@ const MenuBar = { 'adjust_curves', '_', 'limit_to_palette', + 'clear_unused_texture_space', '_', 'flip_texture_x', 'flip_texture_y', diff --git a/js/texturing/edit_texture.js b/js/texturing/edit_texture.js index 220258df..e4e885e7 100644 --- a/js/texturing/edit_texture.js +++ b/js/texturing/edit_texture.js @@ -613,6 +613,65 @@ BARS.defineActions(function() { Undo.finishEdit('Limit texture to palette') } }) + new Action('clear_unused_texture_space', { + icon: 'cleaning_services', + category: 'textures', + condition: {modes: ['paint'], features: ['edit_mode'], method: () => Texture.all.length}, + click() { + let textures = getTextures(); + Undo.initEdit({textures, bitmap: true}); + textures.forEach(texture => { + if (texture.frameCount > 1) { + Blockbench.showQuickMessage('This feature does not work on animated textures at the moment'); + return; + } + texture.edit((canvas) => { + // todo: flipbook animation support + let ctx = canvas.getContext('2d'); + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.beginPath(); + + Outliner.elements.forEach(el => { + if (el instanceof Mesh) { + for (var fkey in el.faces) { + var face = el.faces[fkey]; + if (face.vertices.length <= 2 || face.getTexture() !== texture) continue; + + let matrix = face.getOccupationMatrix(true, [0, 0]); + for (let x in matrix) { + for (let y in matrix[x]) { + if (!matrix[x][y]) continue; + x = parseInt(x); y = parseInt(y); + ctx.rect(x, y, 1, 1); + } + } + } + } else if (el instanceof Cube) { + let factor_x = texture.width / Project.texture_width; + let factor_y = texture.height / Project.texture_height; + for (var fkey in el.faces) { + var face = el.faces[fkey]; + if (face.getTexture() !== texture) continue; + + let rect = face.getBoundingRect(); + let canvasRect = [ + Math.floor(rect.ax * factor_x), + Math.floor(rect.ay * factor_y), + Math.ceil(rect.bx * factor_x) - Math.floor(rect.ax * factor_x), + Math.ceil(rect.by * factor_y) - Math.floor(rect.ay * factor_y), + ] + ctx.rect(...canvasRect); + } + } + }) + + ctx.clip(); + ctx.drawImage(texture.img, 0, 0); + }, {no_undo: true}); + }) + Undo.finishEdit('Clear unused texture space') + } + }) // Transform new Action('flip_texture_x', { diff --git a/js/texturing/textures.js b/js/texturing/textures.js index 1cfae55d..380706fa 100644 --- a/js/texturing/textures.js +++ b/js/texturing/textures.js @@ -1554,6 +1554,7 @@ class Texture { 'adjust_curves', '_', 'limit_to_palette', + 'clear_unused_texture_space', '_', 'flip_texture_x', 'flip_texture_y', diff --git a/lang/en.json b/lang/en.json index d64728de..879430e7 100644 --- a/lang/en.json +++ b/lang/en.json @@ -1381,6 +1381,8 @@ "action.adjust_curves.desc": "Adjust the brightness curves of the selected texture", "action.limit_to_palette": "Limit to Palette", "action.limit_to_palette.desc": "Limits the colors of the texture to those in the currently loaded palette", + "action.clear_unused_texture_space": "Clear Unused Texture Space", + "action.clear_unused_texture_space.desc": "Clear parts of the texture that are not UV-mapped to any elements", "action.flip_texture_x": "Flip Texture Horizontally", "action.flip_texture_y": "Flip Texture Vertically", "action.rotate_texture_cw": "Rotate Texture Clockwise", diff --git a/lib/CanvasFrame.js b/lib/CanvasFrame.js index 3fa77666..da465a68 100644 --- a/lib/CanvasFrame.js +++ b/lib/CanvasFrame.js @@ -48,10 +48,10 @@ class CanvasFrame { } this.ctx.drawImage(img, 0, 0) } - loadFromCanvas(img) { - this.canvas.width = image.naturalWidth; - this.canvas.height = image.naturalHeight; - this.ctx.drawImage(img, 0, 0) + loadFromCanvas(canvas) { + this.canvas.width = canvas.width; + this.canvas.height = canvas.height; + this.ctx.drawImage(canvas, 0, 0) } autoCrop() { // Based on code by remy, licensed under MIT