diff --git a/css/panels.css b/css/panels.css index bfb258a..bb14c19 100644 --- a/css/panels.css +++ b/css/panels.css @@ -1385,8 +1385,8 @@ cursor: pointer; } #uv_scale_handle { - width: 20px; - height: 20px; + width: 18px; + height: 18px; position: absolute; text-align: center; cursor: nw-resize; @@ -1398,7 +1398,8 @@ } #uv_scale_handle i { transform: scaleY(-1); - font-size: 18px; + font-size: 16px; + padding-top: 2px; } .cube_box_uv { diff --git a/js/texturing/uv.js b/js/texturing/uv.js index 4ae3a54..69ec386 100644 --- a/js/texturing/uv.js +++ b/js/texturing/uv.js @@ -2469,7 +2469,7 @@ Interface.definePanels(function() { } }) }, - rotateFace(face_key, event) { + rotateFace(event) { if (event.which == 2 || event.which == 3) return; event.stopPropagation(); convertTouchEvent(event); @@ -2601,6 +2601,62 @@ Interface.definePanels(function() { addEventListeners(document, 'mouseup touchend', stop); }, + scaleFaces(event) { + if (event.which == 2 || event.which == 3) return; + event.stopPropagation(); + let elements = UVEditor.getMappableElements(); + Undo.initEdit({elements, uv_only: true}) + elements.forEach(element => { + this.selected_faces.forEach(fkey => { + let face = element.faces[fkey]; + if (!face) return; + if (element instanceof Cube) { + face.old_uv = face.uv.slice(); + } else if (element instanceof Mesh) { + face.old_uv = {}; + face.vertices.forEach(vkey => { + if (!face.uv[vkey]) return; + face.old_uv[vkey] = face.uv[vkey].slice(); + }) + } + }) + }) + let min = this.getSelectedUVBoundingBox(); + let bounding_size = [min[2]-min[0], min[3]-min[1]] + + let total_offset = [0, 0]; + let total_offset_y = 0; + this.drag({ + event, + onDrag: (x, y, event) => { + total_offset[0] += x; + total_offset[1] += y; + total_offset_y = (event.altKey || Pressing.overrides.alt) ? (total_offset[0] / bounding_size[0] * bounding_size[1]) : total_offset[1]; + elements.forEach(element => { + this.selected_faces.forEach(key => { + if (!element.faces[key]) return; + let face = element.faces[key]; + if (element instanceof Cube) { + face.uv[0] = min[0] + (face.old_uv[0] - min[0]) * (1 + total_offset[0]/bounding_size[0]); + face.uv[1] = min[1] + (face.old_uv[1] - min[1]) * (1 + total_offset_y /bounding_size[1]); + face.uv[2] = min[0] + (face.old_uv[2] - min[0]) * (1 + total_offset[0]/bounding_size[0]); + face.uv[3] = min[1] + (face.old_uv[3] - min[1]) * (1 + total_offset_y /bounding_size[1]); + } else if (element instanceof Mesh) { + for (let vkey in face.uv) { + face.uv[vkey][0] = min[0] + (face.old_uv[vkey][0] - min[0]) * (1 + total_offset[0]/bounding_size[0]); + face.uv[vkey][1] = min[1] + (face.old_uv[vkey][1] - min[1]) * (1 + total_offset_y /bounding_size[1]); + } + } + }) + }) + return [x, y] + }, + onEnd: () => { + UVEditor.disableAutoUV() + Undo.finishEdit('Scale UV') + } + }) + }, dragVertices(element, vertex_key, event) { if (event.which == 2 || event.which == 3) return; @@ -2654,7 +2710,7 @@ Interface.definePanels(function() { face.uv[vertex_key][0] += x; face.uv[vertex_key][1] += y; if ((event.shiftKey || Pressing.overrides.shift) && !(event.ctrlOrCmd || Pressing.overrides.ctrl)) { - let multiplier = settings.shift_size.value / 16 + let multiplier = (settings.shift_size.value / 16) * UVEditor.grid; face.uv[vertex_key][0] = Math.round(face.uv[vertex_key][0] * multiplier) / multiplier; face.uv[vertex_key][1] = Math.round(face.uv[vertex_key][1] * multiplier) / multiplier; } @@ -2723,6 +2779,40 @@ Interface.definePanels(function() { return faces; } }, + isScalingAvailable() { + if (this.mappable_elements[0] instanceof Cube) { + return !Project.box_uv && this.selected_faces.length > 1; + + } else if (this.mappable_elements[0] instanceof Mesh) { + return this.selected_faces.length > 0; + } + }, + getSelectedUVBoundingBox() { + let min = [Project.texture_width, Project.texture_height]; + let max = [0, 0]; + this.selected_faces.forEach(fkey => { + this.mappable_elements.forEach(element => { + if (!element.faces[fkey]) return; + + let face = element.faces[fkey]; + if (element instanceof Cube) { + min[0] = Math.min(min[0], face.uv[0], face.uv[2]); + min[1] = Math.min(min[1], face.uv[1], face.uv[3]); + max[0] = Math.max(max[0], face.uv[0], face.uv[2]); + max[1] = Math.max(max[1], face.uv[1], face.uv[3]); + } else if (element instanceof Mesh) { + face.vertices.forEach(vkey => { + if (!face.uv[vkey]) return; + min[0] = Math.min(min[0], face.uv[vkey][0]); + min[1] = Math.min(min[1], face.uv[vkey][1]); + max[0] = Math.max(max[0], face.uv[vkey][0]); + max[1] = Math.max(max[1], face.uv[vkey][1]); + }) + } + }) + }) + return [...min, ...max]; + }, getBrushOutlineStyle() { if (Toolbox.selected.brushTool) { var pixel_size = this.inner_width / (this.texture ? this.texture.width : Project.texture_width); @@ -2811,16 +2901,16 @@ Interface.definePanels(function() {
-
+
-
+
-
+
-
+
@@ -2863,7 +2953,7 @@ Interface.definePanels(function() { @mousedown.prevent.stop="dragVertices(element, key, $event)" @touchstart.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) )}" > -
+
@@ -2871,6 +2961,17 @@ Interface.definePanels(function() { +
+ +
+