From 968ec5f6d4e2d6ee9dbe9ac956c0f81a66e43420 Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Wed, 25 Aug 2021 22:00:08 +0200 Subject: [PATCH] New UV editor progress --- css/panels.css | 56 +++- js/io/project.js | 1 + js/texturing/uv.js | 642 ++++++++++++++------------------------------- lang/en.json | 1 + 4 files changed, 250 insertions(+), 450 deletions(-) diff --git a/css/panels.css b/css/panels.css index 37f7e3f2..146cc8b1 100644 --- a/css/panels.css +++ b/css/panels.css @@ -1126,6 +1126,7 @@ border: 4px solid var(--color-ui); box-shadow: 0 0 0 800px var(--color-back); box-sizing: content-box; + --color-unselected: var(--color-grid); } body[mode=paint] #uv_frame { @@ -1159,10 +1160,11 @@ .cube_box_uv { position: absolute; + z-index: 2; } .cube_box_uv > div { position: absolute; - z-index: 1; + z-index: 2; cursor: move; border: 2px solid var(--color-accent); box-sizing: border-box; @@ -1172,11 +1174,11 @@ } .cube_box_uv:hover > div { border-color: var(--color-light); - z-index: 2; + z-index: 3; } .cube_uv_face { position: absolute; - z-index: 1; + z-index: 2; width: var(--width); height: var(--height); cursor: move; @@ -1189,11 +1191,21 @@ .cube_uv_face:hover { border-color: var(--color-light); background-color: rgba(50, 70, 240, 0.3); - z-index: 2; + z-index: 3; } .cube_uv_face.selected { - border-color: var(--color-accent); - z-index: 3; + border-color: var(--color-light); + z-index: 4; + box-shadow: 0 0 4px #000000cc; + } + .cube_uv_face.unselected, + .cube_box_uv.unselected { + pointer-events: none; + z-index: 1; + } + .cube_uv_face.unselected div, + .cube_box_uv.unselected div { + border-color: var(--color-unselected) !important; } .uv_resize_side { @@ -1214,9 +1226,10 @@ .uv_resize_corner { position: absolute; margin: -6px; - height: 8px; - width: 8px; - background-color: var(--color-text); + height: 9px; + width: 9px; + background-color: white; + border: 1px solid black; z-index: 3; } .uv_resize_corner.uv_c_nw {cursor: nw-resize;} @@ -1321,6 +1334,26 @@ left: 2px; }*/ + .uv_cube_face_bar { + display: flex; + height: 28px; + } + .uv_cube_face_bar li { + flex-grow: 1; + text-align: center; + padding: 2px; + margin: 0 1px; + } + .uv_cube_face_bar li:hover { + color: var(--color-light); + } + .uv_cube_face_bar li.selected { + border-bottom: 3px solid var(--color-accent); + } + .uv_cube_face_bar li.disabled { + color: var(--color-subtle_text); + } + #texture_selection_rect { position: absolute; pointer-events: none; @@ -1367,6 +1400,11 @@ background-color: var(--color-accent); color: var(--color-accent_text); } + .uv_transparent_face { + margin: 8px auto auto; + color: var(--color-subtle_text); + max-width: fit-content; + } /*Chat*/ #chat { diff --git a/js/io/project.js b/js/io/project.js index ec29633a..ffb88c18 100644 --- a/js/io/project.js +++ b/js/io/project.js @@ -172,6 +172,7 @@ class ModelProject { Interface.Panels.outliner.inside_vue.root = this.outliner; UVEditor.vue.elements = this.selected_elements; + UVEditor.vue.all_elements = this.elements; UVEditor.vue.selected_vertices = this.selected_vertices; UVEditor.vue.selected_faces = this.selected_faces; UVEditor.vue.box_uv = this.box_uv; diff --git a/js/texturing/uv.js b/js/texturing/uv.js index 66f2a3d3..bf7dfc52 100644 --- a/js/texturing/uv.js +++ b/js/texturing/uv.js @@ -32,7 +32,7 @@ const UVEditor = { get vue() { return this.panel.inside_vue; }, - + /* buildDom(toolbar) { var scope = this if (this.jquery.main) { @@ -75,62 +75,7 @@ const UVEditor = { this.jquery.sliders = $('
') this.jquery.main.append(this.jquery.sliders) - - var dragging_not_clicking = false; - this.jquery.size.resizable({ - handles: "all", - maxHeight: 320, - maxWidth: 320, - minWidth: 0, - minHeight: 0, - containment: 'parent', - start: function(event, ui) { - Undo.initEdit({elements: Cube.selected, uv_only: true}) - }, - resize: function(event, ui) { - scope.save(false) - scope.displaySliders() - }, - stop: function(event, ui) { - dragging_not_clicking = true; - scope.disableAutoUV() - Undo.finishEdit('Edit UV size') - scope.updateDragHandle(ui.position) - } - }) - - this.jquery.size.draggable({ - start: function(event, ui) { - Undo.initEdit({elements: Cube.selected, uv_only: true}) - }, - drag: function( event, ui ) { - var p = ui.position; - var o = ui.originalPosition; - - p.left = o.left + (p.left - o.left); - p.top = o.top + (p.top - o.top); - - p.left = limitNumber(p.left, 0, scope.inner_width-scope.jquery.size.width()+1); - p.top = limitNumber(p.top, 0, scope.inner_height-scope.jquery.size.height()+1); - - let step_x = (scope.inner_width / scope.getResolution(0) / scope.grid); - let step_y = (scope.inner_height / scope.getResolution(1) / scope.grid); - - p.left = Math.round(p.left / step_x) * step_x; - p.top = Math.round(p.top / step_y) * step_y; - - scope.save(true); - scope.displaySliders(); - return true; - }, - stop: function(event, ui) { - scope.save(true) - scope.disableAutoUV() - Undo.finishEdit('Move UV') - scope.updateDragHandle(ui.position) - } - }) this.jquery.frame.droppable({ accept: 'li.texture', @@ -222,6 +167,7 @@ const UVEditor = { this.setSize(this.size) return this; }, + */ updateBrushOutline(e) { if (Modes.paint && Toolbox.selected.brushTool) { this.jquery.frame.append(this.brush_outline); @@ -243,8 +189,10 @@ const UVEditor = { }, message(msg, vars) { msg = tl(msg, vars) - var box = $('
' + msg + '
') - this.jquery.main.append(box) + let box = document.createElement('div'); + box.className = 'uv_message_box' + box.textContent = msg; + this.vue.$refs.main.append(box) setTimeout(function() { box.remove() }, 1200) @@ -530,10 +478,10 @@ const UVEditor = { return this.vue.zoom; }, get inner_width() { - return this.size*this.zoom; + return this.vue.inner_width; }, get inner_height() { - return this.height*this.zoom; + return this.vue.inner_height; }, getPixelSize() { if (Project.box_uv) { @@ -546,13 +494,28 @@ const UVEditor = { ); } }, - getFaces(event) { + getFaces(obj, event) { + let available = Object.keys(obj.faces) if (event && event.shiftKey) { - return ['north', 'east', 'south', 'west', 'up', 'down'] + return available; } else { - return [this.face] + return UVEditor.vue.selected_faces.filter(key => available.includes(key)); } }, + getReferenceFace() { + let el = this.getMappableElements()[0]; + if (el) { + for (let key in el.faces) { + if (UVEditor.vue.selected_faces.includes(key)) { + return el.faces[key]; + } + } + } + }, + getMappableElements() { + let object = 'object' + return Outliner.selected.filter(el => typeof el.faces == object); + }, getUVTag(obj) { if (!obj) obj = Cube.selected[0] if (Project.box_uv) { @@ -682,40 +645,37 @@ const UVEditor = { //Selection reverseSelect(event) { var scope = this; - if (!this.texture && !Format.single_texture) return this; + if (!this.vue.texture && !Format.single_texture) return this; if (!event.target.classList.contains('uv_size_handle') && !event.target.id === 'uv_frame') { return this; } var matches = []; - var face_match; + var face_matches = []; var u = event.offsetX / this.vue.inner_width * this.getResolution(0); var v = event.offsetY / this.vue.inner_height * this.getResolution(1); Cube.all.forEach(cube => { for (var face in cube.faces) { var uv = cube.faces[face].uv - if (uv && Math.isBetween(u, uv[0], uv[2]) && Math.isBetween(v, uv[1], uv[3]) && (cube.faces[face].getTexture() === scope.texture || Format.single_texture)) { + if (uv && Math.isBetween(u, uv[0], uv[2]) && Math.isBetween(v, uv[1], uv[3]) && (cube.faces[face].getTexture() === scope.vue.texture || Format.single_texture)) { matches.safePush(cube) - if (!face_match) { - face_match = face - } + face_matches.safePush(face) break; } } }) if (matches.length) { if (!Project.box_uv) { - UVEditor.setFace(face_match); + UVEditor.vue.selected_faces.replace(face_matches); } - if (!event.shiftKey && !Pressing.overrides.shift) { - selected.empty(); + if (!event.shiftKey && !Pressing.overrides.shift && !event.ctrlOrCmd && !Pressing.overrides.ctrl) { + Project.selected_elements.empty(); } matches.forEach(s => { - selected.safePush(s) - console.log(s.size(), face_match) + Project.selected_elements.safePush(s) }); updateSelection(); } - return this; + return matches; }, forCubes(cb) { var i = 0; @@ -734,16 +694,15 @@ const UVEditor = { this.vue.updateTexture(); this.displaySliders(); this.displayTools(); + this.vue.$forceUpdate(); return this; if (Cube.selected.length === 0 && !Modes.paint) return; var face = Cube.selected[0] && Cube.selected[0].faces[this.face]; //Set Rotation - BarItems.uv_rotation.set((face && face.rotation)||0) this.displayTexture(face) this.displayFrame()//and transform info - this.updateDragHandle() if (this !== UVEditor && this.face === UVEditor.face) { UVEditor.loadData() } @@ -855,174 +814,14 @@ const UVEditor = { this.jquery.transform_info.append(''+ref.rotation+'') } }, - displayFrame() { - return this; - var scope = this; - if (!Modes.edit) return; - if (Project.box_uv) { - var uvTag = this.getUVTag(Cube.selected[0]) - - var size_tag = Cube.selected[0].size(undefined, true) - - var width = (size_tag[0] + size_tag[2])*2 - width = limitNumber(width, 0, Project.texture_width) - width = width/Project.texture_width*scope.inner_width - - var x = limitNumber(uvTag[0], 0, Project.texture_width) - x *= scope.inner_width/Project.texture_width - - this.jquery.size.width(width) - this.jquery.size.css('left', x+'px') - - - var height = size_tag[2] + size_tag[1] - height = limitNumber(height, 0, Project.texture_height) - height = height/Project.texture_height*scope.inner_width - height *= Project.texture_height/Project.texture_width - - var y = limitNumber(uvTag[1], 0, Project.texture_height) - y *= scope.inner_width/Project.texture_height - y *= Project.texture_height/Project.texture_width - - this.jquery.size.height(height) - this.jquery.size.css('top', y+'px') - } else { - - var uvTag = this.getUVTag(Cube.selected[0]) - - //X - var tex_width = this.getResolution(0); - var width = limitNumber(uvTag[2]-uvTag[0], -tex_width, tex_width) - var x = limitNumber(uvTag[0], 0, tex_width) - if (width < 0) { - width *= -1 - x = x - width - } - var pixels = this.inner_width/tex_width; - this.jquery.size.width(width * pixels); - this.jquery.size.css('left', x*pixels+'px'); - - //Y - var tex_height = this.getResolution(1); - var height = limitNumber(uvTag[3]-uvTag[1], -tex_height, tex_height); - var y = limitNumber(uvTag[1], 0, tex_height); - if (height < 0) { - height *= -1; - y = y - height; - } - this.jquery.size.height(height * pixels); - this.jquery.size.css('top', y*pixels+'px'); - } - this.updateDragHandle(); - this.displayTransformInfo(); - }, - //Overlay - displayMappingOverlay() { - return this; - if (!Project.box_uv || Cube.selected.length == 0) return this; - var scope = this; - var sides = this.getMappingOverlay(); - - $(scope.jquery.size).find('.mapping_overlay_cube').remove(); - scope.jquery.size.append(sides); - - return this; - }, - getMappingOverlay(cube, absolute) { - return this; - var scope = this; - var sides = document.createElement('div'); - sides.classList.add('mapping_overlay_cube'); - var pixels = scope.getPixelSize(); - if (!cube) cube = Cube.selected[0]; - function addElement(x, y, width, height, n, color) { - if (absolute) { - x += cube.uv_offset[0]; - y += cube.uv_offset[1]; - } - x *= pixels; - y *= pixels; - width = limitNumber(width *pixels + x, 0, scope.inner_width) - x; - height = limitNumber(height*pixels + y, 0, scope.inner_height)- y; - - let face = document.createElement('div'); - face.classList.add('uv_mapping_overlay'); - face.style.left = x+'px'; face.style.top = y+'px'; - face.style.height = height+'px'; face.style.width = width+'px'; - face.style.background = color; - face.dataset.sizes = [x/pixels, y/pixels, width/pixels, height/pixels].map(v => Math.round(v)).join(','); - sides.append(face); - } - var size = cube.size(undefined, true); - - sides.setAttribute('size_hash', `${cube.uv_offset[0]}_${cube.uv_offset[1]}_${size[0]}_${size[1]}_${size[2]}`) - - addElement(size[2], 0, size[0], size[2], '#b4d4e1', '#ecf8fd') - addElement(size[2]+size[0], 0, size[0], size[2], '#536174', '#6e788c') - addElement(0, size[2], size[2], size[1], '#43e88d', '#7BFFA3') - addElement(size[2], size[2], size[0], size[1], '#5bbcf4', '#7BD4FF') - addElement(size[2]+size[0], size[2], size[2], size[1], '#f48686', '#FFA7A4') - addElement(2*size[2]+size[0], size[2], size[0], size[1],'#f8dd72', '#FFF899') - - return sides; - }, - /* - displayAllMappingOverlays(force_reload) { - var scope = this; - var cycle = 'C'+bbuid(4) - if (this.showing_overlays && Project.box_uv) { - Cube.all.forEach(cube => { - var size = cube.size(undefined, true) - var hash = `${cube.uv_offset[0]}_${cube.uv_offset[1]}_${size[0]}_${size[1]}_${size[2]}` - if (scope.jquery.frame[0].querySelector(`:scope > .mapping_overlay_cube.${cycle}[size_hash="${hash}"]`)) return; - - var c = scope.jquery.frame[0].querySelector(`:scope > .mapping_overlay_cube:not(.${cycle})[size_hash="${hash}"]`) - if (force_reload || !c) { - var sides = scope.getMappingOverlay(cube, true) - sides.classList.add(cycle) - scope.jquery.frame.append(sides) - } else { - c.classList.add(cycle) - } - }) - $(`.mapping_overlay_cube:not(.${cycle})`).remove() - $('.mapping_overlay_cube').removeClass(cycle) - } else { - $(scope.jquery.frame).find('.mapping_overlay_cube').remove() - } - }, - updateAllMappingOverlays() { - var scope = this; - var pixels = scope.getPixelSize(); - if (this.showing_overlays) { - Cube.all.forEach(cube => { - var size = cube.size(undefined, true) - var hash = `${cube.uv_offset[0]}_${cube.uv_offset[1]}_${size[0]}_${size[1]}_${size[2]}` - var c = scope.jquery.frame[0].querySelector(`:scope > .mapping_overlay_cube[size_hash="${hash}"]`); - - if (c) { - c.childNodes.forEach(side => { - var data = side.dataset.sizes; - data = data.split(','); - data.forEach((s, i) => { - data[i] = parseInt(s); - }) - side.style.left = (data[0] * pixels)+'px'; - side.style.top = (data[1] * pixels)+'px'; - side.style.width = (data[2] * pixels)+'px'; - side.style.height = (data[3] * pixels)+'px'; - }) - } - }) - } - },*/ - //UI displaySliders() { if (!Cube.selected.length) return; this.sliders.pos_x.update() this.sliders.pos_y.update() this.sliders.size_x.update() this.sliders.size_y.update() + let face = this.getReferenceFace(); + BarItems.uv_rotation.set((face && face.rotation)||0) }, displayTools() { //Cullface @@ -1032,28 +831,11 @@ const UVEditor = { BarItems.face_tint.setIcon(face.tint !== -1 ? 'check_box' : 'check_box_outline_blank') BarItems.slider_face_tint.update() }, - updateDragHandle() { - var pos = this.jquery.size.position() - var handle = this.jquery.size.find('div.uv_size_handle').get(0); - if (!handle) return; - - var left = limitNumber(this.vue.$refs.viewport.scrollLeft, 0, this.size*(this.zoom-1)) - pos.left; - var top = limitNumber(this.vue.$refs.viewport.scrollTop, 0, (this.height||this.size)*(this.zoom-1)) - pos.top; - handle.style.left = left +'px'; - handle.style.top = top +'px'; - - handle.style.width = this.size + 'px'; - handle.style.height = (this.height||this.size) + 'px'; - return this; - }, - updateInterface() { - this.jquery.size.resizable('option', 'disabled', Project.box_uv) - }, - contextMenu() { + contextMenu(event) { var scope = this; - this.reference_face = Cube.selected[0] && Cube.selected[0].faces[scope.face]; - this.menu.open(event, this) - return this; + UVEditor.getReferenceFace() = Cube.selected[0] && Cube.selected[0].faces[scope.face]; + UVEditor.menu.open(event, UVEditor) + return UVEditor; }, slidePos(modify, axis) { var scope = this @@ -1139,7 +921,7 @@ const UVEditor = { maximize(event) { var scope = this; this.forCubes(obj => { - scope.getFaces(event).forEach(function(side) { + scope.getFaces(obj, event).forEach(function(side) { obj.faces[side].uv = [0, 0, scope.getResolution(0, obj.faces[side]), scope.getResolution(1, obj.faces[side])] }) obj.autouv = 0 @@ -1151,7 +933,7 @@ const UVEditor = { turnMapping(event) { var scope = this; this.forCubes(obj => { - scope.getFaces(event).forEach(function(side) { + scope.getFaces(obj, event).forEach(function(side) { var uv = obj.faces[side].uv_size; obj.faces[side].uv_size = [uv[1], uv[0]]; }) @@ -1166,7 +948,7 @@ const UVEditor = { var top2, left2; this.forCubes(obj => { - scope.getFaces(event).forEach(function(side) { + scope.getFaces(obj, event).forEach(function(side) { let face = obj.faces[side]; let mirror_x = face.uv[0] > face.uv[2]; let mirror_y = face.uv[1] > face.uv[3]; @@ -1200,7 +982,7 @@ const UVEditor = { setRelativeAutoSize(event) { var scope = this; this.forCubes(obj => { - scope.getFaces(event).forEach(function(side) { + scope.getFaces(obj, event).forEach(function(side) { var uv = obj.faces[side].uv, ru = scope.getResolution(0, obj.faces[side]), rv = scope.getResolution(1, obj.faces[side]); @@ -1268,7 +1050,7 @@ const UVEditor = { mirrorX(event) { var scope = this; this.forCubes(obj => { - scope.getFaces(event).forEach(function(side) { + scope.getFaces(obj, event).forEach(function(side) { var proxy = obj.faces[side].uv[0] obj.faces[side].uv[0] = obj.faces[side].uv[2] obj.faces[side].uv[2] = proxy @@ -1282,7 +1064,7 @@ const UVEditor = { mirrorY(event) { var scope = this; this.forCubes(obj => { - scope.getFaces(event).forEach(function(side) { + scope.getFaces(obj, event).forEach(function(side) { var proxy = obj.faces[side].uv[1] obj.faces[side].uv[1] = obj.faces[side].uv[3] obj.faces[side].uv[3] = proxy @@ -1309,7 +1091,7 @@ const UVEditor = { var scope = this; Undo.initEdit({elements: Cube.selected, uv_only: true}) this.forCubes(obj => { - scope.getFaces(event).forEach(function(side) { + scope.getFaces(obj, event).forEach(function(side) { obj.faces[side].uv = [0, 0, 0, 0] obj.faces[side].texture = null; }) @@ -1383,7 +1165,7 @@ const UVEditor = { autoCullface(event) { var scope = this; this.forCubes(obj => { - scope.getFaces(event).forEach(function(side) { + scope.getFaces(obj, event).forEach(function(side) { obj.faces[side].cullface = side }) }) @@ -1391,10 +1173,8 @@ const UVEditor = { this.message('uv_editor.auto_cull') }, copy(event) { - this.select() if (Cube.selected.length === 0) return; - var scope = this; UVEditor.clipboard = [] if (Project.box_uv) { @@ -1428,7 +1208,6 @@ const UVEditor = { this.message('uv_editor.copied_x', [UVEditor.clipboard.length]) }, paste(event) { - this.select() if (UVEditor.clipboard === null || Cube.selected.length === 0) return; Undo.initEdit({elements: Cube.selected, uv_only: true}) @@ -1451,7 +1230,7 @@ const UVEditor = { }) } - if (this.id === 'UVEditor' && event) { + if (event) { if (event.shiftKey) { UVEditor.cube_faces.forEach(function(s) { applyFace(UVEditor.clipboard[0], s) @@ -1465,22 +1244,6 @@ const UVEditor = { }) } } - } else { - if (UVEditor.selection.length === 1) { - applyFace(UVEditor.clipboard[0], UVEditor.selection[0]) - } else { - if (UVEditor.clipboard.length === 1) { - UVEditor.selection.forEach(function(s) { - applyFace(UVEditor.clipboard[0], s) - }) - } else { - UVEditor.clipboard.forEach(function(s) { - if (UVEditor.selection.includes(s.face)) { - applyFace(s) - } - }) - } - } } this.loadData() Canvas.updateSelectedFaces() @@ -1490,7 +1253,7 @@ const UVEditor = { reset(event) { var scope = this; this.forCubes(obj => { - scope.getFaces(event).forEach(function(side) { + scope.getFaces(obj, event).forEach(function(side) { obj.faces[side].reset() }) Canvas.adaptObjectFaces(obj) @@ -1501,29 +1264,11 @@ const UVEditor = { }, // Dialog - - isSetup: false, clipboard: null, cube_faces: ['north', 'south', 'west', 'east', 'up', 'down'], - selection: [], - selection_all: [], - all_editors: [], - hoveredSide: false, - single_size: {}, - all_size: {}, - select: function(id, event) { - if (event.shiftKey || Pressing.overrides.shift) { - UVEditor.selection.push(id) - } else { - if (UVEditor.selection.includes(id) && UVEditor.selection.length === 1) { - UVEditor.selection = [] - } else { - UVEditor.selection = [id] - } - } - UVEditor.updateSelection() - }, - forSelection: function(cb, event, ...args) { + forSelection(cb, event, ...args) { + UVEditor[cb](...args); + /* if (open_dialog === false) { UVEditor[cb](event, ...args) } else if (UVEditor.single) { @@ -1538,79 +1283,59 @@ const UVEditor = { UVEditor.editors[s][cb](...args) }) } - } + }*/ }, - copy: function(event) { - if (Cube.selected.length === 0) return; + /* + copy(event) { + + let element = UVEditor.getMappableElements()[0] + if (!element) return; UVEditor.clipboard = [] function addToClipboard(face) { - var tag = Cube.selected[0].faces[face] - UVEditor.clipboard.push(new Face(null, tag)) - } - if (UVEditor.hoveredSide) { - addToClipboard(UVEditor.hoveredSide) - UVEditor.editors[UVEditor.hoveredSide].message('uv_editor.copied') - - } else if (UVEditor.single) { - addToClipboard(UVEditor.editors.single.face) - UVEditor.editors.single.message('uv_editor.copied') - - } else if (UVEditor.selection.length > 0) { - UVEditor.selection.forEach(function(s) { - addToClipboard(s) - UVEditor.editors[s].message('uv_editor.copied') - }) - } else { - UVEditor.cube_faces.forEach(function(s) { - addToClipboard(s) - UVEditor.editors[s].message('uv_editor.copied') - }) + var tag = element.faces[face] + if (tag && element instanceof Cube) { + UVEditor.clipboard.push(new Face(null, tag)) + } else if (tag && element instanceof Mesh) { + UVEditor.clipboard.push(new MeshFace(null, tag)) + } } + UVEditor.vue.selected_faces.forEach(function(s) { + addToClipboard(s) + UVEditor.message('uv_editor.copied') + }) }, - paste: function(event) { + paste(event) { if (UVEditor.clipboard === null || Cube.selected.length === 0) return; function applyFace(tag, face) { if (!face) face = tag.face - Cube.selected.forEach(function(obj) { - obj.faces[face].extend(tag) - Canvas.updateUV(obj) + UVEditor.getMappableElements().forEach(function(obj) { + if (obj.faces[face]) { + obj.faces[face].extend(tag); + Canvas.updateUV(obj); + } }) } - if (UVEditor.hoveredSide) { - UVEditor.editors[UVEditor.hoveredSide].paste({shiftKey: false}) - - } else if (UVEditor.selection.length === 1) { - applyFace(UVEditor.clipboard[0], UVEditor.selection[0]) - if (UVEditor.single) { - UVEditor.editors.single.message('uv_editor.pasted') - } else { - UVEditor.editors[UVEditor.selection[0]].message('uv_editor.pasted') - } + if (UVEditor.vue.selected_faces.length === 1) { + applyFace(UVEditor.clipboard[0], UVEditor.vue.selected_faces[0]) } else { if (UVEditor.clipboard.length === 1) { - UVEditor.selection.forEach(function(s) { + UVEditor.vue.selected_faces.forEach(function(s) { applyFace(UVEditor.clipboard[0], s) - UVEditor.editors[s].message('uv_editor.pasted') }) } else { UVEditor.clipboard.forEach(function(s) { - if (UVEditor.selection.includes(s.face)) { + if (UVEditor.vue.selected_faces.includes(s.face)) { applyFace(s) - UVEditor.editors[s].message('uv_editor.pasted') } }) } } - - for (var key in UVEditor.editors) { - if (UVEditor.editors[key]) { - UVEditor.editors[key].loadData() - } - } - }, + UVEditor.message('uv_editor.pasted') + UVEditor.loadData() + },*/ menu: new Menu([ @@ -1624,9 +1349,9 @@ const UVEditor = { 'copy', 'paste', {icon: 'photo_size_select_large', name: 'menu.uv.mapping', condition: () => !Project.box_uv, children: function(editor) { return [ - {icon: editor.reference_face.enabled!==false ? 'check_box' : 'check_box_outline_blank', name: 'generic.export', click: function(editor) { + {icon: UVEditor.getReferenceFace().enabled!==false ? 'check_box' : 'check_box_outline_blank', name: 'generic.export', click: function() { Undo.initEdit({elements: Cube.selected, uv_only: true}) - editor.toggleUV(event) + UVEditor.toggleUV(event) Undo.finishEdit('Toggle UV export') }}, 'uv_maximize', @@ -1636,91 +1361,92 @@ const UVEditor = { var off = 'radio_button_unchecked' var on = 'radio_button_checked' return [ - {icon: (!editor.reference_face.rotation ? on : off), name: '0°', click: function(editor) { + {icon: (!UVEditor.getReferenceFace().rotation ? on : off), name: '0°', click: function() { Undo.initEdit({elements: Cube.selected, uv_only: true}) - editor.setRotation(0) + UVEditor.setRotation(0) Undo.finishEdit('Rotate UV') }}, - {icon: (editor.reference_face.rotation === 90 ? on : off), name: '90°', click: function(editor) { + {icon: (UVEditor.getReferenceFace().rotation === 90 ? on : off), name: '90°', click: function() { Undo.initEdit({elements: Cube.selected, uv_only: true}) - editor.setRotation(90) + UVEditor.setRotation(90) Undo.finishEdit('Rotate UV') }}, - {icon: (editor.reference_face.rotation === 180 ? on : off), name: '180°', click: function(editor) { + {icon: (UVEditor.getReferenceFace().rotation === 180 ? on : off), name: '180°', click: function() { Undo.initEdit({elements: Cube.selected, uv_only: true}) - editor.setRotation(180) + UVEditor.setRotation(180) Undo.finishEdit('Rotate UV') }}, - {icon: (editor.reference_face.rotation === 270 ? on : off), name: '270°', click: function(editor) { + {icon: (UVEditor.getReferenceFace().rotation === 270 ? on : off), name: '270°', click: function() { Undo.initEdit({elements: Cube.selected, uv_only: true}) - editor.setRotation(270) + UVEditor.setRotation(270) Undo.finishEdit('Rotate UV') }} ] }}, 'uv_turn_mapping', { - icon: (editor.reference_face.uv[0] > editor.reference_face.uv[2] ? 'check_box' : 'check_box_outline_blank'), + icon: (UVEditor.getReferenceFace().uv[0] > UVEditor.getReferenceFace().uv[2] ? 'check_box' : 'check_box_outline_blank'), name: 'menu.uv.mapping.mirror_x', - click: function(editor) { + click: function() { Undo.initEdit({elements: Cube.selected, uv_only: true}) - editor.mirrorX(event) + UVEditor.mirrorX(event) Undo.finishEdit('Mirror UV') } }, { - icon: (editor.reference_face.uv[1] > editor.reference_face.uv[3] ? 'check_box' : 'check_box_outline_blank'), + icon: (UVEditor.getReferenceFace().uv[1] > UVEditor.getReferenceFace().uv[3] ? 'check_box' : 'check_box_outline_blank'), name: 'menu.uv.mapping.mirror_y', - click: function(editor) { + click: function() { Undo.initEdit({elements: Cube.selected, uv_only: true}) - editor.mirrorY(event) + UVEditor.mirrorY(event) Undo.finishEdit('Mirror UV') } }, ]}}, 'face_tint', - {icon: 'flip_to_back', condition: () => Format.id == 'java_block', name: 'action.cullface', children: function(editor) { + {icon: 'flip_to_back', condition: () => (Format.id == 'java_block'&& Cube.selected.length), name: 'action.cullface' , children: function() { var off = 'radio_button_unchecked'; var on = 'radio_button_checked'; function setCullface(cullface) { Undo.initEdit({elements: Cube.selected, uv_only: true}) - editor.forCubes(obj => { - obj.faces[editor.face].cullface = cullface; + UVEditor.forCubes(obj => { + obj.faces[UVEditor.face].cullface = cullface; }) Undo.finishEdit(cullface ? `Set cullface to ${cullface}` : 'Disable cullface'); } return [ - {icon: (!editor.reference_face.cullface ? on : off), name: 'uv_editor.no_faces', click: () => setCullface('')}, - {icon: (editor.reference_face.cullface == 'north' ? on : off), name: 'face.north', click: () => setCullface('north')}, - {icon: (editor.reference_face.cullface == 'south' ? on : off), name: 'face.south', click: () => setCullface('south')}, - {icon: (editor.reference_face.cullface == 'west' ? on : off), name: 'face.west', click: () => setCullface('west')}, - {icon: (editor.reference_face.cullface == 'east' ? on : off), name: 'face.east', click: () => setCullface('east')}, - {icon: (editor.reference_face.cullface == 'up' ? on : off), name: 'face.up', click: () => setCullface('up')}, - {icon: (editor.reference_face.cullface == 'down' ? on : off), name: 'face.down', click: () => setCullface('down')}, + {icon: (!UVEditor.getReferenceFace().cullface ? on : off), name: 'uv_editor.no_faces', click: () => setCullface('')}, + {icon: (UVEditor.getReferenceFace().cullface == 'north' ? on : off), name: 'face.north', click: () => setCullface('north')}, + {icon: (UVEditor.getReferenceFace().cullface == 'south' ? on : off), name: 'face.south', click: () => setCullface('south')}, + {icon: (UVEditor.getReferenceFace().cullface == 'west' ? on : off), name: 'face.west', click: () => setCullface('west')}, + {icon: (UVEditor.getReferenceFace().cullface == 'east' ? on : off), name: 'face.east', click: () => setCullface('east')}, + {icon: (UVEditor.getReferenceFace().cullface == 'up' ? on : off), name: 'face.up', click: () => setCullface('up')}, + {icon: (UVEditor.getReferenceFace().cullface == 'down' ? on : off), name: 'face.down', click: () => setCullface('down')}, 'auto_cullface' ] }}, {icon: 'collections', name: 'menu.uv.texture', condition: () => !Project.box_uv, children: function() { var arr = [ - {icon: 'crop_square', name: 'menu.cube.texture.blank', click: function(editor, event) { - Undo.initEdit({elements: Cube.selected}) - Cube.selected.forEach((obj) => { - editor.getFaces(event).forEach(function(side) { + {icon: 'crop_square', name: 'menu.cube.texture.blank', click: function(context, event) { + let elements = UVEditor.vue.mappable_elements; + Undo.initEdit({elements}) + elements.forEach((obj) => { + UVEditor.getFaces(obj, event).forEach(function(side) { obj.faces[side].texture = false; }) Canvas.adaptObjectFaces(obj) }) - editor.loadData() - editor.message('uv_editor.reset') + UVEditor.loadData() + UVEditor.message('uv_editor.reset') Undo.initEdit('texture blank') }}, - {icon: 'clear', name: 'menu.cube.texture.transparent', click: function(editor) {editor.clear(event)}}, + {icon: 'clear', name: 'menu.cube.texture.transparent', click: function() {UVEditor.clear(event)}}, ] Texture.all.forEach(function(t) { arr.push({ name: t.name, icon: (t.mode === 'link' ? t.img : t.source), - click: function(editor) {editor.applyTexture(t.uuid)} + click: function() {UVEditor.applyTexture(t.uuid)} }) }) return arr; @@ -1935,12 +1661,11 @@ BARS.defineActions(function() { new Toggle('toggle_uv_overlay', { - condition: () => Project.box_uv, + //condition: () => Project.box_uv, icon: 'view_quilt', category: 'uv', onChange(value) { - //UVEditor.showing_overlays = value; - //UVEditor.displayAllMappingOverlays(); + UVEditor.vue.showing_overlays = value; } }) }) @@ -1970,8 +1695,10 @@ Interface.definePanels(function() { project_resolution: [16, 16], elements: [], + all_elements: [], selected_vertices: {}, selected_faces: [], + showing_overlays: false, face_names: { north: tl('face.north'), @@ -1987,10 +1714,22 @@ Interface.definePanels(function() { return this.width * this.zoom; }, inner_height() { - return this.width * (this.project_resolution[0] / this.project_resolution[1]) * this.zoom; + return this.width * (this.project_resolution[1] / this.project_resolution[0]) * this.zoom; }, mappable_elements() { return this.elements.filter(element => element.faces); + }, + all_mappable_elements() { + return this.all_elements.filter(element => element.faces); + } + }, + watch: { + project_resolution: { + deep: true, + handler() { + let min_zoom = Math.min(1, this.inner_width/this.inner_height); + if (this.zoom < min_zoom) this.zoom = 1; + } } }, methods: { @@ -2002,6 +1741,7 @@ Interface.definePanels(function() { let old_size = this.width; let size = Math.floor(Math.clamp(UVEditor.panel.width - 10, 64, 1e5)); this.width = size; + this.height = size * Math.clamp(this.project_resolution[1] / this.project_resolution[0], 0.5, 1); this.$refs.viewport.scrollLeft = Math.round(this.$refs.viewport.scrollLeft * (size / old_size)); this.$refs.viewport.scrollTop = Math.round(this.$refs.viewport.scrollTop * (size / old_size)); @@ -2044,7 +1784,7 @@ Interface.definePanels(function() { var n = (event.deltaY < 0) ? 0.1 : -0.1; n *= this.zoom - var number = limitNumber(this.zoom + n, 0.5, this.max_zoom) + var number = Math.clamp(this.zoom + n, Math.min(1, this.inner_width/this.inner_height), this.max_zoom) let old_zoom = this.zoom; this.zoom = number; @@ -2066,7 +1806,6 @@ Interface.definePanels(function() { let {viewport} = this.$refs; let coords = {x: 0, y: 0} function dragMouseWheel(e2) { - console.log() viewport.scrollLeft -= (e2.pageX - coords.x) viewport.scrollTop -= (e2.pageY - coords.y) coords = {x: e2.pageX, y: e2.pageY} @@ -2099,17 +1838,26 @@ Interface.definePanels(function() { } else { this.selected_faces.replace([key]); } + UVEditor.vue.updateTexture() + }, + selectCube(cube, event) { + if (!this.dragging_uv) { + cube.select(event); + } + UVEditor.vue.updateTexture() }, reverseSelect(event) { - let dragging_not_clicking// todo - var offset = $(this.$refs.frame).offset(); event.offsetX = event.clientX - offset.left; event.offsetY = event.clientY - offset.top; - if (!dragging_not_clicking) { - UVEditor.reverseSelect(event) + if (!this.dragging_uv && event.target.id == 'uv_frame') { + let results = UVEditor.reverseSelect(event) + if (!(results && results.length)) { + if (!this.box_uv) { + this.selected_faces.empty(); + } + } } - dragging_not_clicking = false; }, dragFace(face_key, event) { if (event.which == 2 || event.which == 3) return; @@ -2161,6 +1909,7 @@ Interface.definePanels(function() { UVEditor.loadData(); UVEditor.vue.$forceUpdate(); Canvas.updateView({elements: scope.mappable_elements, element_aspects: {uv: true}}); + scope.dragging_uv = true; } function stop(e1) { @@ -2168,12 +1917,14 @@ Interface.definePanels(function() { removeEventListeners(document, 'mouseup touchend', stop); UVEditor.disableAutoUV() Undo.finishEdit('Move UV') + setTimeout(() => scope.dragging_uv = false, 10); } addEventListeners(document, 'mousemove touchmove', drag); addEventListeners(document, 'mouseup touchend', stop); }, resizeFace(face_key, event, x_side, y_side) { if (event.which == 2 || event.which == 3) return; + event.stopPropagation(); let scope = this; let elements = this.mappable_elements; Undo.initEdit({elements, uv_only: true}) @@ -2212,6 +1963,7 @@ Interface.definePanels(function() { UVEditor.loadData(); UVEditor.vue.$forceUpdate(); Canvas.updateView({elements: scope.mappable_elements, element_aspects: {uv: true}}); + scope.dragging_uv = true; } function stop() { @@ -2219,11 +1971,13 @@ Interface.definePanels(function() { removeEventListeners(document, 'mouseup touchend', stop); UVEditor.disableAutoUV() Undo.finishEdit('Resize UV') + setTimeout(() => scope.dragging_uv = false, 10); } addEventListeners(document, 'mousemove touchmove', drag); addEventListeners(document, 'mouseup touchend', stop); }, + /* openFaceMenu(event) { let faces = []; this.mappable_elements.forEach(element => { @@ -2241,7 +1995,7 @@ Interface.definePanels(function() { } }) new Menu(faces).open(this.$refs.seleced_faces) - }, + },*/ toPixels(uv_coord, offset = 0) { return (uv_coord / this.project_resolution[0] * this.inner_width + offset) + 'px' @@ -2261,10 +2015,10 @@ Interface.definePanels(function() { -
- +
+
  • + {{ face_names[key] }} +
  • -
    +
    -