Make texture editing tools work with selections

Selection fixes
This commit is contained in:
JannisX11 2023-10-28 23:18:25 +02:00
parent 05fc5561db
commit de47f418bf
3 changed files with 72 additions and 28 deletions

View File

@ -22,9 +22,11 @@ BARS.defineActions(function() {
texture.edit((canvas) => {
let ctx = canvas.getContext('2d');
texture.selection.maskCanvas(ctx);
ctx.clearRect(0, 0, texture.width, texture.height);
ctx.filter = 'invert(1)';
ctx.drawImage(texture.img, 0, 0);
ctx.restore();
}, {no_undo: true});
})
@ -59,6 +61,7 @@ BARS.defineActions(function() {
textures.forEach((texture, i) => {
texture.edit((canvas) => {
let ctx = canvas.getContext('2d');
texture.selection.maskCanvas(ctx);
ctx.clearRect(0, 0, texture.width, texture.height);
if (this.preview_changes) {
ctx.filter = `brightness(${this.brightness / 100}) contrast(${this.contrast / 100})`;
@ -66,6 +69,7 @@ BARS.defineActions(function() {
ctx.filter = `brightness(1.0) contrast(1.0)`;
}
ctx.drawImage(original_imgs[i], 0, 0);
ctx.restore();
let ref_ctx = this.$refs.canvas[i].getContext('2d');
ref_ctx.clearRect(0, 0, texture.width, texture.height);
@ -147,6 +151,7 @@ BARS.defineActions(function() {
textures.forEach((texture, i) => {
texture.edit((canvas) => {
let ctx = canvas.getContext('2d');
texture.selection.maskCanvas(ctx);
ctx.clearRect(0, 0, texture.width, texture.height);
if (this.preview_changes) {
ctx.filter = `saturate(${this.saturation / 100}) hue-rotate(${this.hue}deg)`;
@ -154,6 +159,7 @@ BARS.defineActions(function() {
ctx.filter = `brightness(1.0)`;
}
ctx.drawImage(original_imgs[i], 0, 0);
ctx.restore();
let ref_ctx = this.$refs.canvas[i].getContext('2d');
ref_ctx.clearRect(0, 0, texture.width, texture.height);
@ -511,6 +517,7 @@ BARS.defineActions(function() {
textures.forEach((texture, i) => {
texture.edit((canvas) => {
let ctx = canvas.getContext('2d');
texture.selection.maskCanvas(ctx);
ctx.clearRect(0, 0, texture.width, texture.height);
if (this.preview_changes) {
ctx.filter = `opacity(${this.opacity}%)`;
@ -523,6 +530,7 @@ BARS.defineActions(function() {
ctx.filter = `opacity(100%)`;
ctx.drawImage(original_imgs[i], 0, 0);
}
ctx.restore();
let ref_ctx = this.$refs.canvas[i].getContext('2d');
ref_ctx.clearRect(0, 0, texture.width, texture.height);
@ -589,7 +597,7 @@ BARS.defineActions(function() {
palette[color] = tinycolor(color);
})
Painter.scanCanvas(ctx, 0, 0, canvas.width, canvas.height, (x, y, pixel) => {
if (!texture.selection.allow(x, y)) return;
if (pixel[3] < 4) return;
let smallest_distance = Infinity;
let nearest_color = null;

View File

@ -198,9 +198,10 @@ const Painter = {
face_matrices: {}
}
Painter.startPixel = [x, y];
Painter.current.clear.width = texture.width;
Painter.current.clear.height = texture.height;
Painter.current.clear.getContext('2d').drawImage(texture.img, 0, 0);
let {canvas} = texture.getActiveCanvas();
Painter.current.clear.width = canvas.width;
Painter.current.clear.height = canvas.height;
Painter.current.clear.getContext('2d').drawImage(canvas, 0, 0);
} else {
Painter.current.face_matrices = {};
@ -843,9 +844,6 @@ const Painter = {
function drawShape(start_x, start_y, x, y, uvTag) {
var rect = Painter.setupRectFromFace(uvTag, texture);
var [w, h] = [rect[2] - rect[0], rect[3] - rect[1]]
let diff_x = x - start_x;
let diff_y = y - start_y;
@ -864,7 +862,16 @@ const Painter = {
ctx.globalCompositeOperation = Painter.getBlendModeCompositeOperation();
}
if (shape === 'rectangle') {
if (uvTag) {
let rect = Painter.setupRectFromFace(uvTag, texture);
let [w, h] = [rect[2] - rect[0], rect[3] - rect[1]];
ctx.beginPath();
ctx.rect(rect[0], rect[1], w, h);
} else {
texture.selection.maskCanvas(ctx);
}
ctx.strokeStyle = ctx.fillStyle = tinycolor(ColorPanel.get()).setAlpha(b_opacity).toRgbString();
ctx.lineWidth = width;
ctx.beginPath();
@ -878,6 +885,8 @@ const Painter = {
ctx.fill();
}
} else if (shape === 'ellipse') {
let rect = Painter.setupRectFromFace(uvTag, texture);
let [w, h] = [rect[2] - rect[0], rect[3] - rect[1]];
Painter.modifyCanvasSection(ctx, rect[0], rect[1], w, h, (changePixel) => {
//changePixel(0, 0, editPx)
function editPx(pxcolor) {
@ -1006,8 +1015,6 @@ const Painter = {
}
function drawGradient(start_x, start_y, x, y, uvTag) {
let rect = Painter.setupRectFromFace(uvTag, texture);
var [w, h] = [rect[2] - rect[0], rect[3] - rect[1]];
let diff_x = x - start_x;
let diff_y = y - start_y;
@ -1044,10 +1051,20 @@ const Painter = {
gradient.addColorStop(0, tinycolor(ColorPanel.get()).setAlpha(b_opacity).toRgbString());
gradient.addColorStop(1, tinycolor(ColorPanel.get()).setAlpha(0).toRgbString());
ctx.beginPath();
if (uvTag) {
let rect = Painter.setupRectFromFace(uvTag, texture);
let [w, h] = [rect[2] - rect[0], rect[3] - rect[1]];
ctx.beginPath();
ctx.rect(rect[0], rect[1], w, h);
} else {
texture.selection.maskCanvas(ctx);
let rect = texture.selection.getBoundingRect(true);
ctx.rect(rect.start_x, rect.start_y, rect.width, rect.height);
console.log(rect)
}
ctx.fillStyle = gradient;
ctx.rect(rect[0], rect[1], w, h);
ctx.fill();
ctx.restore();
return [diff_x, diff_y];
}
@ -1301,11 +1318,12 @@ const Painter = {
a: data[3]/256
})
},
modifyCanvasSection(ctx, x, y, w, h, cb) {
modifyCanvasSection(ctx, x, y, w, h, cb, texture) {
var arr = ctx.getImageData(x, y, w, h)
var processed = [];
cb((px, py, editPx) => {
if (UVEditor.texture && !UVEditor.texture.selection.allow(px, py)) {;return;}
//changePixel
px = Math.floor(px)-x;
py = Math.floor(py)-y;
@ -1699,16 +1717,16 @@ class IntMatrix {
getDirect(x, y) {
return this.array[y * this.width + x];
}
getBoundingRect() {
getBoundingRect(respect_empty) {
let rect = new Rectangle();
if (this.override == true) {
if (this.override == true || (respect_empty && this.override == false)) {
rect.width = this.width;
rect.height = this.height;
} else if (this.override == null) {
let min_x = Infinity;
let min_y = Infinity;
let max_x = -Infinity;
let max_y = -Infinity;
let min_x = this.width;
let min_y = this.height;
let max_x = 0;
let max_y = 0;
this.forEachPixel((x, y, value) => {
if (!value) return;
min_x = Math.min(min_x, x);
@ -1716,7 +1734,13 @@ class IntMatrix {
max_x = Math.max(max_x, x+1);
max_y = Math.max(max_y, y+1);
})
rect.fromCoords(min_x, min_y, max_x, max_y);
if (min_x == this.width) {
// No pixel selected
rect.width = this.width;
rect.height = this.height;
} else {
rect.fromCoords(min_x, min_y, max_x, max_y);
}
}
return rect;
}
@ -1795,6 +1819,17 @@ class IntMatrix {
})
this.array = new_array;
}
maskCanvas(ctx) {
if (!this.is_custom) return;
ctx.save();
ctx.beginPath();
this.forEachPixel((x, y, value) => {
if (!value) return;
ctx.rect(x, y, 1, 1);
});
ctx.closePath();
ctx.clip();
}
}
SharedActions.add('copy', {
@ -2423,8 +2458,8 @@ BARS.defineActions(function() {
options: {
rectangle: {name: true, icon: 'fas.fa-square'},
rectangle_h: {name: true, icon: 'far.fa-square'},
ellipse: {name: true, icon: 'circle'},
ellipse_h: {name: true, icon: 'radio_button_unchecked'},
ellipse: {name: true, icon: 'fas.fa-circle'},
ellipse_h: {name: true, icon: 'far.fa-circle'},
}
})
new BarSelect('blend_mode', {

View File

@ -117,6 +117,7 @@ const UVEditor = {
selection_outline_lines: [],
async updateSelectionOutline(recalculate_lines = true) {
if (!Modes.paint) return;
let {texture} = this.vue;
if (!texture) {
this.vue.selection_outline = '';
@ -1442,9 +1443,9 @@ SharedActions.add('select_all', {
}
})
SharedActions.add('select_all', {
condition: () => Prop.active_panel == 'uv' && Modes.paint && Texture.selected,
condition: () => Prop.active_panel == 'uv' && Modes.paint && UVEditor.texture,
run() {
Texture.selected.selection.setOverride(Texture.selected.selection.override == true ? false : true);
UVEditor.texture.selection.setOverride(UVEditor.texture.selection.override == true ? false : true);
UVEditor.updateSelectionOutline();
}
})
@ -1456,16 +1457,16 @@ SharedActions.add('unselect_all', {
}
})
SharedActions.add('unselect_all', {
condition: () => Prop.active_panel == 'uv' && Modes.paint,
condition: () => Prop.active_panel == 'uv' && Modes.paint && UVEditor.texture,
run() {
Texture.selected.selection.setOverride(false);
UVEditor.texture.selection.setOverride(false);
UVEditor.updateSelectionOutline();
}
})
SharedActions.add('invert_selection', {
condition: () => Prop.active_panel == 'uv' && Modes.paint && Texture.selected,
condition: () => Prop.active_panel == 'uv' && Modes.paint && UVEditor.texture,
run() {
let texture = Texture.selected;
let texture = UVEditor.texture;
if (texture.selection.is_custom) {
texture.selection.forEachPixel((x, y, val, index) => {
texture.selection.array[index] = val ? 0 : 1;
@ -3856,7 +3857,7 @@ Interface.definePanels(function() {
<div class="ellipse" v-if="texture_selection_rect.ellipse" />
</div>
<svg id="uv_selection_outline">
<svg id="uv_selection_outline" v-if="mode == 'paint'">
<path :d="selection_outline" />
<path :d="selection_outline" class="dash_overlay" />
</svg>