Allow vertex snapping for mesh sections, closes #1056

Fix mesh painting grid issues
Fix vue issues
Fix shape and gradient tool not working on meshes
This commit is contained in:
JannisX11 2021-09-23 15:59:26 +02:00
parent 4ba2e4a33a
commit dd6ad7387a
9 changed files with 85 additions and 93 deletions

View File

@ -2078,9 +2078,13 @@ const BARS = {
Toolbars.vertex_snap = new Toolbar({
id: 'vertex_snap',
children: [
'vertex_snap_mode'
'vertex_snap_mode',
'selection_mode'
]
})
Blockbench.onUpdateTo('4.0', () => {
Toolbars.vertex_snap.add(BarItems.selection_mode);
})
//Mobile
Toolbars.mobile_side = new Toolbar({
@ -2235,7 +2239,8 @@ const BARS = {
}
]).open(event)
},
getIconNode: Blockbench.getIconNode
getIconNode: Blockbench.getIconNode,
Condition
},
template: `
<div>
@ -2243,8 +2248,8 @@ const BARS = {
<li v-for="item in currentBar" v-bind:title="item.name" :key="item.id||item" @contextmenu="openContextMenu(item, $event)">
<div v-if="typeof item === 'string'" class="toolbar_separator" :class="{border: item[0] == '_', spacer: item[0] == '+', linebreak: item[0] == '#'}"></div>
<div v-else class="tool">
<div class="tooltip">{{item.name + (BARS.condition(item.condition) ? '' : ' (' + tl('dialog.toolbar_edit.hidden') + ')' )}}</div>
<span class="icon_wrapper" v-bind:style="{opacity: BARS.condition(item.condition) ? 1 : 0.4}" v-html="getIconNode(item.icon, item.color).outerHTML"></span>
<div class="tooltip">{{item.name + (Condition(item.condition) ? '' : ' (' + tl('dialog.toolbar_edit.hidden') + ')' )}}</div>
<span class="icon_wrapper" v-bind:style="{opacity: Condition(item.condition) ? 1 : 0.4}" v-html="getIconNode(item.icon, item.color).outerHTML"></span>
</div>
</li>
</ul>

View File

@ -970,7 +970,8 @@ var codec = new Codec('bedrock', {
},
open() {
parseGeometry()
}
},
tl
},
computed: {
searched() {

View File

@ -370,7 +370,8 @@ var codec = new Codec('bedrock_old', {
},
open() {
parseGeometry()
}
},
tl
},
computed: {
searched() {

View File

@ -289,7 +289,7 @@ function uploadSketchfabModel() {
if (elements.length === 0 || !Format) {
return;
}
let tag_suggestions = ['lowpoly', 'pixelart'];
let tag_suggestions = ['low-poly', 'pixel-art'];
if (Format.id !== 'free') tag_suggestions.push('minecraft');
if (Format.id === 'skin') tag_suggestions.push('skin');
if (!Mesh.all.length) tag_suggestions.push('voxel');

View File

@ -161,7 +161,8 @@ onVueSetup(function() {
this.list_type = type;
StateMemory.start_screen_list_type = type;
StateMemory.save('start_screen_list_type')
}
},
tl
}
})
StartScreen = {

View File

@ -882,15 +882,15 @@ new NodePreviewController(Mesh, {
let vkey2 = vertices[i+1] || vertices[0];
let uv1 = face.uv[vkey1].slice();
let uv2 = face.uv[vkey2].slice();
if (uv1[0] > uv2[0]) [uv1[0], uv2[0]] = [uv2[0], uv1[0]];
if (uv1[1] > uv2[1]) [uv1[1], uv2[1]] = [uv2[1], uv1[1]];
let range_x = (uv1[0] > uv2[0]) ? [uv2[0], uv1[0]] : [uv1[0], uv2[0]];
let range_y = (uv1[1] > uv2[1]) ? [uv2[1], uv1[1]] : [uv1[1], uv2[1]];
for (let x = Math.ceil(uv1[0] / psize_x) * psize_x; x < uv2[0]; x += psize_x) {
for (let x = Math.ceil(range_x[0] / psize_x) * psize_x; x < range_x[1]; x += psize_x) {
if (!x_memory[x]) x_memory[x] = [];
let y = uv1[1] + (uv2[1] - uv1[1]) * Math.lerp(uv1[0], uv2[0], x);
x_memory[x].push(face.UVToLocal([x, y]).toArray().V3_add(offset));
}
for (let y = Math.ceil(uv1[1] / psize_y) * psize_y; y < uv2[1]; y += psize_y) {
for (let y = Math.ceil(range_y[0] / psize_y) * psize_y; y < range_y[1]; y += psize_y) {
if (!y_memory[y]) y_memory[y] = [];
let x = uv1[0] + (uv2[0] - uv1[0]) * Math.lerp(uv1[1], uv2[1], y);
y_memory[y].push(face.UVToLocal([x, y]).toArray().V3_add(offset));

View File

@ -784,7 +784,7 @@ class Preview {
updateSelection();
}
} else if (data.type == 'vertex') {
} else if (data.type == 'vertex' && Toolbox.selected.id !== 'vertex_snap_tool') {
if (!Project.selected_vertices[data.element.uuid]) {
Project.selected_vertices[data.element.uuid] = [];

View File

@ -236,12 +236,50 @@ const Painter = {
Painter.currentPixel = [-1, -1];
},
// Tools
setupRectFromFace(uvTag, texture) {
let rect;
let uvFactorX = texture.width / Project.texture_width;
let uvFactorY = texture.display_height / Project.texture_height;
if (uvTag) {
let anim_offset = texture.display_height * texture.currentFrame;
if (uvTag instanceof Array) {
rect = Painter.editing_area = [
uvTag[0] * uvFactorX,
uvTag[1] * uvFactorY + anim_offset,
uvTag[2] * uvFactorX,
uvTag[3] * uvFactorY + anim_offset
]
for (var t = 0; t < 2; t++) {
if (rect[t] > rect[t+2]) {
[rect[t], rect[t+2]] = [rect[t+2], rect[t]]
}
rect[t] = Math.round(rect[t])
rect[t+2] = Math.round(rect[t+2])
}
} else {
let min_x = Project.texture_width, min_y = Project.texture_height, max_x = 0, max_y = 0;
for (let vkey in uvTag) {
min_x = Math.min(min_x, uvTag[vkey][0]); max_x = Math.max(max_x, uvTag[vkey][0]);
min_y = Math.min(min_y, uvTag[vkey][1]); max_y = Math.max(max_y, uvTag[vkey][1]);
}
rect = Painter.editing_area = [
Math.floor(min_x * uvFactorX),
Math.floor(min_y * uvFactorY) + anim_offset,
Math.ceil(max_x * uvFactorX),
Math.ceil(max_y * uvFactorY) + anim_offset
]
}
} else {
rect = Painter.editing_area = [0, 0, texture.img.naturalWidth, texture.img.naturalHeight]
}
return rect;
},
useBrushlike(texture, x, y, event, uvTag, no_update, is_opposite) {
if (Painter.currentPixel[0] === x && Painter.currentPixel[1] === y) return;
Painter.currentPixel = [x, y]
Painter.brushChanges = true;
let uvFactorX = 1 / Project.texture_width * texture.width;
let uvFactorY = 1 / Project.texture_height * texture.display_height;
let uvFactorX = texture.width / Project.texture_width;
let uvFactorY = texture.display_height / Project.texture_height;
if (Painter.mirror_painting && !is_opposite) {
Painter.runMirrorBrush(texture, x, y, event, uvTag);
@ -252,38 +290,7 @@ const Painter = {
ctx.save()
ctx.beginPath();
if (uvTag) {
let anim_offset = texture.display_height * texture.currentFrame;
if (uvTag instanceof Array) {
var rect = Painter.editing_area = [
uvTag[0] * uvFactorX,
uvTag[1] * uvFactorY + anim_offset,
uvTag[2] * uvFactorX,
uvTag[3] * uvFactorY + anim_offset
]
} else {
let min_x = Project.texture_width, min_y = Project.texture_height, max_x = 0, max_y = 0;
for (let vkey in uvTag) {
min_x = Math.min(min_x, uvTag[vkey][0]); max_x = Math.max(max_x, uvTag[vkey][0]);
min_y = Math.min(min_y, uvTag[vkey][1]); max_y = Math.max(max_y, uvTag[vkey][1]);
}
var rect = Painter.editing_area = [
Math.floor(min_x * uvFactorX),
Math.floor(min_y * uvFactorY) + anim_offset,
Math.ceil(max_x * uvFactorX),
Math.ceil(max_y * uvFactorY) + anim_offset
]
}
} else {
var rect = Painter.editing_area = [0, 0, texture.img.naturalWidth, texture.img.naturalHeight]
}
for (var t = 0; t < 2; t++) {
if (rect[t] > rect[t+2]) {
[rect[t], rect[t+2]] = [rect[t+2], rect[t]]
}
rect[t] = Math.round(rect[t])
rect[t+2] = Math.round(rect[t+2])
}
let rect = Painter.setupRectFromFace(uvTag, texture);
var [w, h] = [rect[2] - rect[0], rect[3] - rect[1]]
ctx.rect(rect[0], rect[1], w, h)
@ -294,7 +301,6 @@ const Painter = {
}
Painter.editing_area = undefined;
}, {no_undo: true, use_cache: true, no_update});
},
useBrush(texture, ctx, x, y, event) {
@ -601,27 +607,9 @@ const Painter = {
let hollow = shape.substr(-1) == 'h';
shape = shape.replace(/_h$/, '');
if (uvTag) {
var rect = Painter.editing_area = [
uvTag[0] / Project.texture_width * texture.img.naturalWidth,
uvTag[1] / Project.texture_height * texture.img.naturalHeight,
uvTag[2] / Project.texture_width * texture.img.naturalWidth,
uvTag[3] / Project.texture_height * texture.img.naturalHeight
]
} else {
var rect = Painter.editing_area = [0, 0, texture.img.naturalWidth, texture.img.naturalHeight]
}
for (var t = 0; t < 2; t++) {
if (rect[t] > rect[t+2]) {
[rect[t], rect[t+2]] = [rect[t+2], rect[t]]
}
rect[t] = Math.round(rect[t])
rect[t+2] = Math.round(rect[t+2])
}
var rect = Painter.setupRectFromFace(uvTag, texture);
var [w, h] = [rect[2] - rect[0], rect[3] - rect[1]]
let diff_x = x - Painter.startPixel[0];
let diff_y = y - Painter.startPixel[1];
@ -735,23 +723,7 @@ const Painter = {
let b_opacity = BarItems.slider_brush_opacity.get()/100;
if (uvTag) {
var rect = Painter.editing_area = [
uvTag[0] / Project.texture_width * texture.img.naturalWidth,
uvTag[1] / Project.texture_height * texture.img.naturalHeight,
uvTag[2] / Project.texture_width * texture.img.naturalWidth,
uvTag[3] / Project.texture_height * texture.img.naturalHeight
]
} else {
var rect = Painter.editing_area = [0, 0, texture.img.naturalWidth, texture.img.naturalHeight]
}
for (var t = 0; t < 2; t++) {
if (rect[t] > rect[t+2]) {
[rect[t], rect[t+2]] = [rect[t+2], rect[t]]
}
rect[t] = Math.round(rect[t])
rect[t+2] = Math.round(rect[t+2])
}
let rect = Painter.setupRectFromFace(uvTag, texture);
var [w, h] = [rect[2] - rect[0], rect[3] - rect[1]];
let diff_x = x - Painter.startPixel[0];
let diff_y = y - Painter.startPixel[1];

View File

@ -323,6 +323,7 @@ const Vertexsnap = {
Vertexsnap.vertex_index = data.vertex_index;
Vertexsnap.move_origin = typeof data.vertex !== 'string' && data.vertex.allEqual(0);
Vertexsnap.elements = Outliner.selected.slice();
Vertexsnap.selected_vertices = JSON.parse(JSON.stringify(Project.selected_vertices));
Vertexsnap.clearVertexGizmos()
$('#preview').css('cursor', (Vertexsnap.step1 ? 'copy' : 'alias'))
@ -395,16 +396,27 @@ const Vertexsnap = {
Vertexsnap.elements.forEach(function(obj) {
var cube_pos = new THREE.Vector3().copy(global_delta)
if (Format.bone_rig && obj.parent instanceof Group && obj.mesh.parent) {
var q = obj.mesh.parent.getWorldQuaternion(new THREE.Quaternion()).invert();
if (obj instanceof Mesh && Vertexsnap.selected_vertices && Vertexsnap.selected_vertices[obj.uuid]) {
let vertices = Vertexsnap.selected_vertices[obj.uuid];
var q = obj.mesh.getWorldQuaternion(Reusable.quat1).invert();
cube_pos.applyQuaternion(q);
}
if (obj instanceof Cube && Format.rotate_cubes) {
obj.origin.V3_add(cube_pos);
}
var in_box = obj.moveVector(cube_pos.toArray());
if (!in_box && Format.canvas_limit && !settings.deactivate_size_limit.value) {
Blockbench.showMessageBox({translateKey: 'canvas_limit_error'})
let cube_pos_array = cube_pos.toArray();
vertices.forEach(vkey => {
if (obj.vertices[vkey]) obj.vertices[vkey].V3_add(cube_pos_array);
})
} else {
if (Format.bone_rig && obj.parent instanceof Group) {
var q = obj.mesh.parent.getWorldQuaternion(Reusable.quat1).invert();
cube_pos.applyQuaternion(q);
}
if (obj instanceof Cube && Format.rotate_cubes) {
obj.origin.V3_add(cube_pos);
}
var in_box = obj.moveVector(cube_pos.toArray());
if (!in_box && Format.canvas_limit && !settings.deactivate_size_limit.value) {
Blockbench.showMessageBox({translateKey: 'canvas_limit_error'})
}
}
})
}