From 71e796b71d03c2b8c9dfd7b81383c34e2089ba55 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Sat, 18 May 2024 16:09:28 +0200 Subject: [PATCH 01/24] Fix #2347 modded entity export issue in older formats --- js/io/formats/modded_entity.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/io/formats/modded_entity.js b/js/io/formats/modded_entity.js index 88e7c0acd..2719f8b25 100644 --- a/js/io/formats/modded_entity.js +++ b/js/io/formats/modded_entity.js @@ -494,7 +494,7 @@ var codec = new Codec('modded_entity', { let group_snippets = []; for (var group of all_groups) { if ((group instanceof Group === false && !group.is_catch_bone) || !group.export) continue; - if (group.is_rotation_subgroup) continue; + if (group.is_rotation_subgroup && Templates.get('model_part')) continue; //if (usesLayerDef && group.parent instanceof Group) continue; let snippet = Templates.get('field') .replace(R('bone'), group.name) From 42c77fa4737de43686e8925ca0ac54e5d241c5c9 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Sat, 18 May 2024 23:35:07 +0200 Subject: [PATCH 02/24] Improve molang keyframe recognition --- js/animations/keyframe.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/animations/keyframe.js b/js/animations/keyframe.js index 107fb536c..cdccf0366 100644 --- a/js/animations/keyframe.js +++ b/js/animations/keyframe.js @@ -603,8 +603,8 @@ function updateKeyframeSelection() { } let has_expressions = false; if (kf.transform) { - has_expressions = !!kf.data_points.find(point => { - return !isStringNumber(point.x) || !isStringNumber(point.y) ||! isStringNumber(point.z); + has_expressions = !!kf.data_points.find((point, i) => { + return kf.getArray(i).find(v => typeof v == 'string'); }) } if (has_expressions != kf.has_expressions) { From 30abedaed422987c31c39f12fd291ccfc51b720b Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Sat, 18 May 2024 23:38:20 +0200 Subject: [PATCH 03/24] Fix icons displaying cut-off Fixes #2346 Fix start screen section headline sizes --- content/news.json | 2 +- css/dialogs.css | 2 ++ css/start_screen.css | 6 ++++-- js/interface/settings.js | 2 +- js/interface/start_screen.js | 5 +++-- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/content/news.json b/content/news.json index 40c76b6a9..cc157731c 100644 --- a/content/news.json +++ b/content/news.json @@ -5,7 +5,7 @@ "layout": "vertical", "insert_after": "splash_screen", "text": [ - {"text": "Welcome to Blockbench 4.10", "type": "h2"}, + {"text": "Welcome to Blockbench 4.10", "type": "h3"}, {"text": "The Knife Tool Update!", "type": "h1"}, {"text": "Check out the [full changelog](https://github.com/JannisX11/blockbench/releases/tag/v4.10.0)!"} ], diff --git a/css/dialogs.css b/css/dialogs.css index 0d76fb989..ad9d0b660 100644 --- a/css/dialogs.css +++ b/css/dialogs.css @@ -1890,10 +1890,12 @@ li.validator_dialog_problem.validator_warning > i { color: var(--color-warning); margin: 3px 4px; + flex-shrink: 0; } li.validator_dialog_problem.validator_error > i { color: var(--color-error); margin: 3px 4px; + flex-shrink: 0; } li.validator_dialog_problem span { flex-grow: 1; diff --git a/css/start_screen.css b/css/start_screen.css index b2b8b24fc..af6a4a645 100644 --- a/css/start_screen.css +++ b/css/start_screen.css @@ -207,8 +207,10 @@ } #start_screen div.graphic.graphic_icon i { font-size: 40px; - width: 12px; - margin-top: 6px; + width: 42px; + max-width: unset; + margin-top: 4px; + margin-right: -20px; } #start_screen .start_screen_graphic_description { bottom: 15px; diff --git a/js/interface/settings.js b/js/interface/settings.js index 5ce051c2a..98f0b12a0 100644 --- a/js/interface/settings.js +++ b/js/interface/settings.js @@ -733,7 +733,7 @@ function updateStreamerModeNotification() { color: 'var(--color-stream)', text_color: 'var(--color-light)', text: [ - {type: 'h1', text: tl('interface.streamer_mode_on'), click() { + {type: 'h2', text: tl('interface.streamer_mode_on'), click() { Settings.openDialog({search_term: tl('settings.streamer_mode')}) }} ] diff --git a/js/interface/start_screen.js b/js/interface/start_screen.js index 64a234f35..4ac120043 100644 --- a/js/interface/start_screen.js +++ b/js/interface/start_screen.js @@ -79,8 +79,9 @@ function addStartScreenSection(id, data) { var content = line.text ? pureMarked(tl(line.text)) : ''; switch (line.type) { case 'h1': var tag = 'h1'; break; - case 'h2': var tag = 'h3'; break; - case 'h3': var tag = 'h4'; break; + case 'h2': var tag = 'h2'; break; + case 'h3': var tag = 'h3'; break; + case 'h4': var tag = 'h4'; break; case 'list': var tag = 'ul class="list_style"'; line.list.forEach(string => { From 11d4e09bf7d96acc380feb23260fea68e5e9b089 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Sun, 19 May 2024 01:38:55 +0200 Subject: [PATCH 04/24] Fix tiny mesh corner pixels cannot be painted at 32x uv size --- js/outliner/mesh.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/js/outliner/mesh.js b/js/outliner/mesh.js index 11975006a..e94169ed8 100644 --- a/js/outliner/mesh.js +++ b/js/outliner/mesh.js @@ -111,19 +111,29 @@ class MeshFace extends Face { let matrix_x = x-start_offset[0]; let matrix_y = y-start_offset[1]; - let inside = ( pointInsidePolygon(x+0.00001, y+0.00001) - || pointInsidePolygon(x+0.99999, y+0.00001) - || pointInsidePolygon(x+0.00001, y+0.99999) - || pointInsidePolygon(x+0.99999, y+0.99999)); + let inside = ( pointInsidePolygon(x+0.000001, y+0.000001) + || pointInsidePolygon(x+0.999999, y+0.000001) + || pointInsidePolygon(x+0.000001, y+0.999999) + || pointInsidePolygon(x+0.999999, y+0.999999)); if (!inside) { let i = 0; - let px_rect = [[x, y], [x+0.99999, y+0.99999]] + let px_rect = [[x, y], [x+0.999999, y+0.999999]] for (let vkey of sorted_vertices) { - let vkey_b = sorted_vertices[i+1] || sorted_vertices[0] - if (pointInRectangle(face.uv[vkey], ...px_rect)) { + if (!face.uv[vkey]) continue; + let uv_a = [ + face.uv[vkey][0] * factor_x, + face.uv[vkey][1] * factor_y, + ]; + if (pointInRectangle(uv_a, ...px_rect)) { inside = true; break; } - if (lineIntersectsReactangle(face.uv[vkey], face.uv[vkey_b], ...px_rect)) { + let vkey_b = sorted_vertices[i+1] || sorted_vertices[0]; + if (!face.uv[vkey_b]) continue; + let uv_b = [ + face.uv[vkey_b][0] * factor_x, + face.uv[vkey_b][1] * factor_y, + ]; + if (lineIntersectsReactangle(uv_a, uv_b, ...px_rect)) { inside = true; break; } i++; From b7d66fbffc8cd11c531d0267844bd50f19185481 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Mon, 20 May 2024 21:21:35 +0200 Subject: [PATCH 05/24] Fix empty line with colon in scale dialog --- js/interface/dialog.js | 2 +- js/modeling/scale.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/interface/dialog.js b/js/interface/dialog.js index e7b1a1f51..1fe0abbdf 100644 --- a/js/interface/dialog.js +++ b/js/interface/dialog.js @@ -12,7 +12,7 @@ function buildForm(dialog) { let bar = $(`
`) let label; if (typeof data.label == 'string') { - label = Interface.createElement('label', {class: 'name_space_left', for: form_id}, tl(data.label)+(data.nocolon?'':':')) + label = Interface.createElement('label', {class: 'name_space_left', for: form_id}, tl(data.label)+((data.nocolon || !data.label)?'':':')) bar.append(label); if (!data.full_width && data.condition !== false) { dialog.max_label_width = Math.max(getStringWidth(label.textContent), dialog.max_label_width) diff --git a/js/modeling/scale.js b/js/modeling/scale.js index 1cd63aa1b..acd92f5e6 100644 --- a/js/modeling/scale.js +++ b/js/modeling/scale.js @@ -22,7 +22,7 @@ const ModelScaler = { pivot_options: {label: ' ', nocolon: true, type: 'buttons', buttons: ['dialog.scale.element_pivot', 'dialog.scale.selection_center'], click(index) { ModelScaler.setPivot(['pivot', 'selection'][index]); }}, - scale: {label: '', type: 'range', min: 0, max: 4, step: 0.01, value: 1, full_width: true, editable_range_label: true}, + scale: {type: 'range', min: 0, max: 4, step: 0.01, value: 1, full_width: true, editable_range_label: true}, overflow_info: { condition: () => ModelScaler.overflow, type: 'info', From 47448aa360eca124b5198c54fd5e1c556c9616da Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Mon, 20 May 2024 21:51:59 +0200 Subject: [PATCH 06/24] Fix issue with load-order of auto-backups --- css/start_screen.css | 1 + js/boot_loader.js | 2 ++ js/interface/start_screen.js | 24 ------------------------ js/misc.js | 27 +++++++++++++++++++++++++-- 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/css/start_screen.css b/css/start_screen.css index af6a4a645..961754b5c 100644 --- a/css/start_screen.css +++ b/css/start_screen.css @@ -183,6 +183,7 @@ div.start_screen_right > ul { max-height: 470px; padding-right: 5px; + overflow-x: hidden; overflow-y: auto; grid-template-columns: repeat(auto-fit, minmax(170px ,1fr)); grid-gap: 5px; diff --git a/js/boot_loader.js b/js/boot_loader.js index 048d9ee60..45729aff1 100644 --- a/js/boot_loader.js +++ b/js/boot_loader.js @@ -132,6 +132,8 @@ onVueSetup.funcs.forEach((func) => { } }) +AutoBackup.initialize(); + if (isApp) { initializeDesktopApp(); } else { diff --git a/js/interface/start_screen.js b/js/interface/start_screen.js index 4ac120043..e4c23e15e 100644 --- a/js/interface/start_screen.js +++ b/js/interface/start_screen.js @@ -528,30 +528,6 @@ onVueSetup(async function() { if (settings.streamer_mode.value) { updateStreamerModeNotification() } - - //Backup Model - let has_backups = await AutoBackup.hasBackups(); - if (has_backups && (!isApp || !currentwindow.webContents.second_instance)) { - - let section = addStartScreenSection({ - color: 'var(--color-back)', - graphic: {type: 'icon', icon: 'fa-archive'}, - insert_before: 'start_files', - text: [ - {type: 'h2', text: tl('message.recover_backup.title')}, - {text: tl('message.recover_backup.message')}, - {type: 'button', text: tl('message.recover_backup.recover'), click: (e) => { - AutoBackup.recoverAllBackups().then(() => { - section.delete(); - }); - }}, - {type: 'button', text: tl('dialog.discard'), click: (e) => { - AutoBackup.removeAllBackups(); - section.delete(); - }} - ] - }) - } }); diff --git a/js/misc.js b/js/misc.js index 8f65ee615..902d2b297 100644 --- a/js/misc.js +++ b/js/misc.js @@ -257,8 +257,32 @@ const AutoBackup = { console.log(`Upgraded ${Object.keys(parsed_backup_models).length} project back-ups to indexedDB`); } } - request.onsuccess = function() { + request.onsuccess = async function() { AutoBackup.db = request.result; + + // Start Screen Message + let has_backups = await AutoBackup.hasBackups(); + if (has_backups && (!isApp || !currentwindow.webContents.second_instance)) { + + let section = addStartScreenSection({ + color: 'var(--color-back)', + graphic: {type: 'icon', icon: 'fa-archive'}, + insert_before: 'start_files', + text: [ + {type: 'h2', text: tl('message.recover_backup.title')}, + {text: tl('message.recover_backup.message')}, + {type: 'button', text: tl('message.recover_backup.recover'), click: (e) => { + AutoBackup.recoverAllBackups().then(() => { + section.delete(); + }); + }}, + {type: 'button', text: tl('dialog.discard'), click: (e) => { + AutoBackup.removeAllBackups(); + section.delete(); + }} + ] + }) + } } }, async backupOpenProject() { @@ -347,7 +371,6 @@ const AutoBackup = { }); } } -AutoBackup.initialize(); setInterval(function() { From d3d1869a9f83173fe3afe02edc4c975c262ebc5e Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Thu, 23 May 2024 22:00:40 +0200 Subject: [PATCH 07/24] Clear GPU cache after every restart on Linux --- js/desktop.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/desktop.js b/js/desktop.js index df938393f..86abe6510 100644 --- a/js/desktop.js +++ b/js/desktop.js @@ -71,7 +71,7 @@ function initializeDesktopApp() { } else { $('#windows_window_menu').show() } - if (Blockbench.platform == 'linux' && (Blockbench.hasFlag('after_update') || Blockbench.hasFlag('after_patch_update'))) { + if (Blockbench.platform == 'linux') { // Clear GPU cache: https://github.com/JannisX11/blockbench/issues/1964 let gpu_cache_path = PathModule.join(app.getPath('userData'), 'GPUCache'); try { From 1ddb3ce1e7d1b46a9a2d71e9b067a657bbbcdf99 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Thu, 23 May 2024 23:13:24 +0200 Subject: [PATCH 08/24] Fix start screen style issues Update electron --- css/start_screen.css | 1 + js/desktop.js | 2 +- js/misc.js | 2 +- package-lock.json | 12 ++++++------ package.json | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/css/start_screen.css b/css/start_screen.css index 961754b5c..5988b1391 100644 --- a/css/start_screen.css +++ b/css/start_screen.css @@ -21,6 +21,7 @@ } #start_screen button { margin-right: 4px; + margin-top: 4px; } #start_screen .recent_project { margin: 2px 0; diff --git a/js/desktop.js b/js/desktop.js index 86abe6510..159ec5e7f 100644 --- a/js/desktop.js +++ b/js/desktop.js @@ -732,7 +732,7 @@ ipcRenderer.on('update-available', (event, arg) => { color: 'var(--color-back)', graphic: {type: 'icon', icon: 'update'}, text: [ - {type: 'h2', text: tl('message.update_notification.title')}, + {type: 'h3', text: tl('message.update_notification.title')}, {text: tl('message.update_notification.message')}, {type: 'button', text: tl('generic.enable'), click: (e) => { settings.automatic_updates.set(true); diff --git a/js/misc.js b/js/misc.js index 902d2b297..c28402fe1 100644 --- a/js/misc.js +++ b/js/misc.js @@ -269,7 +269,7 @@ const AutoBackup = { graphic: {type: 'icon', icon: 'fa-archive'}, insert_before: 'start_files', text: [ - {type: 'h2', text: tl('message.recover_backup.title')}, + {type: 'h3', text: tl('message.recover_backup.title')}, {text: tl('message.recover_backup.message')}, {type: 'button', text: tl('message.recover_backup.recover'), click: (e) => { AutoBackup.recoverAllBackups().then(() => { diff --git a/package-lock.json b/package-lock.json index 85c274b36..66a5b4c08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "Blockbench", - "version": "4.10.0-beta.1", + "version": "4.10.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Blockbench", - "version": "4.10.0-beta.1", + "version": "4.10.1", "license": "GPL-3.0-or-later", "dependencies": { "@electron/remote": "^2.1.2", @@ -17,7 +17,7 @@ "devDependencies": { "@electron/notarize": "^2.3.0", "blockbench-types": "^4.6.1", - "electron": "^30.0.0", + "electron": "^30.0.6", "electron-builder": "^24.13.3", "webpack": "^5.74.0", "webpack-cli": "^4.5.0", @@ -4303,9 +4303,9 @@ } }, "node_modules/electron": { - "version": "30.0.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-30.0.0.tgz", - "integrity": "sha512-GRwKphq/TUhSlb44OwSckXKl50f5OR/pm9MvF3rBLyqcxwfu7L11xejrZ0hDea1eKyCkzGd4B+cIqaQiDguPEA==", + "version": "30.0.6", + "resolved": "https://registry.npmjs.org/electron/-/electron-30.0.6.tgz", + "integrity": "sha512-PkhEPFdpYcTzjAO3gMHZ+map7g2+xCrMDedo/L1i0ir2BRXvAB93IkTJX497U6Srb/09r2cFt+k20VPNVCdw3Q==", "hasInstallScript": true, "dependencies": { "@electron/get": "^2.0.0", diff --git a/package.json b/package.json index 7f01822f5..3b1fa9164 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "devDependencies": { "@electron/notarize": "^2.3.0", "blockbench-types": "^4.6.1", - "electron": "^30.0.0", + "electron": "^30.0.6", "electron-builder": "^24.13.3", "webpack": "^5.74.0", "webpack-cli": "^4.5.0", From d9b5f077a0f3718cd2ecde10cbbdf6e78cc33113 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Fri, 24 May 2024 19:10:02 +0200 Subject: [PATCH 09/24] Fix pixel perfect option in brush presets not being saved Fix icons being squashed together in some UIs --- css/setup.css | 1 + js/texturing/painter.js | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/css/setup.css b/css/setup.css index 2d65847a1..7b2eb97fa 100644 --- a/css/setup.css +++ b/css/setup.css @@ -299,6 +299,7 @@ -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; overflow: hidden; + flex-shrink: 0; } i.fa_big { font-size: 18px; diff --git a/js/texturing/painter.js b/js/texturing/painter.js index 41f5c4808..e73d75384 100644 --- a/js/texturing/painter.js +++ b/js/texturing/painter.js @@ -1679,7 +1679,11 @@ const Painter = { } else { preset.color = null; } - + if (form.pixel_perfect) { + preset.pixel_perfect = true; + } else { + preset.pixel_perfect = false; + } if (form.shape !== 'unset') { preset.shape = form.shape; } else { From 2687a297a655368a89409ee1a117b479bfbfe995 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Sat, 25 May 2024 12:50:24 +0200 Subject: [PATCH 10/24] Fix #2355 Screenshot model crops out bottom and rightmost pixel row --- lib/CanvasFrame.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/CanvasFrame.js b/lib/CanvasFrame.js index af81262e5..4baab0f75 100644 --- a/lib/CanvasFrame.js +++ b/lib/CanvasFrame.js @@ -101,8 +101,8 @@ class CanvasFrame { } } - var trimHeight = bound.bottom - bound.top, - trimWidth = bound.right - bound.left, + var trimHeight = bound.bottom - bound.top + 1, + trimWidth = bound.right - bound.left + 1, trimmed = this.ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight); copy.canvas.width = trimWidth; From 77ed5489508fba82a06dd7d8036b2c4ca3c59074 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Sun, 26 May 2024 20:59:08 +0200 Subject: [PATCH 11/24] Fix selecting edges not unselecting faces --- js/preview/preview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/preview/preview.js b/js/preview/preview.js index 703879cb1..c71ec5bfe 100644 --- a/js/preview/preview.js +++ b/js/preview/preview.js @@ -947,7 +947,7 @@ class Preview { let vertices = data.element.getSelectedVertices(true); let edges = data.element.getSelectedEdges(true); - let faces = data.element.getSelectedEdges(true); + let faces = data.element.getSelectedFaces(true); if (event.ctrlOrCmd || Pressing.overrides.ctrl || event.shiftKey || Pressing.overrides.shift) { let index = edges.findIndex(edge => sameMeshEdge(edge, data.vertices)) From 337cd24b861bd5d52746ffada3327f7e468d8fd9 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Sun, 26 May 2024 23:13:12 +0200 Subject: [PATCH 12/24] Fix #2340 Texture field in project files is false for unset textures --- js/outliner/outliner.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/js/outliner/outliner.js b/js/outliner/outliner.js index 8bd773ec3..619f2a8ef 100644 --- a/js/outliner/outliner.js +++ b/js/outliner/outliner.js @@ -1899,8 +1899,6 @@ class Face { let tex = this.getTexture() if (tex === null) { copy.texture = null; - } else if (!this.texture) { - copy.texture = false; } else if (tex instanceof Texture && project) { copy.texture = Texture.all.indexOf(tex) } else if (tex instanceof Texture) { From 0d2b0be646eaa5093858eb0d8e64bc4e86761390 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Tue, 28 May 2024 19:20:16 +0200 Subject: [PATCH 13/24] Fix pasted texture selection appearing on top layer Fix displayed face texture when cube face still has texture assigned in group texture formats --- js/outliner/outliner.js | 2 +- js/texturing/painter.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js/outliner/outliner.js b/js/outliner/outliner.js index 619f2a8ef..112e8f59c 100644 --- a/js/outliner/outliner.js +++ b/js/outliner/outliner.js @@ -1874,7 +1874,7 @@ class Face { if (Format.per_group_texture && this.element.parent instanceof Group && this.element.parent.texture) { return Texture.all.findInArray('uuid', this.element.parent.texture); } - if (this.texture !== null && (Format.single_texture || (Format.single_texture_default && !this.texture))) { + if (this.texture !== null && (Format.single_texture || (Format.single_texture_default && (Format.per_group_texture || !this.texture)))) { return Texture.getDefault(); } if (typeof this.texture === 'string') { diff --git a/js/texturing/painter.js b/js/texturing/painter.js index e73d75384..470140721 100644 --- a/js/texturing/painter.js +++ b/js/texturing/painter.js @@ -2055,8 +2055,8 @@ SharedActions.add('paste', { layer.setSize(frame.width, frame.height); layer.ctx.putImageData(image_data, 0, 0); if (!offset) layer.center(); - texture.layers.push(layer); - layer.select(); + + layer.addForEditing(); layer.setLimbo(); texture.updateChangesAfterEdit(); From 6e5516c9120fcfe234cbf9016f00c1c6d28108a6 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Tue, 28 May 2024 19:26:58 +0200 Subject: [PATCH 14/24] Fix 3D brush cursor including flipbook texture UV offset --- js/preview/preview.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/preview/preview.js b/js/preview/preview.js index c71ec5bfe..0198ff66c 100644 --- a/js/preview/preview.js +++ b/js/preview/preview.js @@ -1077,6 +1077,9 @@ class Preview { x = Math.round(x + offset) - offset; y = Math.round(y + offset) - offset; } + if (texture.currentFrame) { + y -= texture.display_height * texture.currentFrame; + } // Position let brush_coord = face.UVToLocal([x * uv_factor_x, y * uv_factor_y]); let brush_coord_difference_x = face.UVToLocal([(x+1) * uv_factor_x, y * uv_factor_y]); From 31cd90df3cc93a251038cb0337a9635641fa024f Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Tue, 28 May 2024 19:48:26 +0200 Subject: [PATCH 15/24] Fix pinned auto UV not working on bedrock blocks --- js/outliner/cube.js | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/js/outliner/cube.js b/js/outliner/cube.js index 397800393..34f283f0a 100644 --- a/js/outliner/cube.js +++ b/js/outliner/cube.js @@ -684,55 +684,56 @@ class Cube extends OutlinerElement { if (scope.autouv === 2) { //Relative UV var all_faces = ['north', 'south', 'west', 'east', 'up', 'down'] + let offset = Format.centered_grid ? 8 : 0; all_faces.forEach(function(side) { var uv = scope.faces[side].uv.slice() switch (side) { case 'north': uv = [ - pw - scope.to[0], + pw - (scope.to[0]+offset), ph - scope.to[1], - pw - scope.from[0], + pw - (scope.from[0]+offset), ph - scope.from[1], ]; break; case 'south': uv = [ - scope.from[0], + (scope.from[0]+offset), ph - scope.to[1], - scope.to[0], + (scope.to[0]+offset), ph - scope.from[1], ]; break; case 'west': uv = [ - scope.from[2], + (scope.from[2]+offset), ph - scope.to[1], - scope.to[2], + (scope.to[2]+offset), ph - scope.from[1], ]; break; case 'east': uv = [ - pw - scope.to[2], + pw - (scope.to[2]+offset), ph - scope.to[1], - pw - scope.from[2], + pw - (scope.from[2]+offset), ph - scope.from[1], ]; break; case 'up': uv = [ - scope.from[0], - scope.from[2], - scope.to[0], - scope.to[2], + (scope.from[0]+offset), + (scope.from[2]+offset), + (scope.to[0]+offset), + (scope.to[2]+offset), ]; break; case 'down': uv = [ - scope.from[0], - ph - scope.to[2], - scope.to[0], - ph - scope.from[2], + (scope.from[0]+offset), + ph - (scope.to[2]+offset), + (scope.to[0]+offset), + ph - (scope.from[2]+offset), ]; break; } From 50f41366f546e61e0ce55a8bb84d47cba5dacdcc Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Tue, 28 May 2024 20:18:45 +0200 Subject: [PATCH 16/24] Fix #2320 Flip Animation creates wrong keyframe at timestamp 0 --- js/animations/keyframe.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/js/animations/keyframe.js b/js/animations/keyframe.js index 107fb536c..23391f30d 100644 --- a/js/animations/keyframe.js +++ b/js/animations/keyframe.js @@ -1200,6 +1200,15 @@ BARS.defineActions(function() { time = (time + Animation.selected.length/2) % (Animation.selected.length + 0.001); } time = Timeline.snapTime(time); + if (Math.epsilon(time, Animation.selected.length, 0.004) && formResult.offset && !occupied_times.includes(0)) { + // Copy keyframe to start + occupied_times.push(0); + let new_kf = opposite_animator.createKeyframe(old_kf, 0, channel, false, false) + if (new_kf) { + new_kf.flip(0); + new_keyframes.push(new_kf); + } + } if (occupied_times.includes(time)) return; occupied_times.push(time); let new_kf = opposite_animator.createKeyframe(old_kf, time, channel, false, false) From 3de79634bbcc467a6f675224dc9889027d8ed3d6 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Tue, 28 May 2024 20:46:38 +0200 Subject: [PATCH 17/24] Fix #2345 Discontinuous keyframe post values can't be edited in mixed group --- js/animations/keyframe.js | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/js/animations/keyframe.js b/js/animations/keyframe.js index 23391f30d..6cadc8dde 100644 --- a/js/animations/keyframe.js +++ b/js/animations/keyframe.js @@ -589,6 +589,7 @@ class Keyframe { function updateKeyframeValue(axis, value, data_point) { Timeline.selected.forEach(function(kf) { if (axis == 'uniform' && kf.channel == 'scale') kf.uniform = true; + if (data_point && !kf.data_points[data_point]) return; kf.set(axis, value, data_point); }) if (!['effect', 'locator', 'script'].includes(axis)) { @@ -1463,6 +1464,17 @@ Interface.definePanels(function() { } } return channel; + }, + firstKeyframe() { + let data_point_length = 0; + let keyframe; + for (let kf of this.keyframes) { + if (kf.data_points.length > data_point_length) { + keyframe = kf; + data_point_length = kf.data_points.length; + } + } + return keyframe; } }, template: ` @@ -1475,7 +1487,7 @@ Interface.definePanels(function() {
@@ -1483,19 +1495,19 @@ Interface.definePanels(function() {
-
    +
      -
      +
      -
      - +
      +
      clear
      -