mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-02-17 16:20:13 +08:00
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:
parent
4ba2e4a33a
commit
dd6ad7387a
@ -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>
|
||||
|
@ -970,7 +970,8 @@ var codec = new Codec('bedrock', {
|
||||
},
|
||||
open() {
|
||||
parseGeometry()
|
||||
}
|
||||
},
|
||||
tl
|
||||
},
|
||||
computed: {
|
||||
searched() {
|
||||
|
@ -370,7 +370,8 @@ var codec = new Codec('bedrock_old', {
|
||||
},
|
||||
open() {
|
||||
parseGeometry()
|
||||
}
|
||||
},
|
||||
tl
|
||||
},
|
||||
computed: {
|
||||
searched() {
|
||||
|
@ -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');
|
||||
|
@ -161,7 +161,8 @@ onVueSetup(function() {
|
||||
this.list_type = type;
|
||||
StateMemory.start_screen_list_type = type;
|
||||
StateMemory.save('start_screen_list_type')
|
||||
}
|
||||
},
|
||||
tl
|
||||
}
|
||||
})
|
||||
StartScreen = {
|
||||
|
@ -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));
|
||||
|
@ -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] = [];
|
||||
|
@ -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];
|
||||
|
@ -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'})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user