mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-02-17 16:20:13 +08:00
Pop up menu when pasting ambiguous content
Fix #1061 Creating a line between quad does not separate face Fix #1084 Auto UV does not work on cubes Deleting lines no longer deletes selected vertices Add fox as mesh thumbnail on update screen
This commit is contained in:
parent
2a85c12152
commit
5da83af608
Binary file not shown.
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 39 KiB |
@ -46,6 +46,57 @@ const Clipbench = {
|
||||
return Clipbench.types.outliner;
|
||||
}
|
||||
},
|
||||
async getPasteType() {
|
||||
let p = Prop.active_panel;
|
||||
if (getFocusedTextInput()) {
|
||||
return Clipbench.types.text;
|
||||
}
|
||||
if (Painter.selection.canvas && Toolbox.selected.id == 'copy_paste_tool') {
|
||||
return Clipbench.types.texture_selection;
|
||||
}
|
||||
if (display_mode) {
|
||||
return Clipbench.types.display_slot
|
||||
}
|
||||
if (Animator.open && Timeline.animators.length && ['keyframe', 'timeline', 'preview'].includes(p)) {
|
||||
return Clipbench.types.keyframe
|
||||
}
|
||||
if (Modes.edit && p == 'preview') {
|
||||
let options = [];
|
||||
if (Clipbench.elements.length || Clipbench.group) {
|
||||
options.push(Clipbench.types.outliner);
|
||||
}
|
||||
if (Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length && Clipbench.vertices) {
|
||||
options.push(Clipbench.types.mesh_selection);
|
||||
}
|
||||
if (UVEditor.getMappableElements().length && Clipbench.faces && Object.keys(Clipbench.faces).length) {
|
||||
options.push(Clipbench.types.face);
|
||||
}
|
||||
if (options.length > 1) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
new Menu(options.map(option => {
|
||||
return {
|
||||
id: option,
|
||||
name: tl(`menu.paste.${option}`),
|
||||
click() {
|
||||
resolve(option);
|
||||
}
|
||||
}
|
||||
})).show('mouse');
|
||||
})
|
||||
} else {
|
||||
return options[0]
|
||||
}
|
||||
}
|
||||
if (p == 'uv' && Modes.edit) {
|
||||
return Clipbench.types.face;
|
||||
}
|
||||
if (p == 'textures' && Texture.selected) {
|
||||
return Clipbench.types.texture;
|
||||
}
|
||||
if (p == 'outliner' && Modes.edit) {
|
||||
return Clipbench.types.outliner;
|
||||
}
|
||||
},
|
||||
copy(event, cut) {
|
||||
let copy_type = Clipbench.getCopyType(1);
|
||||
Clipbench.last_copied = copy_type;
|
||||
@ -68,6 +119,7 @@ const Clipbench = {
|
||||
UVEditor.copy(event);
|
||||
break;
|
||||
case 'mesh_selection':
|
||||
UVEditor.copy(event);
|
||||
Clipbench.setMeshSelection(Mesh.selected[0], event);
|
||||
break;
|
||||
case 'texture':
|
||||
@ -90,8 +142,8 @@ const Clipbench = {
|
||||
}
|
||||
}
|
||||
},
|
||||
paste(event) {
|
||||
switch (Clipbench.getCopyType(2)) {
|
||||
async paste(event) {
|
||||
switch (await Clipbench.getPasteType()) {
|
||||
case 'text':
|
||||
Clipbench.setText(window.getSelection()+'');
|
||||
break;
|
||||
|
@ -1521,7 +1521,6 @@ const BARS = {
|
||||
new Action('delete', {
|
||||
icon: 'delete',
|
||||
category: 'edit',
|
||||
//condition: () => (Modes.edit && (selected.length || Group.selected)),
|
||||
keybind: new Keybind({key: 46}),
|
||||
click: function () {
|
||||
if (Prop.active_panel == 'textures' && Texture.selected) {
|
||||
@ -1536,11 +1535,11 @@ const BARS = {
|
||||
|
||||
Mesh.selected.forEach(mesh => {
|
||||
let has_selected_faces = false;
|
||||
let selected_vertices = mesh.getSelectedVertices();
|
||||
for (let key in mesh.faces) {
|
||||
has_selected_faces = has_selected_faces || mesh.faces[key].isSelected();
|
||||
}
|
||||
if (BarItems.selection_mode.value == 'face' && has_selected_faces) {
|
||||
let selected_vertices = Project.selected_vertices[mesh.uuid];
|
||||
for (let key in mesh.faces) {
|
||||
let face = mesh.faces[key];
|
||||
if (face.isSelected()) {
|
||||
@ -1557,6 +1556,29 @@ const BARS = {
|
||||
delete mesh.vertices[vertex_key];
|
||||
}
|
||||
})
|
||||
} else if (BarItems.selection_mode.value == 'line' && selected_vertices.length) {
|
||||
for (let key in mesh.faces) {
|
||||
let face = mesh.faces[key];
|
||||
let sorted_vertices = face.getSortedVertices();
|
||||
let selected_corners = sorted_vertices.filter(vkey => selected_vertices.includes(vkey));
|
||||
if (selected_corners.length >= 2) {
|
||||
let index_diff = (sorted_vertices.indexOf(selected_corners[0]) - sorted_vertices.indexOf(selected_corners[1])) % sorted_vertices.length;
|
||||
if ((sorted_vertices.length < 4 || Math.abs(index_diff) !== 2)) {
|
||||
delete mesh.faces[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
selected_vertices.forEach(vertex_key => {
|
||||
let used = false;
|
||||
for (let key in mesh.faces) {
|
||||
let face = mesh.faces[key];
|
||||
if (face.vertices.includes(vertex_key)) used = true;
|
||||
}
|
||||
if (!used) {
|
||||
delete mesh.vertices[vertex_key];
|
||||
}
|
||||
})
|
||||
|
||||
} else {
|
||||
let selected_vertices = Project.selected_vertices[mesh.uuid];
|
||||
selected_vertices.forEach(vertex_key => {
|
||||
|
@ -295,6 +295,10 @@ class Menu {
|
||||
var offset_left = (document.body.clientWidth-el_width)/2
|
||||
var offset_top = (document.body.clientHeight-el_height)/2
|
||||
|
||||
} else if (position == 'mouse') {
|
||||
var offset_left = mouse_pos.x;
|
||||
var offset_top = mouse_pos.y;
|
||||
|
||||
} else {
|
||||
if (!position && scope.type === 'bar_menu') {
|
||||
position = scope.label
|
||||
|
@ -1250,53 +1250,83 @@ BARS.defineActions(function() {
|
||||
let selected_vertices = mesh.getSelectedVertices();
|
||||
if (selected_vertices.length >= 2 && selected_vertices.length <= 4) {
|
||||
let reference_face;
|
||||
let reference_face_strength = 0;
|
||||
for (let key in mesh.faces) {
|
||||
let face = mesh.faces[key];
|
||||
if (!reference_face && face.vertices.find(vkey => selected_vertices.includes(vkey))) {
|
||||
let match_strength = face.vertices.filter(vkey => selected_vertices.includes(vkey)).length;
|
||||
if (match_strength > reference_face_strength) {
|
||||
reference_face = face;
|
||||
reference_face_strength = match_strength;
|
||||
}
|
||||
if (face.isSelected()) {
|
||||
delete mesh.faces[key];
|
||||
}
|
||||
}
|
||||
let new_face = new MeshFace(mesh, {
|
||||
vertices: selected_vertices,
|
||||
texture: reference_face.texture,
|
||||
} );
|
||||
mesh.addFaces(new_face);
|
||||
if (selected_vertices.length == 2 && reference_face.vertices.length == 4 && reference_face.vertices.filter(vkey => selected_vertices.includes(vkey)).length == 2) {
|
||||
|
||||
// Correct direction
|
||||
if (selected_vertices.length > 2) {
|
||||
// find face with shared line to compare
|
||||
let fixed_via_face;
|
||||
for (let key in mesh.faces) {
|
||||
let face = mesh.faces[key];
|
||||
let common = face.vertices.filter(vertex_key => selected_vertices.includes(vertex_key))
|
||||
if (common.length == 2) {
|
||||
let old_vertices = face.getSortedVertices();
|
||||
let new_vertices = new_face.getSortedVertices();
|
||||
let index_diff = old_vertices.indexOf(common[0]) - old_vertices.indexOf(common[1]);
|
||||
let new_index_diff = new_vertices.indexOf(common[0]) - new_vertices.indexOf(common[1]);
|
||||
if (index_diff == 1 - face.vertices.length) index_diff = 1;
|
||||
if (new_index_diff == 1 - new_face.vertices.length) new_index_diff = 1;
|
||||
let sorted_vertices = reference_face.getSortedVertices();
|
||||
let unselected_vertices = sorted_vertices.filter(vkey => !selected_vertices.includes(vkey));
|
||||
|
||||
if (Math.abs(index_diff) == 1 && Math.abs(new_index_diff) == 1) {
|
||||
if (index_diff == new_index_diff) {
|
||||
new_face.invert();
|
||||
}
|
||||
fixed_via_face = true;
|
||||
break;
|
||||
}
|
||||
let side_index_diff = Math.abs(sorted_vertices.indexOf(selected_vertices[0]) - sorted_vertices.indexOf(selected_vertices[1]));
|
||||
if (side_index_diff != 1) {
|
||||
|
||||
let new_face = new MeshFace(mesh, reference_face);
|
||||
|
||||
new_face.vertices.remove(unselected_vertices[0]);
|
||||
delete new_face.uv[unselected_vertices[0]];
|
||||
|
||||
reference_face.vertices.remove(unselected_vertices[1]);
|
||||
delete reference_face.uv[unselected_vertices[1]];
|
||||
|
||||
mesh.addFaces(new_face);
|
||||
|
||||
if (Reusable.vec1.fromArray(reference_face.getNormal(true)).angleTo(Reusable.vec2.fromArray(new_face)) > Math.PI/2) {
|
||||
console.log(Reusable.vec1.fromArray(reference_face.getNormal(true)).angleTo(Reusable.vec2.fromArray(new_face)))
|
||||
new_face.invert();
|
||||
}
|
||||
}
|
||||
// If no face available, orient based on camera orientation
|
||||
if (!fixed_via_face) {
|
||||
let normal = new THREE.Vector3().fromArray(new_face.getNormal());
|
||||
normal.applyQuaternion(mesh.mesh.getWorldQuaternion(new THREE.Quaternion()))
|
||||
let cam_direction = Preview.selected.camera.getWorldDirection(new THREE.Vector3());
|
||||
let angle = normal.angleTo(cam_direction);
|
||||
if (angle < Math.PI/2) {
|
||||
new_face.invert();
|
||||
|
||||
} else {
|
||||
|
||||
let new_face = new MeshFace(mesh, {
|
||||
vertices: selected_vertices,
|
||||
texture: reference_face.texture,
|
||||
} );
|
||||
mesh.addFaces(new_face);
|
||||
|
||||
// Correct direction
|
||||
if (selected_vertices.length > 2) {
|
||||
// find face with shared line to compare
|
||||
let fixed_via_face;
|
||||
for (let key in mesh.faces) {
|
||||
let face = mesh.faces[key];
|
||||
let common = face.vertices.filter(vertex_key => selected_vertices.includes(vertex_key))
|
||||
if (common.length == 2) {
|
||||
let old_vertices = face.getSortedVertices();
|
||||
let new_vertices = new_face.getSortedVertices();
|
||||
let index_diff = old_vertices.indexOf(common[0]) - old_vertices.indexOf(common[1]);
|
||||
let new_index_diff = new_vertices.indexOf(common[0]) - new_vertices.indexOf(common[1]);
|
||||
if (index_diff == 1 - face.vertices.length) index_diff = 1;
|
||||
if (new_index_diff == 1 - new_face.vertices.length) new_index_diff = 1;
|
||||
|
||||
if (Math.abs(index_diff) == 1 && Math.abs(new_index_diff) == 1) {
|
||||
if (index_diff == new_index_diff) {
|
||||
new_face.invert();
|
||||
}
|
||||
fixed_via_face = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If no face available, orient based on camera orientation
|
||||
if (!fixed_via_face) {
|
||||
let normal = new THREE.Vector3().fromArray(new_face.getNormal());
|
||||
normal.applyQuaternion(mesh.mesh.getWorldQuaternion(new THREE.Quaternion()))
|
||||
let cam_direction = Preview.selected.camera.getWorldDirection(new THREE.Vector3());
|
||||
let angle = normal.angleTo(cam_direction);
|
||||
if (angle < Math.PI/2) {
|
||||
new_face.invert();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -734,8 +734,8 @@ const UVEditor = {
|
||||
if (face.rotation % 180) {
|
||||
[left2, top2] = [top2, left2];
|
||||
}
|
||||
left2 *= this.getResolution(0, face) / Project.texture_width;
|
||||
top2 *= this.getResolution(1, face) / Project.texture_height;
|
||||
left2 *= UVEditor.getResolution(0, face) / Project.texture_width;
|
||||
top2 *= UVEditor.getResolution(1, face) / Project.texture_height;
|
||||
face.uv_size = [left2, top2];
|
||||
if (mirror_x) [face.uv[0], face.uv[2]] = [face.uv[2], face.uv[0]];
|
||||
if (mirror_y) [face.uv[1], face.uv[3]] = [face.uv[3], face.uv[1]];
|
||||
|
@ -1386,6 +1386,10 @@
|
||||
|
||||
"menu.mobile_keyboard.disable_all": "Disable All",
|
||||
|
||||
"menu.paste.face": "UV Face",
|
||||
"menu.paste.mesh_selection": "Mesh Selection",
|
||||
"menu.paste.outliner": "Elements",
|
||||
|
||||
"web.download_app": "Download App",
|
||||
|
||||
"interface.streamer_mode_on": "Streamer Mode Enabled",
|
||||
|
Loading…
Reference in New Issue
Block a user