From ec49a12a36f00407b210ef94a06b34983eaa4750 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Sat, 9 Dec 2023 13:08:36 +0100 Subject: [PATCH 01/14] Fix layer changes not marking texture as internal --- js/texturing/painter.js | 4 +--- js/texturing/textures.js | 12 +++++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/js/texturing/painter.js b/js/texturing/painter.js index d32b2cf1f..ce22179eb 100644 --- a/js/texturing/painter.js +++ b/js/texturing/painter.js @@ -11,9 +11,7 @@ const Painter = { if (!options.no_undo && !options.no_undo_init) { Undo.initEdit({textures: [texture], bitmap: true}) } - if (texture.mode === 'link') { - texture.convertToInternal(); - } + if (!texture.internal) texture.convertToInternal(); let edit_name = options.no_undo ? null : (options.edit_name || 'Edit texture'); let {canvas, ctx, offset} = texture.getActiveCanvas(); diff --git a/js/texturing/textures.js b/js/texturing/textures.js index d96a9de36..76a0f3f48 100644 --- a/js/texturing/textures.js +++ b/js/texturing/textures.js @@ -1663,6 +1663,7 @@ class Texture { } } updateChangesAfterEdit() { + if (!this.internal) this.convertToInternal(); if (this.layers_enabled) { this.updateLayerChanges(true); } else { @@ -1700,17 +1701,14 @@ class Texture { } return this; } - edit(cb, options) { - var scope = this; - if (!options) options = false; - + edit(cb, options = 0) { if (cb) { - Painter.edit(scope, cb, options); + Painter.edit(this, cb, options); - } else if (scope.mode === 'link') { + } else if (this.mode === 'link') { this.convertToInternal(); } - scope.saved = false; + this.saved = false; } } Texture.prototype.menu = new Menu([ From 924688f7e958d799812353e9039cab4c3b3468a7 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Sat, 9 Dec 2023 21:04:56 +0100 Subject: [PATCH 02/14] Fix texture resizing issue with per texture UV size --- js/texturing/textures.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/texturing/textures.js b/js/texturing/textures.js index 76a0f3f48..5b24f7d44 100644 --- a/js/texturing/textures.js +++ b/js/texturing/textures.js @@ -1276,11 +1276,11 @@ class Texture { // Nothing } else if (formResult.fill === 'repeat' && Format.animated_textures && formResult.size[0] < formResult.size[1]) { // Animated - } else if ((Format.single_texture || Texture.all.length == 1)) { + } else if (Format.single_texture || Texture.all.length == 1 || Format.per_texture_uv_size) { if (Format.per_texture_uv_size) { - this.uv_width = Project.texture_width * (formResult.size[0] / old_width); - this.uv_height = Project.texture_height * (formResult.size[1] / old_height); + scope.uv_width = Project.texture_width * (formResult.size[0] / old_width); + scope.uv_height = Project.texture_height * (formResult.size[1] / old_height); } else { Undo.current_save.uv_mode = { box_uv: Project.box_uv, From 6ab3c53e56ac6ebeacfd1095747fa9c66425a80e Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Sun, 10 Dec 2023 11:46:53 +0100 Subject: [PATCH 03/14] Fix typo in shared actions --- js/interface/shared_actions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/interface/shared_actions.js b/js/interface/shared_actions.js index e33df68ca..cd6d6243b 100644 --- a/js/interface/shared_actions.js +++ b/js/interface/shared_actions.js @@ -21,7 +21,7 @@ const SharedActions = { return { delete() { - lsit.remove(handler); + list.remove(handler); } } }, From 08d86dfd79ea17c3b17f4f12e2682a9d8650b43c Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Wed, 13 Dec 2023 14:21:26 +0100 Subject: [PATCH 04/14] Add bedrock attachable preview support for nested binding Add new globals Fix error in bbmodel merging --- js/display_mode.js | 16 +++++++++++++--- js/globals.js | 2 ++ js/io/formats/bbmodel.js | 6 +++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/js/display_mode.js b/js/display_mode.js index 8dee8520a..7cada3553 100644 --- a/js/display_mode.js +++ b/js/display_mode.js @@ -2136,8 +2136,13 @@ BARS.defineActions(function() { let player_skin_setup = false; function updateBase(mode) { + let root_has_binding = Outliner.root.find(g => g instanceof Group && g.bedrock_binding) if (mode == 'attachable_first') { - Project.model_3d.position.set(-20, 21, 0); + if (root_has_binding) { + Project.model_3d.position.set(-20, 21, 0); + } else { + Project.model_3d.position.set(-8, 6, -18); + } Project.model_3d.rotation.set( Math.degToRad(-95), Math.degToRad(45), @@ -2151,8 +2156,13 @@ BARS.defineActions(function() { if (mode == 'attachable_third') { let angle = Math.degToRad(15); - let arm_offset = Reusable.vec1.set(1, -31, 1).applyAxisAngle(Reusable.vec2.set(1, 0, 0), angle); - Project.model_3d.position.set(5, 22, 0).add(arm_offset); + if (root_has_binding) { + let arm_offset = Reusable.vec1.set(1, -31, 1).applyAxisAngle(Reusable.vec2.set(1, 0, 0), angle); + Project.model_3d.position.set(5, 22, 0).add(arm_offset); + } else { + let arm_offset = Reusable.vec1.set(1, -7, 1).applyAxisAngle(Reusable.vec2.set(1, 0, 0), angle); + Project.model_3d.position.set(5, 22, 0).add(arm_offset); + } Project.model_3d.rotation.set(angle, 0, 0); player_preview_model.enable() diff --git a/js/globals.js b/js/globals.js index 0d45febb5..82b318663 100644 --- a/js/globals.js +++ b/js/globals.js @@ -66,3 +66,5 @@ Blockbench.DisplaySlot = DisplaySlot; Blockbench.Reusable = Reusable; Blockbench.Texture = Texture; +Blockbench.TextureLayer = TextureLayer; +Blockbench.SharedActions = SharedActions; diff --git a/js/io/formats/bbmodel.js b/js/io/formats/bbmodel.js index 7ae4988d2..aa5efa16d 100644 --- a/js/io/formats/bbmodel.js +++ b/js/io/formats/bbmodel.js @@ -598,10 +598,10 @@ var codec = new Codec('project', { ani.uuid = guid(); } if (base_ani.animators) { - for (let key in animators) { + for (let key in base_ani.animators) { if (uuid_map[key]) { - animators[uuid_map[key]] = animators[key]; - delete animators[key]; + base_ani.animators[uuid_map[key]] = base_ani.animators[key]; + delete base_ani.animators[key]; } } } From 75ba67c84c677567a570de9ad27fc391a560aec7 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Wed, 13 Dec 2023 14:45:30 +0100 Subject: [PATCH 05/14] Per texture UV workflow improvements --- js/texturing/texture_generator.js | 12 ++++++++---- js/texturing/textures.js | 6 ++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/js/texturing/texture_generator.js b/js/texturing/texture_generator.js index b1690ec42..f1101dcb0 100644 --- a/js/texturing/texture_generator.js +++ b/js/texturing/texture_generator.js @@ -161,6 +161,10 @@ const TextureGenerator = { let texture = cb(canvas.toDataURL()); texture.uv_width = width; texture.uv_height = height; + if (Format.per_texture_uv_size) { + Project.texture_width = width; + Project.texture_height = height; + } return texture; }, //constructors @@ -1719,10 +1723,10 @@ const TextureGenerator = { changeUVResolution(width, height, texture) { let factor_x = width / Project.getUVWidth(texture); let factor_y = height / Project.getUVHeight(texture); - if (!Format.per_texture_uv_size) { - Project.texture_width = width; - Project.texture_height = height; - } + + Project.texture_width = width; + Project.texture_height = height; + if (texture) { texture.uv_width = width; texture.uv_height = height; diff --git a/js/texturing/textures.js b/js/texturing/textures.js index 5b24f7d44..5c2ef7510 100644 --- a/js/texturing/textures.js +++ b/js/texturing/textures.js @@ -1279,8 +1279,10 @@ class Texture { } else if (Format.single_texture || Texture.all.length == 1 || Format.per_texture_uv_size) { if (Format.per_texture_uv_size) { - scope.uv_width = Project.texture_width * (formResult.size[0] / old_width); - scope.uv_height = Project.texture_height * (formResult.size[1] / old_height); + scope.uv_width = scope.uv_width * (formResult.size[0] / old_width); + scope.uv_height = scope.uv_height * (formResult.size[1] / old_height); + Project.texture_width = scope.uv_width; + Project.texture_height = scope.uv_height; } else { Undo.current_save.uv_mode = { box_uv: Project.box_uv, From 09ba9fd5475128d52d097b7ccb43f6be03dbaba4 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Wed, 13 Dec 2023 18:11:26 +0100 Subject: [PATCH 06/14] Add new bat skin model Support variants for skin models --- js/interface/interface.js | 3 + js/interface/themes.js | 2 +- js/io/formats/skin.js | 289 +++++++++++++++++++++++++++----------- 3 files changed, 211 insertions(+), 83 deletions(-) diff --git a/js/interface/interface.js b/js/interface/interface.js index 3f3484a19..174f5d99d 100644 --- a/js/interface/interface.js +++ b/js/interface/interface.js @@ -746,6 +746,9 @@ Interface.CustomElements.SelectInput = function(id, data) { let value = data.value || data.default || Object.keys(options)[0]; let select = Interface.createElement('bb-select', {id, class: 'half', value: value}, getNameFor(options[value])); function setKey(key, options) { + if (!options) { + options = typeof data.options == 'function' ? data.options() : data.options; + } value = key; select.setAttribute('value', key); select.textContent = getNameFor(options[key]); diff --git a/js/interface/themes.js b/js/interface/themes.js index 4e4f6dadd..4b8e3186d 100644 --- a/js/interface/themes.js +++ b/js/interface/themes.js @@ -336,7 +336,7 @@ const CustomTheme = { CustomTheme.data.colors[scope_key] = last_color; field.spectrum('set', last_color); }, - beforeShow(a, b) { + beforeShow() { last_color = CustomTheme.data.colors[scope_key]; field.spectrum('set', last_color); } diff --git a/js/io/formats/skin.js b/js/io/formats/skin.js index aefc66f48..3b0662f64 100644 --- a/js/io/formats/skin.js +++ b/js/io/formats/skin.js @@ -160,7 +160,7 @@ codec.export = null; codec.rebuild = function(model_id, pose) { let [preset_id, variant] = model_id.split('.'); let preset = skin_presets[preset_id]; - let model = JSON.parse(preset.model || (variant == 'java' ? preset.model_java : preset.model_bedrock)); + let model = JSON.parse(preset.model || (variant == 'java' ? preset.model_java : preset.model_bedrock) || preset[variant]); codec.parse(model, undefined, undefined, pose && pose !== 'none'); if (pose && pose !== 'none') { setTimeout(() => { @@ -245,6 +245,7 @@ function generateTemplate(width = 64, height = 64, cubes, name = 'name', eyes, l } const model_options = {}; +let selected_model = ''; const skin_dialog = new Dialog({ title: tl('dialog.skin.title'), id: 'skin', @@ -254,7 +255,7 @@ const skin_dialog = new Dialog({ type: 'select', options: model_options }, - variant: { + game_edition: { label: 'dialog.skin.variant', type: 'inline_select', default: 'java_edition', @@ -263,7 +264,17 @@ const skin_dialog = new Dialog({ bedrock_edition: 'Bedrock Edition', }, condition(form) { - return !skin_presets[form.model].model; + return skin_presets[form.model].model_bedrock; + } + }, + variant: { + label: 'dialog.skin.variant', + type: 'select', + options() { + return (selected_model && skin_presets[selected_model].variants) || {} + }, + condition(form) { + return skin_presets[form.model].variants; } }, resolution: {label: 'dialog.create_texture.resolution', type: 'select', value: 16, options: { @@ -287,7 +298,19 @@ const skin_dialog = new Dialog({ pose: {type: 'checkbox', label: 'dialog.skin.pose', value: true, condition: form => (!!skin_presets[form.model].pose)}, layer_template: {type: 'checkbox', label: 'dialog.skin.layer_template', value: false} }, - draggable: true, + onFormChange(result) { + selected_model = result.model; + let variants = skin_presets[result.model].variants; + if (variants) { + for (let key in variants) { + if (!result.variant || !variants[result.variant]) { + result.variant = key; + skin_dialog.setFormValues({variant: key}, false); + break; + } + } + } + }, onConfirm(result) { if (result.model == 'flat_texture') { if (result.texture) { @@ -299,9 +322,22 @@ const skin_dialog = new Dialog({ } else { if (newProject(format)) { let preset = skin_presets[result.model]; - let model = JSON.parse(preset.model || (result.variant == 'java_edition' ? preset.model_java : preset.model_bedrock)); + let raw_model; + if (preset.model_bedrock) { + raw_model = result.game_edition == 'java_edition' ? preset.model_java : preset.model_bedrock; + } else if (preset.variants) { + raw_model = preset.variants[result.variant].model; + } else { + raw_model = preset.model; + } + let model = JSON.parse(raw_model); codec.parse(model, result.resolution/16, result.texture, result.pose, result.layer_template); - Project.skin_model = result.model + '.' + (result.variant == 'java_edition' ? 'java' : 'bedrock'); + Project.skin_model = result.model; + if (preset.model_bedrock) { + Project.skin_model += '.' + (result.game_edition == 'java_edition' ? 'java' : 'bedrock'); + } else if (preset.variants) { + Project.skin_model += '.' + result.variant; + } } } }, @@ -1192,84 +1228,173 @@ skin_presets.banner = { skin_presets.bat = { display_name: 'Bat', pose: true, - model: `{ - "name": "bat", - "texturewidth": 64, - "textureheight": 64, - "bones": [ - { - "name": "Head", - "pivot": [0, 24, 0], - "cubes": [ - {"name": "Head", "origin": [-3, 21, -3], "size": [6, 6, 6], "uv": [0, 0]} - ] - }, - { - "name": "rightEar", - "parent": "Head", - "pivot": [0, 24, 0], - "cubes": [ - {"name": "rightEar", "origin": [-4, 26, -2], "size": [3, 4, 1], "uv": [24, 0]} - ] - }, - { - "name": "leftEar", - "parent": "Head", - "pivot": [0, 24, 0], - "mirror": true, - "cubes": [ - {"name": "leftEar", "origin": [1, 26, -2], "size": [3, 4, 1], "uv": [24, 0]} - ] - }, - { - "name": "body", - "pivot": [0, 24, 0], - "rotation": [30, 0, 0], - "cubes": [ - {"name": "body", "origin": [-3, 8, -3], "size": [6, 12, 6], "uv": [0, 16]}, - {"name": "body", "origin": [-5, -8, 0], "size": [10, 16, 1], "uv": [0, 34]} - ] - }, - { - "name": "rightWing", - "parent": "body", - "pivot": [0, 24, 0], - "pose": [0, -10, 0], - "cubes": [ - {"name": "rightWing", "origin": [-12, 7, 1.5], "size": [10, 16, 1], "uv": [42, 0]} - ] - }, - { - "name": "rightWingTip", - "parent": "rightWing", - "pivot": [-12, 23, 1.5], - "pose": [0, -15, 0], - "cubes": [ - {"name": "rightWingTip", "origin": [-20, 10, 1.5], "size": [8, 12, 1], "uv": [24, 16]} - ] - }, - { - "name": "leftWing", - "parent": "body", - "pivot": [0, 24, 0], - "pose": [0, 10, 0], - "mirror": true, - "cubes": [ - {"name": "leftWing", "origin": [2, 7, 1.5], "size": [10, 16, 1], "uv": [42, 0]} + variants: { + new: { + name: 'New', + model: `{ + "name": "bat_v2", + "texturewidth": 32, + "textureheight": 32, + "eyes": [ + [1, 10, 2, 1], + [5, 10, 2, 1] + ], + "bones": [ + { + "name": "Head", + "pivot": [0, 7, 0], + "cubes": [ + {"origin": [-2, 7, -1], "size": [4, 3, 2], "uv": [0, 7]} + ] + }, + { + "name": "rightEar", + "parent": "Head", + "pivot": [-1.5, 9, 0], + "cubes": [ + {"origin": [-4, 8, 0], "size": [3, 5, 0], "uv": [1, 15]} + ] + }, + { + "name": "leftEar", + "parent": "Head", + "pivot": [1.1, 10, 0], + "cubes": [ + {"origin": [1, 8, 0], "size": [3, 5, 0], "uv": [8, 15]} + ] + }, + { + "name": "body", + "pivot": [0, 7, 0], + "cubes": [ + {"origin": [-1.5, 2, -1], "size": [3, 5, 2], "uv": [0, 0]} + ] + }, + { + "name": "feet", + "parent": "body", + "pivot": [0, 2, 0], + "cubes": [ + {"origin": [-1.5, 0, 0], "size": [3, 2, 0], "uv": [16, 16]} + ] + }, + { + "name": "rightWing", + "parent": "body", + "pivot": [-1.5, 7, 0], + "cubes": [ + {"origin": [-3.5, 2, 0], "size": [2, 7, 0], "uv": [12, 0]} + ] + }, + { + "name": "rightWingTip", + "parent": "rightWing", + "pivot": [-3.5, 7, 0], + "cubes": [ + {"origin": [-9.5, 1, 0], "size": [6, 8, 0], "uv": [16, 0]} + ] + }, + { + "name": "leftWing", + "parent": "body", + "pivot": [1.5, 7, 0], + "cubes": [ + {"origin": [1.5, 2, 0], "size": [2, 7, 0], "uv": [12, 7]} + ] + }, + { + "name": "leftWingTip", + "parent": "leftWing", + "pivot": [3.5, 7, 0], + "cubes": [ + {"origin": [3.5, 1, 0], "size": [6, 8, 0], "uv": [16, 8]} + ] + } ] - }, - { - "name": "leftWingTip", - "parent": "leftWing", - "pivot": [12, 23, 1.5], - "pose": [0, 15, 0], - "mirror": true, - "cubes": [ - {"name": "leftWingTip", "origin": [12, 10, 1.5], "size": [8, 12, 1], "uv": [24, 16]} + }` + }, + old: { + name: 'Old', + model: `{ + "name": "bat", + "texturewidth": 64, + "textureheight": 64, + "bones": [ + { + "name": "Head", + "pivot": [0, 24, 0], + "cubes": [ + {"name": "Head", "origin": [-3, 21, -3], "size": [6, 6, 6], "uv": [0, 0]} + ] + }, + { + "name": "rightEar", + "parent": "Head", + "pivot": [0, 24, 0], + "cubes": [ + {"name": "rightEar", "origin": [-4, 26, -2], "size": [3, 4, 1], "uv": [24, 0]} + ] + }, + { + "name": "leftEar", + "parent": "Head", + "pivot": [0, 24, 0], + "mirror": true, + "cubes": [ + {"name": "leftEar", "origin": [1, 26, -2], "size": [3, 4, 1], "uv": [24, 0]} + ] + }, + { + "name": "body", + "pivot": [0, 24, 0], + "rotation": [30, 0, 0], + "cubes": [ + {"name": "body", "origin": [-3, 8, -3], "size": [6, 12, 6], "uv": [0, 16]}, + {"name": "body", "origin": [-5, -8, 0], "size": [10, 16, 1], "uv": [0, 34]} + ] + }, + { + "name": "rightWing", + "parent": "body", + "pivot": [0, 24, 0], + "pose": [0, -10, 0], + "cubes": [ + {"name": "rightWing", "origin": [-12, 7, 1.5], "size": [10, 16, 1], "uv": [42, 0]} + ] + }, + { + "name": "rightWingTip", + "parent": "rightWing", + "pivot": [-12, 23, 1.5], + "pose": [0, -15, 0], + "cubes": [ + {"name": "rightWingTip", "origin": [-20, 10, 1.5], "size": [8, 12, 1], "uv": [24, 16]} + ] + }, + { + "name": "leftWing", + "parent": "body", + "pivot": [0, 24, 0], + "pose": [0, 10, 0], + "mirror": true, + "cubes": [ + {"name": "leftWing", "origin": [2, 7, 1.5], "size": [10, 16, 1], "uv": [42, 0]} + ] + }, + { + "name": "leftWingTip", + "parent": "leftWing", + "pivot": [12, 23, 1.5], + "pose": [0, 15, 0], + "mirror": true, + "cubes": [ + {"name": "leftWingTip", "origin": [12, 10, 1.5], "size": [8, 12, 1], "uv": [24, 16]} + ] + } ] - } - ] - }` + }` + }, + } }; skin_presets.bed = { display_name: 'Bed', From 7f64f7abc75edbad11cbf13cdbd7acc2115cd401 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Thu, 14 Dec 2023 00:01:53 +0100 Subject: [PATCH 07/14] Fix #2124 Converting cube to mesh changes rotation --- js/modeling/mesh_editing.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/modeling/mesh_editing.js b/js/modeling/mesh_editing.js index 4afe3fdff..495d7986a 100644 --- a/js/modeling/mesh_editing.js +++ b/js/modeling/mesh_editing.js @@ -943,6 +943,10 @@ BARS.defineActions(function() { rotation: cube.rotation, vertices: [] }) + let rotation_euler = new THREE.Euler(0, 0, 0, 'ZYX').fromArray(cube.rotation.map(Math.degToRad)); + rotation_euler.reorder('XYZ'); + mesh.rotation.V3_set(rotation_euler.toArray().map(r => Math.roundTo(Math.radToDeg(r), 4))); + var adjustedFrom = cube.from.slice(); var adjustedTo = cube.to.slice(); adjustFromAndToForInflateAndStretch(adjustedFrom, adjustedTo, cube); From 00fa0d645c19c59dfcf078330cd2569a1fbde34a Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Thu, 14 Dec 2023 23:23:39 +0100 Subject: [PATCH 08/14] Fix reference appearing behind 2D editor by default --- js/preview/reference_images.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/preview/reference_images.js b/js/preview/reference_images.js index 894cdf0a5..e56c6f2c0 100644 --- a/js/preview/reference_images.js +++ b/js/preview/reference_images.js @@ -820,6 +820,9 @@ const ReferenceImageMode = { }) files.forEach(file => { let ref = new ReferenceImage({source: file.content, name: file.name}); + if (Format.image_editor) { + ref.layer = 'viewport'; + } if (save_mode == 'project') { ref.addAsReference(true); } else { From 49637d2b12f7b42942f600a7b20abb17f8db581a Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Thu, 14 Dec 2023 23:30:37 +0100 Subject: [PATCH 09/14] Fix #2149 Cannot click on input box in dialog file picker --- js/interface/dialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/interface/dialog.js b/js/interface/dialog.js index 94c307db3..70bf7155b 100644 --- a/js/interface/dialog.js +++ b/js/interface/dialog.js @@ -295,7 +295,7 @@ function buildForm(dialog) { case 'save': if (data.type == 'folder' && !isApp) break; - let input = $(``); + let input = $(``); input[0].value = settings.streamer_mode.value ? `[${tl('generic.redacted')}]` : data.value || ''; let input_wrapper = $('
'); input_wrapper.append(input); From 9c9d45a47d3ae85079467f239d43b412192e3c1a Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Fri, 15 Dec 2023 21:12:27 +0100 Subject: [PATCH 10/14] Copy pasting tweaks Fix issue with duplicating texture selection --- js/interface/keyboard.js | 10 ++++++++++ js/texturing/painter.js | 10 ++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/js/interface/keyboard.js b/js/interface/keyboard.js index 5bd308042..b60c01282 100644 --- a/js/interface/keyboard.js +++ b/js/interface/keyboard.js @@ -847,6 +847,16 @@ addEventListeners(document, 'keydown mousedown', function(e) { ReferenceImageMode.deactivate(); used = true; } + } else if (Prop.active_panel == 'uv' && Modes.paint && Texture.selected && Texture.selected.selection.is_custom) { + if (Keybinds.extra.cancel.keybind.isTriggered(e)) { + SharedActions.run('unselect_all', e); + used = true; + } + } else if (Modes.paint && TextureLayer.selected && TextureLayer.selected.in_limbo) { + if (Keybinds.extra.confirm.keybind.isTriggered(e)) { + TextureLayer.selected.resolveLimbo(false); + used = true; + } } if (ActionControl.open) { used = ActionControl.handleKeys(e) || used diff --git a/js/texturing/painter.js b/js/texturing/painter.js index ce22179eb..0c9a2100b 100644 --- a/js/texturing/painter.js +++ b/js/texturing/painter.js @@ -2034,6 +2034,7 @@ SharedActions.add('paste', { Undo.initEdit({textures: [texture], bitmap: true}); if (!texture.layers_enabled) { + texture.flags.add('temporary_layers'); texture.activateLayers(false); } let offset = Clipbench.image ? [Math.clamp(Clipbench.image.x, 0, texture.width), Math.clamp(Clipbench.image.y, 0, texture.height)] : undefined; @@ -2091,17 +2092,19 @@ SharedActions.add('duplicate', { copy_canvas.width = rect.width; copy_canvas.height = rect.height; - selection.maskCanvas(copy_ctx, offset); - copy_ctx.drawImage(canvas, -rect.start_x, -rect.start_y); + selection.maskCanvas(copy_ctx, [rect.start_x, rect.start_y]); + copy_ctx.drawImage(canvas, -rect.start_x + offset[0], -rect.start_y + offset[1]); canvas = copy_canvas; + offset = [rect.start_x, rect.start_y]; } Undo.initEdit({textures: [texture], bitmap: true}); if (!texture.layers_enabled) { + texture.flags.add('temporary_layers'); texture.activateLayers(false); } - let new_layer = new TextureLayer({name: layer.name + ' - copy', offset}, texture); + let new_layer = new TextureLayer({name: layer ? (layer.name + ' - copy') : 'selection', offset}, texture); let image_data = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height); new_layer.setSize(canvas.width, canvas.height); new_layer.ctx.putImageData(image_data, 0, 0); @@ -2113,7 +2116,6 @@ SharedActions.add('duplicate', { Undo.finishEdit('Duplicate texture selection'); updateInterfacePanels(); BARS.updateConditions(); - } }) SharedActions.add('delete', { From acd048022bd4f4195e06e2f02fde8aaa9606e3a7 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Fri, 15 Dec 2023 21:16:27 +0100 Subject: [PATCH 11/14] Fix layer resize handles not working with UV overlay enabled --- css/panels.css | 2 +- js/texturing/uv.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/css/panels.css b/css/panels.css index 9cf88b664..a7a014be4 100644 --- a/css/panels.css +++ b/css/panels.css @@ -1940,7 +1940,7 @@ span.controller_state_section_info { --color-uv-background: transparent; --uv-line-width: 1px; } - #uv_frame.overlay_mode * { + #uv_frame.overlay_mode .uv_face { pointer-events: none; } diff --git a/js/texturing/uv.js b/js/texturing/uv.js index b673d4718..1e334101f 100644 --- a/js/texturing/uv.js +++ b/js/texturing/uv.js @@ -3762,7 +3762,7 @@ Interface.definePanels(function() {