Add Erase Mode toggle for Fill and Shape tool

Closes #618
This commit is contained in:
JannisX11 2021-08-07 13:51:00 +02:00
parent 8c7fa5b8ce
commit d12247bf3d
3 changed files with 51 additions and 3 deletions

View File

@ -1860,10 +1860,14 @@ const BARS = {
'slider_brush_opacity', 'slider_brush_opacity',
'slider_brush_softness', 'slider_brush_softness',
'mirror_painting', 'mirror_painting',
'color_erase_mode',
'lock_alpha', 'lock_alpha',
'painting_grid', 'painting_grid',
] ]
}) })
Blockbench.onUpdateTo('4.0', () => {
Toolbars.brush.add(BarItems.color_erase_mode, -3);
})
Toolbars.vertex_snap = new Toolbar({ Toolbars.vertex_snap = new Toolbar({
id: 'vertex_snap', id: 'vertex_snap',
children: [ children: [

View File

@ -5,6 +5,7 @@ const Painter = {
selection: {}, selection: {},
mirror_painting: false, mirror_painting: false,
lock_alpha: false, lock_alpha: false,
erase_mode: false,
edit(texture, cb, options) { edit(texture, cb, options) {
if (!options.no_undo) { if (!options.no_undo) {
Undo.initEdit({textures: [texture], bitmap: true}) Undo.initEdit({textures: [texture], bitmap: true})
@ -352,12 +353,16 @@ const Painter = {
var color = tinycolor(ColorPanel.get()).toRgb(); var color = tinycolor(ColorPanel.get()).toRgb();
let b_opacity = BarItems.slider_brush_opacity.get()/100; let b_opacity = BarItems.slider_brush_opacity.get()/100;
let tool = Toolbox.selected.id;
let {rect, uvFactorX, uvFactorY, w, h} = area; let {rect, uvFactorX, uvFactorY, w, h} = area;
ctx.fillStyle = tinycolor(ColorPanel.get()).setAlpha(b_opacity).toRgbString(); ctx.fillStyle = tinycolor(ColorPanel.get()).setAlpha(b_opacity).toRgbString();
if (Painter.erase_mode && (fill_mode === 'cube' || fill_mode === 'face')) {
ctx.globalAlpha = b_opacity;
ctx.globalCompositeOperation = 'destination-out'
}
var fill_mode = BarItems.fill_mode.get() var fill_mode = BarItems.fill_mode.get()
var cube = Painter.current.cube; var cube = Painter.current.cube;
if (cube && fill_mode === 'cube') { if (cube && fill_mode === 'cube') {
@ -416,7 +421,16 @@ const Painter = {
b: px[2], b: px[2],
a: px[3]/255 a: px[3]/255
} }
var result_color = Painter.combineColors(pxcolor, color, b_opacity); var result_color = pxcolor;
if (!Painter.erase_mode) {
result_color = Painter.combineColors(pxcolor, color, b_opacity);
} else if (!Painter.lock_alpha) {
if (b_opacity == 1) {
result_color.r = result_color.g = result_color.b = result_color.a = 0;
} else {
result_color.a = Math.clamp(result_color.a * (1-b_opacity), 0, 1);
}
}
px[0] = result_color.r px[0] = result_color.r
px[1] = result_color.g px[1] = result_color.g
px[2] = result_color.b px[2] = result_color.b
@ -424,6 +438,8 @@ const Painter = {
} }
}) })
} }
ctx.globalAlpha = 1.0;
ctx.globalCompositeOperation = 'source-over'
}, },
runMirrorBrush(texture, x, y, event, uvTag) { runMirrorBrush(texture, x, y, event, uvTag) {
if (uvTag && Painter.current.cube) { if (uvTag && Painter.current.cube) {
@ -534,6 +550,11 @@ const Painter = {
diff_y = diff_y>0 ? clamp : -clamp; diff_y = diff_y>0 ? clamp : -clamp;
} }
if (Painter.erase_mode) {
ctx.globalAlpha = b_opacity;
ctx.globalCompositeOperation = 'destination-out'
}
if (shape === 'rectangle') { if (shape === 'rectangle') {
ctx.strokeStyle = ctx.fillStyle = tinycolor(ColorPanel.get()).setAlpha(b_opacity).toRgbString(); ctx.strokeStyle = ctx.fillStyle = tinycolor(ColorPanel.get()).setAlpha(b_opacity).toRgbString();
ctx.lineWidth = width; ctx.lineWidth = width;
@ -551,7 +572,16 @@ const Painter = {
Painter.modifyCanvasSection(ctx, rect[0], rect[1], w, h, (changePixel) => { Painter.modifyCanvasSection(ctx, rect[0], rect[1], w, h, (changePixel) => {
//changePixel(0, 0, editPx) //changePixel(0, 0, editPx)
function editPx(pxcolor) { function editPx(pxcolor) {
return Painter.combineColors(pxcolor, color, b_opacity); if (!Painter.erase_mode) {
return Painter.combineColors(pxcolor, color, b_opacity);
} else {
if (b_opacity == 1) {
pxcolor.r = pxcolor.g = pxcolor.b = pxcolor.a = 0;
} else {
pxcolor.a = Math.clamp(pxcolor.a * (1-b_opacity), 0, 1);
}
return pxcolor;
}
} }
if (hollow) { if (hollow) {
let r_min = Math.trunc(-width/2); let r_min = Math.trunc(-width/2);
@ -609,6 +639,8 @@ const Painter = {
}) })
} }
//Painter.editing_area = undefined; //Painter.editing_area = undefined;
ctx.globalAlpha = 1.0;
ctx.globalCompositeOperation = 'source-over';
}, {no_undo: true, use_cache: true}); }, {no_undo: true, use_cache: true});
}, },
@ -1064,6 +1096,16 @@ BARS.defineActions(function() {
} }
} }
}) })
new Toggle('color_erase_mode', {
icon: 'remove_circle',
category: 'paint',
condition: {
tools: ['fill_tool', 'draw_shape_tool']
},
onChange: function (value) {
Painter.erase_mode = value;
}
})
new Toggle('lock_alpha', { new Toggle('lock_alpha', {
icon: 'fas.fa-chess-board', icon: 'fas.fa-chess-board',
category: 'paint', category: 'paint',

View File

@ -695,6 +695,8 @@
"action.draw_shape_type.ellipse": "Ellipse", "action.draw_shape_type.ellipse": "Ellipse",
"action.draw_shape_type.ellipse_h": "Ellipse (Hollow)", "action.draw_shape_type.ellipse_h": "Ellipse (Hollow)",
"action.draw_shape_type.line": "Line", "action.draw_shape_type.line": "Line",
"action.color_erase_mode": "Erase Mode",
"action.color_erase_mode.desc": "With erase mode enabled, tools like Fill and Rectangle subtract colors rather than adding them",
"action.mirror_painting": "Mirror Painting", "action.mirror_painting": "Mirror Painting",
"action.mirror_painting.description": "Mirror your paint strokes to the other side of the model", "action.mirror_painting.description": "Mirror your paint strokes to the other side of the model",
"action.lock_alpha": "Lock Alpha Channel", "action.lock_alpha": "Lock Alpha Channel",