mirror of
https://github.com/JannisX11/blockbench.git
synced 2024-11-21 01:13:37 +08:00
Add loop edge selection
Merge "Add Mesh" and "Add Primitive Close #1010 Remember "Add Primitive" dialog settings Close #1038 Write popup-setting description below input instead on a button Close #1035 by adding tool to filter menu
This commit is contained in:
parent
c7a9cc943d
commit
bcad73d4e4
@ -576,7 +576,6 @@ const MenuBar = {
|
||||
'_',
|
||||
'add_cube',
|
||||
'add_mesh',
|
||||
'add_primitive',
|
||||
'add_group',
|
||||
'add_locator',
|
||||
'add_null_object',
|
||||
@ -636,6 +635,7 @@ const MenuBar = {
|
||||
})
|
||||
|
||||
new BarMenu('filter', [
|
||||
'convert_to_mesh',
|
||||
'remove_blank_faces',
|
||||
])
|
||||
|
||||
|
@ -136,7 +136,11 @@ class Setting {
|
||||
label: this.name,
|
||||
description: this.description,
|
||||
type: this.type
|
||||
}
|
||||
},
|
||||
description: this.description ? {
|
||||
type: 'info',
|
||||
text: this.description
|
||||
} : undefined
|
||||
},
|
||||
onConfirm({input}) {
|
||||
setting.set(input);
|
||||
|
@ -231,6 +231,7 @@ class ModelProject {
|
||||
unselect() {
|
||||
if (isApp) updateRecentProjectThumbnail();
|
||||
this.thumbnail = Preview.selected.canvas.toDataURL();
|
||||
Interface.tab_bar.last_opened_project = this.uuid;
|
||||
|
||||
this.selected = false;
|
||||
Painter.current = {};
|
||||
@ -416,6 +417,7 @@ onVueSetup(() => {
|
||||
drag_position_index: null,
|
||||
close_tab_label: tl('projects.close_tab'),
|
||||
search_tabs_label: tl('generic.search'),
|
||||
last_opened_project: '',
|
||||
new_tab: {
|
||||
name: tl('projects.new_tab'),
|
||||
saved: true,
|
||||
@ -424,7 +426,14 @@ onVueSetup(() => {
|
||||
visible: true,
|
||||
is_new_tab: true,
|
||||
close: () => {
|
||||
if (ModelProject.all.length) {
|
||||
Interface.tab_bar.new_tab.visible = false;
|
||||
let project = Project.all.find(project => project.uuid == Interface.tab_bar.last_opened_project) ||
|
||||
Project.all.last();
|
||||
if (project) project.select();
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
},
|
||||
select() {
|
||||
if (Project) {
|
||||
@ -448,6 +457,7 @@ onVueSetup(() => {
|
||||
},
|
||||
methods: {
|
||||
openNewTab() {
|
||||
this.last_opened_project = Project.uuid;
|
||||
this.new_tab.visible = true;
|
||||
this.new_tab.select();
|
||||
setStartScreen(true);
|
||||
|
@ -649,48 +649,278 @@ new NodePreviewController(Mesh, {
|
||||
})
|
||||
|
||||
BARS.defineActions(function() {
|
||||
new Action('add_mesh', {
|
||||
icon: 'fa-gem',
|
||||
category: 'edit',
|
||||
keybind: new Keybind({key: 'n', ctrl: true}),
|
||||
condition: () => (Modes.edit && Format.meshes),
|
||||
click: function () {
|
||||
|
||||
Undo.initEdit({outliner: true, elements: [], selection: true});
|
||||
var base_mesh = new Mesh({
|
||||
autouv: (settings.autouv.value ? 1 : 0)
|
||||
}).init()
|
||||
let add_mesh_dialog = new Dialog({
|
||||
id: 'add_primitive',
|
||||
title: 'action.add_mesh',
|
||||
form: {
|
||||
shape: {label: 'dialog.add_primitive.shape', type: 'select', options: {
|
||||
cube: 'dialog.add_primitive.shape.cube',
|
||||
pyramid: 'dialog.add_primitive.shape.pyramid',
|
||||
circle: 'dialog.add_primitive.shape.circle',
|
||||
cylinder: 'dialog.add_primitive.shape.cylinder',
|
||||
tube: 'dialog.add_primitive.shape.tube',
|
||||
cone: 'dialog.add_primitive.shape.cone',
|
||||
sphere: 'dialog.add_primitive.shape.sphere',
|
||||
torus: 'dialog.add_primitive.shape.torus',
|
||||
}},
|
||||
diameter: {label: 'dialog.add_primitive.diameter', type: 'number', value: 16},
|
||||
height: {label: 'dialog.add_primitive.height', type: 'number', value: 8, condition: ({shape}) => ['cylinder', 'cone', 'cube', 'pyramid', 'tube'].includes(shape)},
|
||||
sides: {label: 'dialog.add_primitive.sides', type: 'number', value: 16, condition: ({shape}) => ['cylinder', 'cone', 'circle', 'torus', 'sphere', 'tube'].includes(shape)},
|
||||
minor_diameter: {label: 'dialog.add_primitive.minor_diameter', type: 'number', value: 4, condition: ({shape}) => ['torus', 'tube'].includes(shape)},
|
||||
minor_sides: {label: 'dialog.add_primitive.minor_sides', type: 'number', value: 8, condition: ({shape}) => ['torus'].includes(shape)},
|
||||
},
|
||||
onConfirm(result) {
|
||||
let elements = [];
|
||||
Undo.initEdit({elements});
|
||||
let mesh = new Mesh({
|
||||
name: result.shape,
|
||||
vertices: {}
|
||||
});
|
||||
var group = getCurrentGroup();
|
||||
base_mesh.addTo(group)
|
||||
mesh.addTo(group)
|
||||
|
||||
if (result.shape == 'circle') {
|
||||
let vertex_keys = mesh.addVertices([0, 0, 0]);
|
||||
let [m] = vertex_keys;
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let x = Math.sin((i / result.sides) * Math.PI * 2) * result.diameter/2;
|
||||
let z = Math.cos((i / result.sides) * Math.PI * 2) * result.diameter/2;
|
||||
vertex_keys.push(...mesh.addVertices([x, 0, z]));
|
||||
}
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let [a, b] = vertex_keys.slice(i+2, i+2 + 2);
|
||||
if (!a) {
|
||||
b = vertex_keys[2];
|
||||
a = vertex_keys[1];
|
||||
} else if (!b) {
|
||||
b = vertex_keys[1];
|
||||
}
|
||||
mesh.addFaces(new MeshFace( mesh, {vertices: [a, b, m]} ));
|
||||
}
|
||||
}
|
||||
if (result.shape == 'cone') {
|
||||
let vertex_keys = mesh.addVertices([0, 0, 0], [0, result.height, 0]);
|
||||
let [m0, m1] = vertex_keys;
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let x = Math.sin((i / result.sides) * Math.PI * 2) * result.diameter/2;
|
||||
let z = Math.cos((i / result.sides) * Math.PI * 2) * result.diameter/2;
|
||||
vertex_keys.push(...mesh.addVertices([x, 0, z]));
|
||||
}
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let [a, b] = vertex_keys.slice(i+2, i+2 + 2);
|
||||
if (!b) {
|
||||
b = vertex_keys[2];
|
||||
}
|
||||
mesh.addFaces(
|
||||
new MeshFace( mesh, {vertices: [b, a, m0]} ),
|
||||
new MeshFace( mesh, {vertices: [a, b, m1]} )
|
||||
);
|
||||
}
|
||||
}
|
||||
if (result.shape == 'cylinder') {
|
||||
let vertex_keys = mesh.addVertices([0, 0, 0], [0, result.height, 0]);
|
||||
let [m0, m1] = vertex_keys;
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let x = Math.sin((i / result.sides) * Math.PI * 2) * result.diameter/2;
|
||||
let z = Math.cos((i / result.sides) * Math.PI * 2) * result.diameter/2;
|
||||
vertex_keys.push(...mesh.addVertices([x, 0, z], [x, result.height, z]));
|
||||
}
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let [a, b, c, d] = vertex_keys.slice(2*i+2, 2*i+2 + 4);
|
||||
if (!c) {
|
||||
c = vertex_keys[2];
|
||||
d = vertex_keys[3];
|
||||
}
|
||||
mesh.addFaces(
|
||||
new MeshFace( mesh, {vertices: [c, a, m0]}),
|
||||
new MeshFace( mesh, {vertices: [a, c, d, b]} ),
|
||||
new MeshFace( mesh, {vertices: [b, d, m1]} )
|
||||
);
|
||||
}
|
||||
}
|
||||
if (result.shape == 'tube') {
|
||||
let vertex_keys = [];
|
||||
|
||||
let outer_r = result.diameter/2;
|
||||
let inner_r = outer_r - result.minor_diameter;
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let x = Math.sin((i / result.sides) * Math.PI * 2);
|
||||
let z = Math.cos((i / result.sides) * Math.PI * 2);
|
||||
vertex_keys.push(...mesh.addVertices(
|
||||
[x * outer_r, 0, z * outer_r],
|
||||
[x * outer_r, result.height, z * outer_r],
|
||||
[x * inner_r, 0, z * inner_r],
|
||||
[x * inner_r, result.height, z * inner_r],
|
||||
));
|
||||
}
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let [a1, b1, c1, d1, a2, b2, c2, d2] = vertex_keys.slice(4*i, 4*i + 8);
|
||||
if (!a2) {
|
||||
a2 = vertex_keys[0];
|
||||
b2 = vertex_keys[1];
|
||||
c2 = vertex_keys[2];
|
||||
d2 = vertex_keys[3];
|
||||
}
|
||||
if (a1 && b1 && c1 && d1 && a2 && b2 && c2 && d2) {
|
||||
mesh.addFaces(
|
||||
new MeshFace( mesh, {vertices: [a1, a2, b2, b1]} ),
|
||||
new MeshFace( mesh, {vertices: [d1, d2, c2, c1]} ),
|
||||
new MeshFace( mesh, {vertices: [c1, c2, a2, a1]} ),
|
||||
new MeshFace( mesh, {vertices: [b1, b2, d2, d1]} ),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.shape == 'torus') {
|
||||
let rings = [];
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let circle_x = Math.sin((i / result.sides) * Math.PI * 2);
|
||||
let circle_z = Math.cos((i / result.sides) * Math.PI * 2);
|
||||
|
||||
let vertices = [];
|
||||
for (let j = 0; j < result.minor_sides; j++) {
|
||||
let slice_x = Math.sin((j / result.minor_sides) * Math.PI * 2) * result.minor_diameter/2;
|
||||
let x = circle_x * (result.diameter/2 + slice_x)
|
||||
let y = Math.cos((j / result.minor_sides) * Math.PI * 2) * result.minor_diameter/2;
|
||||
let z = circle_z * (result.diameter/2 + slice_x)
|
||||
vertices.push(...mesh.addVertices([x, y, z]));
|
||||
}
|
||||
rings.push(vertices);
|
||||
|
||||
}
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let this_ring = rings[i];
|
||||
let next_ring = rings[i+1] || rings[0];
|
||||
for (let j = 0; j < result.minor_sides; j++) {
|
||||
mesh.addFaces(new MeshFace( mesh, {vertices: [
|
||||
this_ring[j+1] || this_ring[0],
|
||||
next_ring[j+1] || next_ring[0],
|
||||
this_ring[j],
|
||||
next_ring[j],
|
||||
]} ));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.shape == 'sphere') {
|
||||
let rings = [];
|
||||
let sides = Math.round(result.sides/2)*2;
|
||||
let [bottom] = mesh.addVertices([0, -result.diameter/2, 0]);
|
||||
let [top] = mesh.addVertices([0, result.diameter/2, 0]);
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let circle_x = Math.sin((i / result.sides) * Math.PI * 2);
|
||||
let circle_z = Math.cos((i / result.sides) * Math.PI * 2);
|
||||
|
||||
let vertices = [];
|
||||
for (let j = 1; j < (sides/2); j++) {
|
||||
|
||||
let slice_x = Math.sin((j / sides) * Math.PI * 2) * result.diameter/2;
|
||||
let x = circle_x * slice_x
|
||||
let y = Math.cos((j / sides) * Math.PI * 2) * result.diameter/2;
|
||||
let z = circle_z * slice_x
|
||||
vertices.push(...mesh.addVertices([x, y, z]));
|
||||
}
|
||||
rings.push(vertices);
|
||||
|
||||
}
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let this_ring = rings[i];
|
||||
let next_ring = rings[i+1] || rings[0];
|
||||
for (let j = 0; j < (sides/2); j++) {
|
||||
if (j == 0) {
|
||||
mesh.addFaces(new MeshFace( mesh, {vertices: [
|
||||
this_ring[j],
|
||||
next_ring[j],
|
||||
top
|
||||
]} ));
|
||||
} else if (!this_ring[j]) {
|
||||
mesh.addFaces(new MeshFace( mesh, {vertices: [
|
||||
next_ring[j-1],
|
||||
this_ring[j-1],
|
||||
bottom
|
||||
]} ));
|
||||
} else {
|
||||
mesh.addFaces(new MeshFace( mesh, {vertices: [
|
||||
this_ring[j],
|
||||
next_ring[j],
|
||||
this_ring[j-1],
|
||||
next_ring[j-1],
|
||||
]} ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.shape == 'cube') {
|
||||
let r = result.diameter/2;
|
||||
let h = result.height;
|
||||
mesh.addVertices([r, h, r], [r, h, -r], [r, 0, r], [r, 0, -r], [-r, h, r], [-r, h, -r], [-r, 0, r], [-r, 0, -r]);
|
||||
let vertex_keys = Object.keys(mesh.vertices);
|
||||
mesh.addFaces(
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[0], vertex_keys[2], vertex_keys[1], vertex_keys[3]]} ), // East
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[4], vertex_keys[5], vertex_keys[6], vertex_keys[7]]} ), // West
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[0], vertex_keys[1], vertex_keys[4], vertex_keys[5]]} ), // Up
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[2], vertex_keys[6], vertex_keys[3], vertex_keys[7]]} ), // Down
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[0], vertex_keys[4], vertex_keys[2], vertex_keys[6]]} ), // South
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[1], vertex_keys[3], vertex_keys[5], vertex_keys[7]]} ), // North
|
||||
);
|
||||
}
|
||||
if (result.shape == 'pyramid') {
|
||||
let r = result.diameter/2;
|
||||
let h = result.height;
|
||||
mesh.addVertices([0, h, 0], [r, 0, r], [r, 0, -r], [-r, 0, r], [-r, 0, -r]);
|
||||
let vertex_keys = Object.keys(mesh.vertices);
|
||||
mesh.addFaces(
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[1], vertex_keys[3], vertex_keys[2], vertex_keys[4]]} ), // Down
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[1], vertex_keys[2], vertex_keys[0]]} ), // east
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[3], vertex_keys[1], vertex_keys[0]]} ), // south
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[2], vertex_keys[4], vertex_keys[0]]} ), // north
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[4], vertex_keys[3], vertex_keys[0]]} ), // west
|
||||
);
|
||||
}
|
||||
|
||||
if (Texture.all.length && Format.single_texture) {
|
||||
for (var face in base_mesh.faces) {
|
||||
base_mesh.faces[face].texture = Texture.getDefault().uuid
|
||||
for (var face in mesh.faces) {
|
||||
mesh.faces[face].texture = Texture.getDefault().uuid
|
||||
}
|
||||
UVEditor.loadData()
|
||||
}
|
||||
if (Format.bone_rig) {
|
||||
if (group) {
|
||||
var pos1 = group.origin.slice()
|
||||
base_mesh.extend({
|
||||
from:[ pos1[0]-0, pos1[1]-0, pos1[2]-0 ],
|
||||
to:[ pos1[0]+1, pos1[1]+1, pos1[2]+1 ],
|
||||
mesh.extend({
|
||||
origin: pos1.slice()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
elements.push(mesh);
|
||||
mesh.init()
|
||||
if (Group.selected) Group.selected.unselect()
|
||||
base_mesh.select()
|
||||
Undo.finishEdit('Add mesh', {outliner: true, elements: selected, selection: true});
|
||||
Blockbench.dispatchEvent( 'add_mesh', {object: base_mesh} )
|
||||
mesh.select()
|
||||
Undo.finishEdit('Add primitive');
|
||||
Blockbench.dispatchEvent( 'add_mesh', {object: mesh} )
|
||||
|
||||
Vue.nextTick(function() {
|
||||
if (settings.create_rename.value) {
|
||||
base_mesh.rename()
|
||||
mesh.rename()
|
||||
}
|
||||
})
|
||||
return base_mesh
|
||||
}
|
||||
})
|
||||
|
||||
new Action('add_mesh', {
|
||||
icon: 'fa-gem',
|
||||
category: 'edit',
|
||||
keybind: new Keybind({key: 'n', ctrl: true}),
|
||||
condition: () => (Modes.edit && Format.meshes),
|
||||
click: function () {
|
||||
add_mesh_dialog.show();
|
||||
}
|
||||
})
|
||||
new BarSelect('selection_mode', {
|
||||
@ -1226,250 +1456,4 @@ BARS.defineActions(function() {
|
||||
})
|
||||
}
|
||||
})
|
||||
new Action('add_primitive', {
|
||||
icon: 'fa-shapes',
|
||||
category: 'edit',
|
||||
condition: () => (Modes.edit && Format.meshes),
|
||||
click() {
|
||||
|
||||
let dialog = new Dialog({
|
||||
id: 'add_primitive',
|
||||
title: 'action.add_primitive',
|
||||
form: {
|
||||
shape: {label: 'dialog.add_primitive.shape', type: 'select', options: {
|
||||
circle: 'dialog.add_primitive.shape.circle',
|
||||
cylinder: 'dialog.add_primitive.shape.cylinder',
|
||||
tube: 'dialog.add_primitive.shape.tube',
|
||||
cone: 'dialog.add_primitive.shape.cone',
|
||||
torus: 'dialog.add_primitive.shape.torus',
|
||||
sphere: 'dialog.add_primitive.shape.sphere',
|
||||
cube: 'dialog.add_primitive.shape.cube',
|
||||
pyramid: 'dialog.add_primitive.shape.pyramid',
|
||||
}},
|
||||
diameter: {label: 'dialog.add_primitive.diameter', type: 'number', value: 16},
|
||||
height: {label: 'dialog.add_primitive.height', type: 'number', value: 8, condition: ({shape}) => ['cylinder', 'cone', 'cube', 'pyramid', 'tube'].includes(shape)},
|
||||
sides: {label: 'dialog.add_primitive.sides', type: 'number', value: 16, condition: ({shape}) => ['cylinder', 'cone', 'circle', 'torus', 'sphere', 'tube'].includes(shape)},
|
||||
minor_diameter: {label: 'dialog.add_primitive.minor_diameter', type: 'number', value: 4, condition: ({shape}) => ['torus', 'tube'].includes(shape)},
|
||||
minor_sides: {label: 'dialog.add_primitive.minor_sides', type: 'number', value: 8, condition: ({shape}) => ['torus'].includes(shape)},
|
||||
},
|
||||
onConfirm(result) {
|
||||
let elements = [];
|
||||
Undo.initEdit({elements});
|
||||
let mesh = new Mesh({
|
||||
name: result.shape,
|
||||
vertices: {}
|
||||
});
|
||||
|
||||
if (result.shape == 'circle') {
|
||||
let vertex_keys = mesh.addVertices([0, 0, 0]);
|
||||
let [m] = vertex_keys;
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let x = Math.sin((i / result.sides) * Math.PI * 2) * result.diameter/2;
|
||||
let z = Math.cos((i / result.sides) * Math.PI * 2) * result.diameter/2;
|
||||
vertex_keys.push(...mesh.addVertices([x, 0, z]));
|
||||
}
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let [a, b] = vertex_keys.slice(i+2, i+2 + 2);
|
||||
if (!a) {
|
||||
b = vertex_keys[2];
|
||||
a = vertex_keys[1];
|
||||
} else if (!b) {
|
||||
b = vertex_keys[1];
|
||||
}
|
||||
mesh.addFaces(new MeshFace( mesh, {vertices: [a, b, m]} ));
|
||||
}
|
||||
}
|
||||
if (result.shape == 'cone') {
|
||||
let vertex_keys = mesh.addVertices([0, 0, 0], [0, result.height, 0]);
|
||||
let [m0, m1] = vertex_keys;
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let x = Math.sin((i / result.sides) * Math.PI * 2) * result.diameter/2;
|
||||
let z = Math.cos((i / result.sides) * Math.PI * 2) * result.diameter/2;
|
||||
vertex_keys.push(...mesh.addVertices([x, 0, z]));
|
||||
}
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let [a, b] = vertex_keys.slice(i+2, i+2 + 2);
|
||||
if (!b) {
|
||||
b = vertex_keys[2];
|
||||
}
|
||||
mesh.addFaces(
|
||||
new MeshFace( mesh, {vertices: [b, a, m0]} ),
|
||||
new MeshFace( mesh, {vertices: [a, b, m1]} )
|
||||
);
|
||||
}
|
||||
}
|
||||
if (result.shape == 'cylinder') {
|
||||
let vertex_keys = mesh.addVertices([0, 0, 0], [0, result.height, 0]);
|
||||
let [m0, m1] = vertex_keys;
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let x = Math.sin((i / result.sides) * Math.PI * 2) * result.diameter/2;
|
||||
let z = Math.cos((i / result.sides) * Math.PI * 2) * result.diameter/2;
|
||||
vertex_keys.push(...mesh.addVertices([x, 0, z], [x, result.height, z]));
|
||||
}
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let [a, b, c, d] = vertex_keys.slice(2*i+2, 2*i+2 + 4);
|
||||
if (!c) {
|
||||
c = vertex_keys[2];
|
||||
d = vertex_keys[3];
|
||||
}
|
||||
mesh.addFaces(
|
||||
new MeshFace( mesh, {vertices: [c, a, m0]}),
|
||||
new MeshFace( mesh, {vertices: [a, c, d, b]} ),
|
||||
new MeshFace( mesh, {vertices: [b, d, m1]} )
|
||||
);
|
||||
}
|
||||
}
|
||||
if (result.shape == 'tube') {
|
||||
let vertex_keys = [];
|
||||
|
||||
let outer_r = result.diameter/2;
|
||||
let inner_r = outer_r - result.minor_diameter;
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let x = Math.sin((i / result.sides) * Math.PI * 2);
|
||||
let z = Math.cos((i / result.sides) * Math.PI * 2);
|
||||
vertex_keys.push(...mesh.addVertices(
|
||||
[x * outer_r, 0, z * outer_r],
|
||||
[x * outer_r, result.height, z * outer_r],
|
||||
[x * inner_r, 0, z * inner_r],
|
||||
[x * inner_r, result.height, z * inner_r],
|
||||
));
|
||||
}
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let [a1, b1, c1, d1, a2, b2, c2, d2] = vertex_keys.slice(4*i, 4*i + 8);
|
||||
if (!a2) {
|
||||
a2 = vertex_keys[0];
|
||||
b2 = vertex_keys[1];
|
||||
c2 = vertex_keys[2];
|
||||
d2 = vertex_keys[3];
|
||||
}
|
||||
if (a1 && b1 && c1 && d1 && a2 && b2 && c2 && d2) {
|
||||
mesh.addFaces(
|
||||
new MeshFace( mesh, {vertices: [a1, a2, b2, b1]} ),
|
||||
new MeshFace( mesh, {vertices: [d1, d2, c2, c1]} ),
|
||||
new MeshFace( mesh, {vertices: [c1, c2, a2, a1]} ),
|
||||
new MeshFace( mesh, {vertices: [b1, b2, d2, d1]} ),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.shape == 'torus') {
|
||||
let rings = [];
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let circle_x = Math.sin((i / result.sides) * Math.PI * 2);
|
||||
let circle_z = Math.cos((i / result.sides) * Math.PI * 2);
|
||||
|
||||
let vertices = [];
|
||||
for (let j = 0; j < result.minor_sides; j++) {
|
||||
let slice_x = Math.sin((j / result.minor_sides) * Math.PI * 2) * result.minor_diameter/2;
|
||||
let x = circle_x * (result.diameter/2 + slice_x)
|
||||
let y = Math.cos((j / result.minor_sides) * Math.PI * 2) * result.minor_diameter/2;
|
||||
let z = circle_z * (result.diameter/2 + slice_x)
|
||||
vertices.push(...mesh.addVertices([x, y, z]));
|
||||
}
|
||||
rings.push(vertices);
|
||||
|
||||
}
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let this_ring = rings[i];
|
||||
let next_ring = rings[i+1] || rings[0];
|
||||
for (let j = 0; j < result.minor_sides; j++) {
|
||||
mesh.addFaces(new MeshFace( mesh, {vertices: [
|
||||
this_ring[j+1] || this_ring[0],
|
||||
next_ring[j+1] || next_ring[0],
|
||||
this_ring[j],
|
||||
next_ring[j],
|
||||
]} ));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.shape == 'sphere') {
|
||||
let rings = [];
|
||||
let sides = Math.round(result.sides/2)*2;
|
||||
let [bottom] = mesh.addVertices([0, -result.diameter/2, 0]);
|
||||
let [top] = mesh.addVertices([0, result.diameter/2, 0]);
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let circle_x = Math.sin((i / result.sides) * Math.PI * 2);
|
||||
let circle_z = Math.cos((i / result.sides) * Math.PI * 2);
|
||||
|
||||
let vertices = [];
|
||||
for (let j = 1; j < (sides/2); j++) {
|
||||
|
||||
let slice_x = Math.sin((j / sides) * Math.PI * 2) * result.diameter/2;
|
||||
let x = circle_x * slice_x
|
||||
let y = Math.cos((j / sides) * Math.PI * 2) * result.diameter/2;
|
||||
let z = circle_z * slice_x
|
||||
vertices.push(...mesh.addVertices([x, y, z]));
|
||||
}
|
||||
rings.push(vertices);
|
||||
|
||||
}
|
||||
|
||||
for (let i = 0; i < result.sides; i++) {
|
||||
let this_ring = rings[i];
|
||||
let next_ring = rings[i+1] || rings[0];
|
||||
for (let j = 0; j < (sides/2); j++) {
|
||||
if (j == 0) {
|
||||
mesh.addFaces(new MeshFace( mesh, {vertices: [
|
||||
this_ring[j],
|
||||
next_ring[j],
|
||||
top
|
||||
]} ));
|
||||
} else if (!this_ring[j]) {
|
||||
mesh.addFaces(new MeshFace( mesh, {vertices: [
|
||||
next_ring[j-1],
|
||||
this_ring[j-1],
|
||||
bottom
|
||||
]} ));
|
||||
} else {
|
||||
mesh.addFaces(new MeshFace( mesh, {vertices: [
|
||||
this_ring[j],
|
||||
next_ring[j],
|
||||
this_ring[j-1],
|
||||
next_ring[j-1],
|
||||
]} ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.shape == 'cube') {
|
||||
let r = result.diameter/2;
|
||||
let h = result.height;
|
||||
mesh.addVertices([r, h, r], [r, h, -r], [r, 0, r], [r, 0, -r], [-r, h, r], [-r, h, -r], [-r, 0, r], [-r, 0, -r]);
|
||||
let vertex_keys = Object.keys(mesh.vertices);
|
||||
mesh.addFaces(
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[0], vertex_keys[2], vertex_keys[1], vertex_keys[3]]} ), // East
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[4], vertex_keys[5], vertex_keys[6], vertex_keys[7]]} ), // West
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[0], vertex_keys[1], vertex_keys[4], vertex_keys[5]]} ), // Up
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[2], vertex_keys[6], vertex_keys[3], vertex_keys[7]]} ), // Down
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[0], vertex_keys[4], vertex_keys[2], vertex_keys[6]]} ), // South
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[1], vertex_keys[3], vertex_keys[5], vertex_keys[7]]} ), // North
|
||||
);
|
||||
}
|
||||
if (result.shape == 'pyramid') {
|
||||
let r = result.diameter/2;
|
||||
let h = result.height;
|
||||
mesh.addVertices([0, h, 0], [r, 0, r], [r, 0, -r], [-r, 0, r], [-r, 0, -r]);
|
||||
let vertex_keys = Object.keys(mesh.vertices);
|
||||
mesh.addFaces(
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[1], vertex_keys[3], vertex_keys[2], vertex_keys[4]]} ), // Down
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[1], vertex_keys[2], vertex_keys[0]]} ), // east
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[3], vertex_keys[1], vertex_keys[0]]} ), // south
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[2], vertex_keys[4], vertex_keys[0]]} ), // north
|
||||
new MeshFace( mesh, {vertices: [vertex_keys[4], vertex_keys[3], vertex_keys[0]]} ), // west
|
||||
);
|
||||
}
|
||||
elements.push(mesh);
|
||||
mesh.init()
|
||||
|
||||
Undo.finishEdit('Add primitive');
|
||||
}
|
||||
}).show()
|
||||
}
|
||||
})
|
||||
})
|
@ -782,6 +782,60 @@ class Preview {
|
||||
} else {
|
||||
list.replace(data.vertices);
|
||||
}
|
||||
if (event.altKey || Pressing.overrides.alt) {
|
||||
|
||||
let mesh = data.element;
|
||||
let start_face;
|
||||
for (let fkey in mesh.faces) {
|
||||
let face = mesh.faces[fkey];
|
||||
if (face.vertices.length < 3) continue;
|
||||
let vertices = face.vertices.filter(vkey => data.vertices.includes(vkey))
|
||||
if (vertices.length >= 2) {
|
||||
start_face = face;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!start_face) return;
|
||||
let processed_faces = [start_face];
|
||||
|
||||
function splitFace(face, side_vertices) {
|
||||
processed_faces.push(face);
|
||||
let sorted_vertices = face.getSortedVertices();
|
||||
|
||||
let side_index_diff = sorted_vertices.indexOf(side_vertices[0]) - sorted_vertices.indexOf(side_vertices[1]);
|
||||
if (side_index_diff == -1 || side_index_diff > 2) side_vertices.reverse();
|
||||
|
||||
let opposite_vertices = sorted_vertices.filter(vkey => !side_vertices.includes(vkey));
|
||||
let opposite_index_diff = sorted_vertices.indexOf(opposite_vertices[0]) - sorted_vertices.indexOf(opposite_vertices[1]);
|
||||
if (opposite_index_diff == 1 || opposite_index_diff < -2) opposite_vertices.reverse();
|
||||
|
||||
list.safePush(...side_vertices);
|
||||
|
||||
// Find next (and previous) face
|
||||
function doNextFace(index) {
|
||||
for (let fkey in mesh.faces) {
|
||||
let ref_face = mesh.faces[fkey];
|
||||
if (ref_face.vertices.length < 3 || processed_faces.includes(ref_face)) continue;
|
||||
|
||||
let sorted_vertices = ref_face.getSortedVertices();
|
||||
let vertices = ref_face.vertices.filter(vkey => vkey == side_vertices[index] || vkey == opposite_vertices[index]);
|
||||
|
||||
if (vertices.length >= 2) {
|
||||
let second_vertex = sorted_vertices.find((vkey, i) => {
|
||||
return vkey !== side_vertices[index]
|
||||
&& vkey !== opposite_vertices[index]
|
||||
&& (sorted_vertices.length == 3 || Math.abs(sorted_vertices.indexOf(side_vertices[index]) - i) !== 2);
|
||||
})
|
||||
splitFace(ref_face, [side_vertices[index], second_vertex]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
doNextFace(0)
|
||||
doNextFace(1);
|
||||
}
|
||||
splitFace(start_face, data.vertices);
|
||||
}
|
||||
updateSelection();
|
||||
}
|
||||
if (typeof Toolbox.selected.onCanvasClick === 'function') {
|
||||
|
@ -913,8 +913,6 @@
|
||||
"action.add_cube.desc": "Adds a new cube",
|
||||
"action.add_mesh": "Add Mesh",
|
||||
"action.add_mesh.desc": "Adds a new mesh",
|
||||
"action.add_primitive": "Add Primitive",
|
||||
"action.add_primitive.desc": "Adds a new primitive shape",
|
||||
"action.add_locator": "Add Locator",
|
||||
"action.add_locator.desc": "Adds a new locator to control positions of particles, leashes etc",
|
||||
"action.add_null_object": "Add Null Object",
|
||||
|
Loading…
Reference in New Issue
Block a user