mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-03-25 17:11:15 +08:00
Add UV rotate tool
Improve array export of JSON compiler Stop texture animations playing when switching tab Fix duplicate keybinding from add mesh button Improve transform space normal calculation Fix interface issues Add "Instance" property type
This commit is contained in:
parent
cc1c48fb56
commit
66f7ec2b44
BIN
assets/rotate_cursor.png
Normal file
BIN
assets/rotate_cursor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
@ -328,6 +328,12 @@
|
||||
display: inline-block;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.tool:active .icon {
|
||||
padding-top: 1px;
|
||||
}
|
||||
.tool:active .icon.fa_big {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.tool.enabled {
|
||||
border-bottom: 3px solid var(--color-accent);
|
||||
|
@ -1182,7 +1182,7 @@
|
||||
background-color: rgba(50, 70, 240, 0.14);
|
||||
}
|
||||
.cube_box_uv:hover > div {
|
||||
border-color: var(--color-light);
|
||||
border-color: white;
|
||||
z-index: 3;
|
||||
}
|
||||
.cube_uv_face {
|
||||
@ -1198,12 +1198,12 @@
|
||||
color: var(--color-subtle_text);
|
||||
}
|
||||
.cube_uv_face:hover {
|
||||
border-color: var(--color-light);
|
||||
border-color: white;
|
||||
background-color: rgba(50, 70, 240, 0.3);
|
||||
z-index: 3;
|
||||
}
|
||||
.cube_uv_face.selected:not(.unselected) {
|
||||
border-color: var(--color-light);
|
||||
border-color: white;
|
||||
z-index: 4;
|
||||
box-shadow: 0 0 4px #000000cc;
|
||||
}
|
||||
@ -1273,7 +1273,7 @@
|
||||
stroke-width: 2px;
|
||||
}
|
||||
.mesh_uv_face:hover polygon {
|
||||
stroke: var(--color-light);
|
||||
stroke: white;
|
||||
}
|
||||
.mesh_uv_face.selected polygon {
|
||||
stroke: var(--color-accent);
|
||||
@ -1303,6 +1303,29 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.main_corner {
|
||||
position: absolute;
|
||||
}
|
||||
.main_corner::after {
|
||||
content: "";
|
||||
display: block;
|
||||
margin: -2px;
|
||||
height: 11px;
|
||||
width: 11px;
|
||||
border: 1px solid white;
|
||||
}
|
||||
.main_corner.selected::after {
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
.uv_rotate_field {
|
||||
position: absolute;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
bottom: 6px;
|
||||
right: 6px;
|
||||
cursor: url('../assets/rotate_cursor.png') 9 9, auto;
|
||||
}
|
||||
|
||||
.panel .bar.next_to_title {
|
||||
margin-top: -34px;
|
||||
margin-right: 32px;
|
||||
|
@ -1,6 +1,6 @@
|
||||
(function() {
|
||||
|
||||
let FORMATV = '3.6';
|
||||
let FORMATV = '4.0';
|
||||
|
||||
function processHeader(model) {
|
||||
if (!model.meta) {
|
||||
|
10
js/io/io.js
10
js/io/io.js
@ -392,21 +392,21 @@ function compileJSON(object, options) {
|
||||
//Number
|
||||
o = (Math.round(o*100000)/100000).toString()
|
||||
out += o
|
||||
} else if (typeof o === 'object' && o instanceof Array) {
|
||||
} else if (o instanceof Array) {
|
||||
//Array
|
||||
var has_content = false
|
||||
let has_content = false
|
||||
let has_objects = !!o.find(item => typeof item === 'object');
|
||||
out += '['
|
||||
for (var i = 0; i < o.length; i++) {
|
||||
var compiled = handleVar(o[i], tabs+1)
|
||||
if (compiled) {
|
||||
var breaks = typeof o[i] === 'object'
|
||||
if (has_content) {out += ',' + (breaks || options.small?'':' ')}
|
||||
if (breaks) {out += newLine(tabs)}
|
||||
if (has_objects) {out += newLine(tabs)}
|
||||
out += compiled
|
||||
has_content = true
|
||||
}
|
||||
}
|
||||
if (typeof o[o.length-1] === 'object') {out += newLine(tabs-1)}
|
||||
if (has_objects) {out += newLine(tabs-1)}
|
||||
out += ']'
|
||||
} else if (typeof o === 'object') {
|
||||
//Object
|
||||
|
@ -254,6 +254,7 @@ class ModelProject {
|
||||
}
|
||||
})
|
||||
|
||||
if (TextureAnimator.isPlaying) TextureAnimator.stop();
|
||||
this.selected = false;
|
||||
Painter.current = {};
|
||||
scene.remove(this.model_3d);
|
||||
|
@ -873,9 +873,15 @@ new NodePreviewController(Cube, {
|
||||
let {mesh} = cube;
|
||||
|
||||
let indices = [];
|
||||
let j = 0;
|
||||
mesh.geometry.faces = [];
|
||||
mesh.geometry.clearGroups();
|
||||
Canvas.face_order.forEach((fkey, i) => {
|
||||
if (cube.faces[fkey].texture !== null) {
|
||||
indices.push(0 + i*4, 2 + i*4, 1 + i*4, 2 + i*4, 3 + i*4, 1 + i*4);
|
||||
mesh.geometry.addGroup(j*6, 6, j)
|
||||
mesh.geometry.faces.push(fkey)
|
||||
j++;
|
||||
}
|
||||
})
|
||||
mesh.geometry.setIndex(indices)
|
||||
@ -899,11 +905,7 @@ new NodePreviewController(Cube, {
|
||||
} else {
|
||||
var materials = []
|
||||
Canvas.face_order.forEach(function(face) {
|
||||
|
||||
if (cube.faces[face].texture === null) {
|
||||
materials.push(Canvas.transparentMaterial)
|
||||
|
||||
} else {
|
||||
if (cube.faces[face].texture !== null) {
|
||||
var tex = cube.faces[face].getTexture()
|
||||
if (tex && tex.uuid) {
|
||||
materials.push(Project.materials[tex.uuid])
|
||||
|
@ -279,15 +279,30 @@ class Mesh extends OutlinerElement {
|
||||
return faces;
|
||||
}
|
||||
getSelectionRotation() {
|
||||
let [face] = this.getSelectedFaces().map(fkey => this.faces[fkey]);
|
||||
if (face) {
|
||||
let normal = face.getNormal(true)
|
||||
let faces = this.getSelectedFaces().map(fkey => this.faces[fkey]);
|
||||
if (!faces[0]) {
|
||||
let selected_vertices = this.getSelectedVertices();
|
||||
this.forAllFaces((face) => {
|
||||
if (face.vertices.find(vkey => selected_vertices.includes(vkey))) {
|
||||
faces.push(face);
|
||||
}
|
||||
})
|
||||
}
|
||||
if (faces[0]) {
|
||||
let normal = [0, 0, 0];
|
||||
faces.forEach(face => normal.V3_add(face.getNormal(true)))
|
||||
normal.V3_divide(faces.length);
|
||||
|
||||
var y = Math.atan2(normal[0], normal[2]);
|
||||
var x = Math.atan2(normal[1], Math.sqrt(Math.pow(normal[0], 2) + Math.pow(normal[2], 2)));
|
||||
return new THREE.Euler(-x, y, 0, 'YXZ');
|
||||
}
|
||||
}
|
||||
forAllFaces(cb) {
|
||||
for (let fkey in this.faces) {
|
||||
cb(this.faces[fkey], fkey);
|
||||
}
|
||||
}
|
||||
transferOrigin(origin, update = true) {
|
||||
if (!this.mesh) return;
|
||||
var q = new THREE.Quaternion().copy(this.mesh.quaternion);
|
||||
@ -814,7 +829,7 @@ BARS.defineActions(function() {
|
||||
}},
|
||||
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)},
|
||||
sides: {label: 'dialog.add_primitive.sides', type: 'number', value: 12, 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)},
|
||||
},
|
||||
@ -1066,7 +1081,6 @@ 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 () {
|
||||
add_mesh_dialog.show();
|
||||
|
@ -5,8 +5,6 @@ class Property {
|
||||
}
|
||||
target_class.properties[name] = this;
|
||||
|
||||
let scope = this;
|
||||
|
||||
this.class = target_class;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
@ -20,6 +18,7 @@ class Property {
|
||||
case 'number': this.default = 0; break;
|
||||
case 'boolean': this.default = false; break;
|
||||
case 'array': this.default = []; break;
|
||||
case 'instance': this.default = null; break;
|
||||
case 'vector': this.default = [0, 0, 0]; break;
|
||||
case 'vector2': this.default = [0, 0]; break;
|
||||
}
|
||||
@ -30,6 +29,7 @@ class Property {
|
||||
case 'number': this.isNumber = true; break;
|
||||
case 'boolean': this.isBoolean = true; break;
|
||||
case 'array': this.isArray = true; break;
|
||||
case 'instance': this.isInstance = true; break;
|
||||
case 'vector': this.isVector = true; break;
|
||||
case 'vector2': this.isVector2 = true; break;
|
||||
}
|
||||
@ -87,6 +87,11 @@ class Property {
|
||||
instance[this.name].replace(data[this.name]);
|
||||
}
|
||||
}
|
||||
else if (this.isInstance) {
|
||||
if (typeof data[this.name] === 'object') {
|
||||
instance[this.name] =data[this.name];
|
||||
}
|
||||
}
|
||||
}
|
||||
copy(instance, target) {
|
||||
if (!Condition(this.condition, instance)) return;
|
||||
|
@ -442,9 +442,6 @@ class Texture {
|
||||
this.source = dataUrl;
|
||||
this.img.src = dataUrl;
|
||||
this.updateMaterial();
|
||||
if (this == UVEditor.texture) {
|
||||
UVEditor.img.src = dataUrl;
|
||||
};
|
||||
if (open_dialog == 'UVEditor') {
|
||||
for (var key in UVEditor.editors) {
|
||||
var editor = UVEditor.editors[key];
|
||||
@ -654,7 +651,7 @@ class Texture {
|
||||
TextureAnimator.updateButton()
|
||||
hideDialog()
|
||||
if (UVEditor.texture == this) {
|
||||
UVEditor.displayTexture();
|
||||
UVEditor.vue.updateTexture();
|
||||
}
|
||||
BARS.updateConditions()
|
||||
Undo.finishEdit('Remove texture', {textures: []})
|
||||
@ -1381,9 +1378,6 @@ TextureAnimator = {
|
||||
$(`.texture[texid="${tex.uuid}"]`).find('img').css('margin-top', (tex.currentFrame*-48)+'px');
|
||||
maxFrame = Math.max(maxFrame, tex.currentFrame);
|
||||
})
|
||||
if (animated_textures.includes(UVEditor.texture)) {
|
||||
UVEditor.img.style.objectPosition = `0 -${UVEditor.texture.currentFrame * UVEditor.inner_height}px`;
|
||||
}
|
||||
Cube.all.forEach(cube => {
|
||||
var update = false
|
||||
for (var face in cube.faces) {
|
||||
|
@ -24,7 +24,6 @@ const UVEditor = {
|
||||
grid: 1,
|
||||
max_zoom: 16,
|
||||
auto_grid: true,
|
||||
texture: false,
|
||||
panel: null,
|
||||
sliders: {},
|
||||
|
||||
@ -373,6 +372,9 @@ const UVEditor = {
|
||||
get selected_faces() {
|
||||
return this.vue.selected_faces;
|
||||
},
|
||||
get texture() {
|
||||
return this.vue.texture;
|
||||
},
|
||||
getPixelSize() {
|
||||
if (Project.box_uv) {
|
||||
return this.inner_width/Project.texture_width
|
||||
@ -656,6 +658,18 @@ const UVEditor = {
|
||||
scope.getFaces(obj, event).forEach(function(side) {
|
||||
var uv = obj.faces[side].uv_size;
|
||||
obj.faces[side].uv_size = [uv[1], uv[0]];
|
||||
if (uv[0] < 0) {
|
||||
obj.faces[side].uv[0] += uv[0];
|
||||
obj.faces[side].uv[2] += uv[0];
|
||||
obj.faces[side].uv[1] -= uv[0];
|
||||
obj.faces[side].uv[3] -= uv[0];
|
||||
}
|
||||
if (uv[1] < 0) {
|
||||
obj.faces[side].uv[1] += uv[1];
|
||||
obj.faces[side].uv[3] += uv[1];
|
||||
obj.faces[side].uv[0] -= uv[1];
|
||||
obj.faces[side].uv[2] -= uv[1];
|
||||
}
|
||||
})
|
||||
obj.autouv = 0;
|
||||
Canvas.updateUV(obj);
|
||||
@ -896,11 +910,10 @@ const UVEditor = {
|
||||
this.message('uv_editor.mirrored')
|
||||
this.loadData()
|
||||
},
|
||||
applyAll(event) {
|
||||
var scope = this;
|
||||
applyAll() {
|
||||
this.forCubes(obj => {
|
||||
UVEditor.cube_faces.forEach(function(side) {
|
||||
$.extend(true, obj.faces[side], obj.faces[scope.face])
|
||||
UVEditor.cube_faces.forEach(side => {
|
||||
obj.faces[side].extend(obj.faces[this.selected_faces[0]])
|
||||
})
|
||||
obj.autouv = 0
|
||||
})
|
||||
@ -1582,14 +1595,14 @@ Interface.definePanels(function() {
|
||||
}
|
||||
}
|
||||
if (texture === null) {
|
||||
this.texture = UVEditor.texture = null;
|
||||
this.texture = null;
|
||||
} else if (texture instanceof Texture) {
|
||||
this.texture = texture;
|
||||
if (!Project.box_uv && UVEditor.auto_grid) {
|
||||
UVEditor.grid = texture.width / Project.texture_width;
|
||||
}
|
||||
} else {
|
||||
this.texture = UVEditor.texture = 0;
|
||||
this.texture = 0;
|
||||
}
|
||||
},
|
||||
updateMouseCoords(event) {
|
||||
@ -1776,7 +1789,7 @@ Interface.definePanels(function() {
|
||||
}
|
||||
}
|
||||
},
|
||||
drag({event, onDrag, onEnd, onAbort}) {
|
||||
drag({event, onDrag, onEnd, onAbort, snap}) {
|
||||
if (event.which == 2 || event.which == 3) return;
|
||||
let scope = this;
|
||||
|
||||
@ -1784,13 +1797,21 @@ Interface.definePanels(function() {
|
||||
let last_pos = [0, 0];
|
||||
function drag(e1) {
|
||||
|
||||
let snap = UVEditor.grid / canvasGridSize(e1.shiftKey || Pressing.overrides.shift, e1.ctrlOrCmd || Pressing.overrides.ctrl);
|
||||
if (snap == undefined) {
|
||||
let snap = UVEditor.grid / canvasGridSize(e1.shiftKey || Pressing.overrides.shift, e1.ctrlOrCmd || Pressing.overrides.ctrl);
|
||||
|
||||
let step_x = (scope.inner_width / UVEditor.getResolution(0) / snap);
|
||||
let step_y = (scope.inner_height / UVEditor.getResolution(1) / snap);
|
||||
|
||||
let step_x = (scope.inner_width / UVEditor.getResolution(0) / snap);
|
||||
let step_y = (scope.inner_height / UVEditor.getResolution(1) / snap);
|
||||
|
||||
pos[0] = Math.round((e1.clientX - event.clientX) / step_x) / snap;
|
||||
pos[1] = Math.round((e1.clientY - event.clientY) / step_y) / snap;
|
||||
pos[0] = Math.round((e1.clientX - event.clientX) / step_x) / snap;
|
||||
pos[1] = Math.round((e1.clientY - event.clientY) / step_y) / snap;
|
||||
} else {
|
||||
let step_x = snap
|
||||
let step_y = snap
|
||||
|
||||
pos[0] = Math.round((e1.clientX - event.clientX) / step_x) / snap;
|
||||
pos[1] = Math.round((e1.clientY - event.clientY) / step_y) / snap;
|
||||
}
|
||||
|
||||
if (pos[0] != last_pos[0] || pos[1] != last_pos[1]) {
|
||||
onDrag(pos[0] - last_pos[0], pos[1] - last_pos[1], e1)
|
||||
@ -1904,6 +1925,113 @@ Interface.definePanels(function() {
|
||||
}
|
||||
})
|
||||
},
|
||||
rotateFace(face_key, event) {
|
||||
if (event.which == 2 || event.which == 3) return;
|
||||
event.stopPropagation();
|
||||
let scope = this;
|
||||
let elements = this.mappable_elements;
|
||||
Undo.initEdit({elements, uv_only: true})
|
||||
|
||||
let face_center = [0, 0];
|
||||
let points = 0;
|
||||
elements.forEach(element => {
|
||||
this.selected_faces.forEach(fkey => {
|
||||
let face = element.faces[fkey];
|
||||
if (!face) return;
|
||||
if (element instanceof Cube) {
|
||||
face_center[0] += face.uv[0] + face.uv[2];
|
||||
face_center[1] += face.uv[1] + face.uv[3];
|
||||
points += 2;
|
||||
} else if (element instanceof Mesh) {
|
||||
face.vertices.forEach(vkey => {
|
||||
if (!face.uv[vkey]) return;
|
||||
face_center[0] += face.uv[vkey][0];
|
||||
face_center[1] += face.uv[vkey][1];
|
||||
points += 1;
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
face_center.forEach((v, i) => face_center[i] = v / points);
|
||||
|
||||
let offset = $(UVEditor.vue.$refs.frame).offset();
|
||||
let center_on_screen = [
|
||||
face_center[0] * UVEditor.getPixelSize() + offset.left,
|
||||
face_center[1] * UVEditor.getPixelSize() + offset.top,
|
||||
]
|
||||
|
||||
let angle = 0;
|
||||
let last_angle;
|
||||
let snap = elements[0] instanceof Cube ? 90 : 1;
|
||||
function drag(e1) {
|
||||
|
||||
angle = Math.atan2(
|
||||
(e1.clientY - center_on_screen[1]),
|
||||
(e1.clientX - center_on_screen[0]),
|
||||
)
|
||||
angle = Math.round(Math.radToDeg(angle) / snap) * snap;
|
||||
if (last_angle == undefined) last_angle = angle;
|
||||
if (Math.abs(angle - last_angle) > 300) last_angle = angle;
|
||||
|
||||
if (angle != last_angle) {
|
||||
|
||||
elements.forEach(element => {
|
||||
if (element instanceof Cube && Format.uv_rotation) {
|
||||
scope.selected_faces.forEach(key => {
|
||||
if (element.faces[key]) {
|
||||
element.faces[key].rotation += 90 * Math.sign(last_angle - angle);
|
||||
console.log(element.faces[key].rotation, Math.sign(last_angle - angle))
|
||||
if (element.faces[key].rotation == 360) element.faces[key].rotation = 0;
|
||||
if (element.faces[key].rotation < 0) element.faces[key].rotation += 360;
|
||||
console.log(element.faces[key].rotation)
|
||||
console.log('-----')
|
||||
}
|
||||
})
|
||||
|
||||
} else if (element instanceof Mesh) {
|
||||
scope.selected_faces.forEach(fkey => {
|
||||
let face = element.faces[fkey];
|
||||
if (!face) return;
|
||||
face.vertices.forEach(vkey => {
|
||||
if (!face.uv[vkey]) return;
|
||||
let sin = Math.sin(Math.degToRad(angle - last_angle));
|
||||
let cos = Math.cos(Math.degToRad(angle - last_angle));
|
||||
face.uv[vkey][0] -= face_center[0];
|
||||
face.uv[vkey][1] -= face_center[1];
|
||||
face.uv[vkey][0] = (face.uv[vkey][0] * cos - face.uv[vkey][1] * sin)
|
||||
face.uv[vkey][1] = (face.uv[vkey][0] * sin + face.uv[vkey][1] * cos)
|
||||
face.uv[vkey][0] += face_center[0];
|
||||
face.uv[vkey][1] += face_center[1];
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
UVEditor.turnMapping()
|
||||
|
||||
last_angle = angle;
|
||||
UVEditor.displaySliders();
|
||||
UVEditor.loadData();
|
||||
UVEditor.vue.$forceUpdate();
|
||||
Canvas.updateView({elements, element_aspects: {uv: true}});
|
||||
scope.dragging_uv = true;
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
removeEventListeners(document, 'mousemove touchmove', drag);
|
||||
removeEventListeners(document, 'mouseup touchend', stop);
|
||||
if (scope.dragging_uv) {
|
||||
UVEditor.disableAutoUV()
|
||||
Undo.finishEdit('Rotate UV')
|
||||
setTimeout(() => scope.dragging_uv = false, 10);
|
||||
} else {
|
||||
Undo.cancelEdit();
|
||||
}
|
||||
}
|
||||
addEventListeners(document, 'mousemove touchmove', drag);
|
||||
addEventListeners(document, 'mouseup touchend', stop);
|
||||
|
||||
},
|
||||
|
||||
dragVertices(element, vertex_key, event) {
|
||||
if (event.which == 2 || event.which == 3) return;
|
||||
@ -2076,10 +2204,18 @@ Interface.definePanels(function() {
|
||||
<div class="uv_resize_side horizontal" @mousedown="resizeFace(key, $event, 0, 1)" style="top: var(--height); width: var(--width)"></div>
|
||||
<div class="uv_resize_side vertical" @mousedown="resizeFace(key, $event, -1, 0)" style="height: var(--height)"></div>
|
||||
<div class="uv_resize_side vertical" @mousedown="resizeFace(key, $event, 1, 0)" style="left: var(--width); height: var(--height)"></div>
|
||||
<div class="uv_resize_corner uv_c_nw" @mousedown="resizeFace(key, $event, -1, -1)" style="left: 0; top: 0"></div>
|
||||
<div class="uv_resize_corner uv_c_ne" @mousedown="resizeFace(key, $event, 1, -1)" style="left: var(--width); top: 0"></div>
|
||||
<div class="uv_resize_corner uv_c_sw" @mousedown="resizeFace(key, $event, -1, 1)" style="left: 0; top: var(--height)"></div>
|
||||
<div class="uv_resize_corner uv_c_se" @mousedown="resizeFace(key, $event, 1, 1)" style="left: var(--width); top: var(--height)"></div>
|
||||
<div class="uv_resize_corner uv_c_nw" :class="{main_corner: !face.rotation}" @mousedown="resizeFace(key, $event, -1, -1)" style="left: 0; top: 0">
|
||||
<div class="uv_rotate_field" v-if="!face.rotation" @mousedown.stop="rotateFace(key, $event)"></div>
|
||||
</div>
|
||||
<div class="uv_resize_corner uv_c_ne" :class="{main_corner: face.rotation == 270}" @mousedown="resizeFace(key, $event, 1, -1)" style="left: var(--width); top: 0">
|
||||
<div class="uv_rotate_field" v-if="face.rotation == 270" @mousedown.stop="rotateFace(key, $event)"></div>
|
||||
</div>
|
||||
<div class="uv_resize_corner uv_c_sw" :class="{main_corner: face.rotation == 90}" @mousedown="resizeFace(key, $event, -1, 1)" style="left: 0; top: var(--height)">
|
||||
<div class="uv_rotate_field" v-if="face.rotation == 90" @mousedown.stop="rotateFace(key, $event)"></div>
|
||||
</div>
|
||||
<div class="uv_resize_corner uv_c_se" :class="{main_corner: face.rotation == 180}" @mousedown="resizeFace(key, $event, 1, 1)" style="left: var(--width); top: var(--height)">
|
||||
<div class="uv_rotate_field" v-if="face.rotation == 180" @mousedown.stop="rotateFace(key, $event)"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
@ -2113,11 +2249,13 @@ Interface.definePanels(function() {
|
||||
<polygon :points="getMeshFaceOutline(face)" />
|
||||
</svg>
|
||||
<template v-if="selected_faces.includes(key)">
|
||||
<div class="uv_mesh_vertex" v-for="key in face.vertices"
|
||||
:class="{selected: selected_vertices[element.uuid] && selected_vertices[element.uuid].includes(key)}"
|
||||
<div class="uv_mesh_vertex" v-for="(key, index) in face.vertices"
|
||||
:class="{main_corner: index == 0, selected: selected_vertices[element.uuid] && selected_vertices[element.uuid].includes(key)}"
|
||||
@mousedown.prevent.stop="dragVertices(element, key, $event)"
|
||||
:style="{left: toPixels( face.uv[key][0] - getMeshFaceCorner(face, 0) ), top: toPixels( face.uv[key][1] - getMeshFaceCorner(face, 1) )}"
|
||||
></div>
|
||||
>
|
||||
<div class="uv_rotate_field" @mousedown.stop="rotateFace(key, $event)" v-if="index == 0"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
32
package-lock.json
generated
32
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Blockbench",
|
||||
"version": "4.0.0-beta.0",
|
||||
"version": "4.0.0-beta.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -1188,9 +1188,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@electron/get": {
|
||||
"version": "1.12.4",
|
||||
"resolved": "https://registry.npmjs.org/@electron/get/-/get-1.12.4.tgz",
|
||||
"integrity": "sha512-6nr9DbJPUR9Xujw6zD3y+rS95TyItEVM0NVjt1EehY2vUWfIgPiIPVHxCvaTS0xr2B+DRxovYVKbuOWqC35kjg==",
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@electron/get/-/get-1.13.0.tgz",
|
||||
"integrity": "sha512-+SjZhRuRo+STTO1Fdhzqnv9D2ZhjxXP6egsJ9kiO8dtP68cDx7dFCwWi64dlMQV7sWcfW1OYCW4wviEBzmRsfQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^4.1.1",
|
||||
@ -2111,9 +2111,9 @@
|
||||
}
|
||||
},
|
||||
"boolean": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.2.tgz",
|
||||
"integrity": "sha512-YN6UmV0FfLlBVvRvNPx3pz5W/mUoYB24J4WSXOKP/OOJpi+Oq6WYqPaNTHzjI0QzwWtnvEd5CGYyQPgp1jFxnw==",
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.4.tgz",
|
||||
"integrity": "sha512-3hx0kwU3uzG6ReQ3pnaFQPSktpBw6RHN3/ivDKEuU8g1XSfafowyvDnadjv1xp8IZqhtSukxlwv9bF6FhX8m0w==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -2603,9 +2603,9 @@
|
||||
}
|
||||
},
|
||||
"core-js": {
|
||||
"version": "3.14.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.14.0.tgz",
|
||||
"integrity": "sha512-3s+ed8er9ahK+zJpp9ZtuVcDoFzHNiZsPbNAAE4KXgrRHbjSqqNN6xGSXq6bq7TZIbKj4NLrLb6bJ5i+vSVjHA==",
|
||||
"version": "3.17.3",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.17.3.tgz",
|
||||
"integrity": "sha512-lyvajs+wd8N1hXfzob1LdOCCHFU4bGMbqqmLn1Q4QlCpDqWPpGf+p0nj+LNrvDDG33j0hZXw2nsvvVpHysxyNw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -2848,9 +2848,9 @@
|
||||
}
|
||||
},
|
||||
"electron": {
|
||||
"version": "13.1.2",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-13.1.2.tgz",
|
||||
"integrity": "sha512-aNT9t+LgdQaZ7FgN36pN7MjSEoj+EWc2T9yuOqBApbmR4HavGRadSz7u9N2Erw2ojdIXtei2RVIAvVm8mbDZ0g==",
|
||||
"version": "13.3.0",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-13.3.0.tgz",
|
||||
"integrity": "sha512-d/BvOLDjI4i7yf9tqCuLL2fFGA2TrM/D9PyRpua+rJolG0qrwp/FohP02L0m+44kmPpofIo4l3NPwLmzyKKimA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@electron/get": "^1.0.1",
|
||||
@ -2859,9 +2859,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "14.17.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.3.tgz",
|
||||
"integrity": "sha512-e6ZowgGJmTuXa3GyaPbTGxX17tnThl2aSSizrFthQ7m9uLGZBXiGhgE55cjRZTF5kjZvYn9EOPOMljdjwbflxw==",
|
||||
"version": "14.17.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.17.tgz",
|
||||
"integrity": "sha512-niAjcewgEYvSPCZm3OaM9y6YQrL2SEPH9PymtE6fuZAvFiP6ereCcvApGl2jKTq7copTIguX3PBvfP08LN4LvQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +104,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"blockbench-types": "^3.9.0",
|
||||
"electron": "^13.1.2",
|
||||
"electron": "^13.3.0",
|
||||
"electron-builder": "^22.11.11",
|
||||
"electron-notarize": "^1.0.0",
|
||||
"webpack": "^5.21.2",
|
||||
|
Loading…
x
Reference in New Issue
Block a user