Add UV scaling

Fix  Problem with UV Mapping Meshes on 32x and above resolution
This commit is contained in:
JannisX11 2022-05-14 23:56:52 +02:00
parent d6a4d4e238
commit 43653520db
3 changed files with 113 additions and 10 deletions
css
js/texturing
lang

@ -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 {

@ -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() {
<div class="uv_resize_side vertical" @mousedown="resizeFace(key, $event, -1, 0)" @touchstart.prevent="resizeFace(key, $event, -1, 0)" style="height: var(--height)"></div>
<div class="uv_resize_side vertical" @mousedown="resizeFace(key, $event, 1, 0)" @touchstart.prevent="resizeFace(key, $event, 1, 0)" style="left: var(--width); height: var(--height)"></div>
<div class="uv_resize_corner uv_c_nw" :class="{main_corner: !face.rotation}" @mousedown="resizeFace(key, $event, -1, -1)" @touchstart.prevent="resizeFace(key, $event, -1, -1)" style="left: 0; top: 0">
<div class="uv_rotate_field" v-if="!face.rotation" @mousedown.stop="rotateFace(key, $event)" @touchstart.prevent.stop="rotateFace(key, $event)"></div>
<div class="uv_rotate_field" v-if="!face.rotation" @mousedown.stop="rotateFace($event)" @touchstart.prevent.stop="rotateFace($event)"></div>
</div>
<div class="uv_resize_corner uv_c_ne" :class="{main_corner: face.rotation == 270}" @mousedown="resizeFace(key, $event, 1, -1)" @touchstart.prevent="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)" @touchstart.prevent.stop="rotateFace(key, $event)"></div>
<div class="uv_rotate_field" v-if="face.rotation == 270" @mousedown.stop="rotateFace($event)" @touchstart.prevent.stop="rotateFace($event)"></div>
</div>
<div class="uv_resize_corner uv_c_sw" :class="{main_corner: face.rotation == 90}" @mousedown="resizeFace(key, $event, -1, 1)" @touchstart.prevent="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)" @touchstart.prevent.stop="rotateFace(key, $event)"></div>
<div class="uv_rotate_field" v-if="face.rotation == 90" @mousedown.stop="rotateFace($event)" @touchstart.prevent.stop="rotateFace($event)"></div>
</div>
<div class="uv_resize_corner uv_c_se" :class="{main_corner: face.rotation == 180}" @mousedown="resizeFace(key, $event, 1, 1)" @touchstart.prevent="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)" @touchstart.prevent.stop="rotateFace(key, $event)"></div>
<div class="uv_rotate_field" v-if="face.rotation == 180" @mousedown.stop="rotateFace($event)" @touchstart.prevent.stop="rotateFace($event)"></div>
</div>
</template>
</div>
@ -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) )}"
>
<div class="uv_rotate_field" @mousedown.stop="rotateFace(key, $event)" @touchstart.prevent.stop="rotateFace(key, $event)" v-if="index == 0"></div>
<div class="uv_rotate_field" @mousedown.stop="rotateFace($event)" @touchstart.prevent.stop="rotateFace($event)" v-if="index == 0"></div>
</div>
</template>
</div>
@ -2871,6 +2961,17 @@ Interface.definePanels(function() {
</template>
<div id="uv_scale_handle" v-if="mode == 'uv' && isScalingAvailable()"
@mousedown.stop="scaleFaces($event)" @touchstart.prevent.stop="scaleFaces($event)"
:title="tl('uv_editor.scale_uv')"
:style="{
left: toPixels(getSelectedUVBoundingBox()[2], -2),
top: toPixels(getSelectedUVBoundingBox()[3], -2),
}
">
<i class="fa fa-solid fa-square-up-right"></i>
</div>
<div class="selection_rectangle"
v-if="selection_rect.active"
:style="{

@ -1587,6 +1587,7 @@
"uv_editor.all_faces": "All",
"uv_editor.no_faces": "None",
"uv_editor.rotated": "Rotated",
"uv_editor.scale_uv": "Scale UV",
"uv_editor.auto_cull": "Cullface To Self",
"uv_editor.copied": "Copied Face",
"uv_editor.pasted": "Pasted Face",