From c4265189bde33c5df8859d96f5c295d43ebcd82d Mon Sep 17 00:00:00 2001 From: JannisX11 Date: Thu, 19 Aug 2021 15:18:01 +0200 Subject: [PATCH] New UV editor progress --- css/panels.css | 43 +++++++++- js/blockbench.js | 3 + js/io/project.js | 6 +- js/texturing/uv.js | 197 ++++++++++++++++++++++++++++++++------------- 4 files changed, 188 insertions(+), 61 deletions(-) diff --git a/css/panels.css b/css/panels.css index dc29e7a1..37f7e3f2 100644 --- a/css/panels.css +++ b/css/panels.css @@ -1114,6 +1114,7 @@ #uv_viewport { height: 320px; width: 320px; + margin: auto; position: relative; overflow: hidden; } @@ -1176,10 +1177,14 @@ .cube_uv_face { position: absolute; z-index: 1; + width: var(--width); + height: var(--height); cursor: move; - border: 2px solid var(--color-grid); + border: 2px solid var(--color-text); box-sizing: border-box; background-color: rgba(50, 70, 240, 0.14); + text-align: center; + color: var(--color-subtle_text); } .cube_uv_face:hover { border-color: var(--color-light); @@ -1188,6 +1193,42 @@ } .cube_uv_face.selected { border-color: var(--color-accent); + z-index: 3; + } + + .uv_resize_side { + position: absolute; + top: 0; + left: 0; + } + .uv_resize_side.horizontal { + cursor: n-resize; + height: 6px; + margin-top: -4px; + } + .uv_resize_side.vertical { + cursor: w-resize; + width: 6px; + margin-left: -4px; + } + .uv_resize_corner { + position: absolute; + margin: -6px; + height: 8px; + width: 8px; + background-color: var(--color-text); + z-index: 3; + } + .uv_resize_corner.uv_c_nw {cursor: nw-resize;} + .uv_resize_corner.uv_c_ne {cursor: ne-resize;} + .uv_resize_corner.uv_c_sw {cursor: sw-resize;} + .uv_resize_corner.uv_c_se {cursor: se-resize;} + + #uv_seleced_faces { + display: flex; + } + #uv_seleced_faces li { + padding: 0 5px; } /* #uv_size { diff --git a/js/blockbench.js b/js/blockbench.js index 168d4b38..748278f6 100644 --- a/js/blockbench.js +++ b/js/blockbench.js @@ -156,6 +156,9 @@ function updateSelection(options = {}) { function selectAll() { if (Modes.animate) { selectAllKeyframes() + } else if (Prop.active_panel == 'uv') { + UVEditor.selectAll() + } else if (Modes.edit || Modes.paint) { if (Outliner.selected.length < Outliner.elements.length) { if (Outliner.root.length == 1) { diff --git a/js/io/project.js b/js/io/project.js index 801f6fbc..ec29633a 100644 --- a/js/io/project.js +++ b/js/io/project.js @@ -58,7 +58,7 @@ class ModelProject { get texture_height() {return this._texture_height} set texture_width(n) { n = parseInt(n)||16 - Vue.nextTick(updateProjectResolution) + if (this.selected) Vue.nextTick(updateProjectResolution) this._texture_width = n; } get optional_box_uv() { @@ -66,7 +66,7 @@ class ModelProject { } set texture_height(n) { n = parseInt(n)||16 - Vue.nextTick(updateProjectResolution) + if (this.selected) Vue.nextTick(updateProjectResolution) this._texture_height = n; } get name() { @@ -174,6 +174,7 @@ class ModelProject { UVEditor.vue.elements = this.selected_elements; UVEditor.vue.selected_vertices = this.selected_vertices; UVEditor.vue.selected_faces = this.selected_faces; + UVEditor.vue.box_uv = this.box_uv; Interface.Panels.textures.inside_vue.textures = Texture.all; scene.add(this.model_3d); @@ -202,6 +203,7 @@ class ModelProject { setProjectTitle(this.name); setStartScreen(!Project); updateInterface(); + updateProjectResolution(); Vue.nextTick(() => { loadTextureDraggable(); }) diff --git a/js/texturing/uv.js b/js/texturing/uv.js index 22f3dbdc..66f2a3d3 100644 --- a/js/texturing/uv.js +++ b/js/texturing/uv.js @@ -711,6 +711,7 @@ const UVEditor = { } matches.forEach(s => { selected.safePush(s) + console.log(s.size(), face_match) }); updateSelection(); } @@ -1046,10 +1047,6 @@ const UVEditor = { return this; }, updateInterface() { - for (var key in this.sliders) { - var slider = this.sliders[key] - slider.node.style.setProperty('display', BARS.condition(slider.condition)?'block':'none') - } this.jquery.size.resizable('option', 'disabled', Project.box_uv) }, contextMenu() { @@ -1092,8 +1089,7 @@ const UVEditor = { Canvas.updateUV(obj) }) this.displaySliders() - this.displayFrame() - this.disableAutoUV() + this.vue.$forceUpdate() }, slideSize(modify, axis) { var scope = this @@ -1109,14 +1105,25 @@ const UVEditor = { } }) this.displaySliders() - this.displayFrame() this.disableAutoUV() + this.vue.$forceUpdate() }, getResolution(axis, texture) { return axis ? Project.texture_height : Project.texture_width; }, //Events + selectAll() { + let selected_before = this.vue.selected_faces.length; + this.vue.mappable_elements.forEach(element => { + for (let key in element.faces) { + this.vue.selected_faces.safePush(key); + } + }) + if (selected_before == this.vue.selected_faces.length) { + this.vue.selected_faces.empty(); + } + }, disableAutoUV() { this.forCubes(obj => { obj.autouv = 0 @@ -1492,16 +1499,10 @@ const UVEditor = { this.loadData() this.message('uv_editor.reset') }, - select() { - if (UVEditor.cube_faces.includes(this.id) === false) return; - UVEditor.selection = [this.id] - UVEditor.updateSelection() - }, // Dialog isSetup: false, - single: false, clipboard: null, cube_faces: ['north', 'south', 'west', 'east', 'up', 'down'], selection: [], @@ -1522,18 +1523,6 @@ const UVEditor = { } UVEditor.updateSelection() }, - selectAll: function() { - if (UVEditor.selection.length === 6) { - UVEditor.selection.empty() - } else { - UVEditor.selection = UVEditor.cube_faces.slice() - } - UVEditor.updateSelection() - }, - selectNone: function() { - UVEditor.selection = [] - UVEditor.updateSelection() - }, forSelection: function(cb, event, ...args) { if (open_dialog === false) { UVEditor[cb](event, ...args) @@ -1785,9 +1774,7 @@ BARS.defineActions(function() { }, onChange: function(slider) { var value = slider.get().replace(/x/, ''); - UVEditor.all_editors.forEach(editor => { - editor.setGrid(value); - }); + UVEditor.setGrid(value); } }) /* @@ -1979,7 +1966,7 @@ Interface.definePanels(function() { height: 320, zoom: 1, checkerboard: settings.uv_checkerboard.value, - texture: '', + texture: 0, project_resolution: [16, 16], elements: [], @@ -2018,9 +2005,11 @@ Interface.definePanels(function() { 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)); - /*for (var id in UVEditor.sliders) { - UVEditor.sliders[id].setWidth(size/(Project.box_uv?2:4)-1) - }*/ + for (var id in UVEditor.sliders) { + var slider = UVEditor.sliders[id]; + slider.setWidth(size/(Project.box_uv?2:4)-1) + slider.node.style.setProperty('display', BARS.condition(slider.condition)?'block':'none') + } }, setMode(mode) { this.mode = mode; @@ -2040,12 +2029,11 @@ Interface.definePanels(function() { } } if (texture == null) { - this.texture = null; - UVEditor.texture = null; + this.texture = UVEditor.texture = null; } else if (texture instanceof Texture) { - this.texture = (!texture.error || texture.error == 2) ? texture.source : ''; + this.texture = texture; } else { - this.texture = ''; + this.texture = UVEditor.texture = 0; } }, onMouseWheel(event) { @@ -2099,8 +2087,10 @@ Interface.definePanels(function() { contextMenu(event) { UVEditor.menu.open(event); }, - selectFace(key, event, element) { - if (event.shiftKey || event.ctrlOrCmd || Pressing.overrides.shift || Pressing.overrides.ctrl) { + selectFace(key, event, keep_selection) { + if (keep_selection && this.selected_faces.includes(key)) { + + } else if (event.shiftKey || event.ctrlOrCmd || Pressing.overrides.shift || Pressing.overrides.ctrl) { if (this.selected_faces.includes(key)) { this.selected_faces.remove(key); } else { @@ -2123,6 +2113,8 @@ Interface.definePanels(function() { }, dragFace(face_key, event) { if (event.which == 2 || event.which == 3) return; + + this.selectFace(face_key, event, true); let scope = this; let elements = this.mappable_elements; Undo.initEdit({elements, uv_only: true}) @@ -2155,8 +2147,8 @@ Interface.definePanels(function() { let step_x = (scope.inner_width / UVEditor.getResolution(0) / UVEditor.grid); let step_y = (scope.inner_height / UVEditor.getResolution(1) / UVEditor.grid); - pos[0] = Math.round((e1.clientX - event.clientX) / step_x); - pos[1] = Math.round((e1.clientY - event.clientY) / step_y); + pos[0] = Math.round((e1.clientX - event.clientX) / step_x) / UVEditor.grid; + pos[1] = Math.round((e1.clientY - event.clientY) / step_y) / UVEditor.grid; if (pos[0] != last_pos[0] || pos[1] != last_pos[1]) { @@ -2165,18 +2157,10 @@ Interface.definePanels(function() { }) last_pos.replace(pos); } - /* - 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); - p.left = Math.round(p.left / step_x) * step_x; - p.top = Math.round(p.top / step_y) * step_y;*/ UVEditor.displaySliders(); UVEditor.loadData(); UVEditor.vue.$forceUpdate(); + Canvas.updateView({elements: scope.mappable_elements, element_aspects: {uv: true}}); } function stop(e1) { @@ -2188,11 +2172,86 @@ Interface.definePanels(function() { 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; + let scope = this; + let elements = this.mappable_elements; + Undo.initEdit({elements, uv_only: true}) + + let pos = [0, 0]; + let last_pos = [0, 0]; + let offset = function(element, x, y) { + scope.selected_faces.forEach(key => { + if (element.faces[key] && element instanceof Cube) { + if (x_side == -1) element.faces[key].uv[0] += x; + if (y_side == -1) element.faces[key].uv[1] += y; + if (x_side == 1) element.faces[key].uv[2] += x; + if (y_side == 1) element.faces[key].uv[3] += y; + } + }) + element.uv_offset[0] += x; + element.uv_offset[1] += y; + } + + function drag(e1) { + + let step_x = (scope.inner_width / UVEditor.getResolution(0) / UVEditor.grid); + let step_y = (scope.inner_height / UVEditor.getResolution(1) / UVEditor.grid); + + pos[0] = Math.round((e1.clientX - event.clientX) / step_x) / UVEditor.grid; + pos[1] = Math.round((e1.clientY - event.clientY) / step_y) / UVEditor.grid; + + if (pos[0] != last_pos[0] || pos[1] != last_pos[1]) { + + elements.forEach(element => { + offset(element, pos[0] - last_pos[0], pos[1] - last_pos[1]) + }) + last_pos.replace(pos); + } + UVEditor.displaySliders(); + UVEditor.loadData(); + UVEditor.vue.$forceUpdate(); + Canvas.updateView({elements: scope.mappable_elements, element_aspects: {uv: true}}); + } + + function stop() { + removeEventListeners(document, 'mousemove touchmove', drag); + removeEventListeners(document, 'mouseup touchend', stop); + UVEditor.disableAutoUV() + Undo.finishEdit('Resize UV') + } + addEventListeners(document, 'mousemove touchmove', drag); + addEventListeners(document, 'mouseup touchend', stop); + }, + + openFaceMenu(event) { + let faces = []; + this.mappable_elements.forEach(element => { + for (let key in element.faces) { + if (faces.find(item => item.id == key)) continue; + faces.push({ + id: key, + name: this.face_names[key], + icon: this.selected_faces.includes(key) ? 'check_box' : 'check_box_outline_blank', + click: () => { + this.selected_faces.splice(0, Infinity, key); + //UVEditor.loadData() + } + }) + } + }) + 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' } }, + /* + Extra Info + Selected Faces + Pointer Coords + */ template: `
@@ -2202,6 +2261,12 @@ Interface.definePanels(function() {
+
+ +
+
+
@@ -2239,7 +2320,7 @@ Interface.definePanels(function() {
- +
@@ -2268,12 +2349,12 @@ Interface.definePanels(function() { UVEditor.sliders.pos_x = new NumSlider({ id: 'uv_slider_pos_x', private: true, - condition: function() {return true}, + condition: () => UVEditor.vue.selected_faces.length, get: function() { if (Project.box_uv && Cube.selected[0]) { return trimFloatNumber(Cube.selected[0].uv_offset[0]) } else if (Cube.selected[0]) { - var face_uv = Cube.selected[0].faces[UVEditor.face].uv + var face_uv = Cube.selected[0].faces[UVEditor.vue.selected_faces[0]].uv if (face_uv) { return trimFloatNumber(face_uv[0]) } @@ -2291,12 +2372,12 @@ Interface.definePanels(function() { UVEditor.sliders.pos_y = new NumSlider({ id: 'uv_slider_pos_y', private: true, - condition: function() {return true}, + condition: () => UVEditor.vue.selected_faces.length, get: function() { if (Project.box_uv && Cube.selected[0]) { return trimFloatNumber(Cube.selected[0].uv_offset[1]) } else if (Cube.selected[0]) { - var face_uv = Cube.selected[0].faces[UVEditor.face].uv + var face_uv = Cube.selected[0].faces[UVEditor.vue.selected_faces[0]].uv if (face_uv) { return trimFloatNumber(face_uv[1]) } @@ -2314,7 +2395,7 @@ Interface.definePanels(function() { UVEditor.sliders.size_x = new NumSlider({ id: 'uv_slider_size_x', private: true, - condition: function() {return !Project.box_uv}, + condition: () => (!Project.box_uv && Cube.selected[0]), get: function() { if (!Project.box_uv && Cube.selected[0]) { var face_uv = Cube.selected[0].faces[UVEditor.face].uv @@ -2335,7 +2416,7 @@ Interface.definePanels(function() { UVEditor.sliders.size_y = new NumSlider({ id: 'uv_slider_size_y', private: true, - condition: function() {return !Project.box_uv}, + condition: () => (!Project.box_uv && Cube.selected[0]), get: function() { if (!Project.box_uv && Cube.selected[0]) { var face_uv = Cube.selected[0].faces[UVEditor.face].uv