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:
JannisX11 2021-10-08 12:28:41 +03:00
parent 2a85c12152
commit 5da83af608
7 changed files with 153 additions and 41 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -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;

View File

@ -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 => {

View File

@ -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

View File

@ -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();
}
}
}
}

View File

@ -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]];

View File

@ -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",