mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-02-17 16:20:13 +08:00
parent
c68023c6d4
commit
56ef236edc
@ -743,6 +743,9 @@ class NumSlider extends Widget {
|
||||
this.value = trimFloatNumber(value)
|
||||
} else {
|
||||
|
||||
}
|
||||
if (this.tool_setting) {
|
||||
Toolbox.selected.tool_settings[this.tool_setting] = value;
|
||||
}
|
||||
this.jq_outer.find('.nslide:not(.editing)').text(this.value)
|
||||
if (this.settings && this.settings.show_bar) {
|
||||
@ -2154,6 +2157,7 @@ const BARS = {
|
||||
'slider_brush_opacity',
|
||||
'slider_brush_softness',
|
||||
'brush_shape',
|
||||
'blend_mode',
|
||||
'mirror_painting',
|
||||
'color_erase_mode',
|
||||
'lock_alpha',
|
||||
@ -2165,6 +2169,7 @@ const BARS = {
|
||||
})
|
||||
Blockbench.onUpdateTo('4.4', () => {
|
||||
Toolbars.brush.add(BarItems.brush_shape, 5);
|
||||
Toolbars.brush.add(BarItems.blend_mode, 6);
|
||||
})
|
||||
Toolbars.vertex_snap = new Toolbar({
|
||||
id: 'vertex_snap',
|
||||
|
@ -287,6 +287,7 @@ const Settings = {
|
||||
new Setting('color_wheel', {category: 'paint', value: false, onChange(value) {
|
||||
Interface.Panels.color.vue.picker_type = value ? 'wheel' : 'box';
|
||||
}});
|
||||
new Setting('pick_color_opacity', {category: 'paint', value: false});
|
||||
new Setting('paint_side_restrict', {category: 'paint', value: true});
|
||||
// TODO: implement paint with stylus only into paint tools
|
||||
new Setting('paint_with_stylus_only', {category: 'paint', value: false});
|
||||
|
@ -111,6 +111,15 @@ const Painter = {
|
||||
var y = (e.offsetY - bg_pos[1]) * pixel_ratio
|
||||
if (x >= 0 && y >= 0 && x < preview.background.imgtag.width && y < preview.background.imgtag.height) {
|
||||
let color = Painter.getPixelColor(ctx, x, y);
|
||||
if (settings.pick_color_opacity.value) {
|
||||
let opacity = Math.floor(color.getAlpha()*256);
|
||||
for (let id in BarItems) {
|
||||
let tool = BarItems[id];
|
||||
if (tool.tool_settings && tool.tool_settings.brush_opacity) {
|
||||
tool.tool_settings.brush_opacity = opacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
ColorPanel.set(color);
|
||||
}
|
||||
}
|
||||
@ -376,10 +385,22 @@ const Painter = {
|
||||
// Custom area
|
||||
} else if (shape == 'square') {
|
||||
Painter.editSquare(ctx, x, y, size, softness, function(pxcolor, local_opacity, px, py) {
|
||||
if (Painter.current.face_matrices[Painter.current.face] && settings.paint_side_restrict.value) {
|
||||
let matrix = Painter.current.face_matrices[Painter.current.face];
|
||||
if (!matrix[Math.floor(px)] || !matrix[Math.floor(px)][Math.floor(py)]) {
|
||||
return pxcolor;
|
||||
}
|
||||
}
|
||||
return tool.brush.changePixel(px, py, pxcolor, local_opacity, {color, opacity: b_opacity, ctx, x, y, size, softness, texture, event});
|
||||
})
|
||||
} else if (shape == 'circle') {
|
||||
Painter.editCircle(ctx, x, y, size, softness, function(pxcolor, local_opacity, px, py) {
|
||||
if (Painter.current.face_matrices[Painter.current.face] && settings.paint_side_restrict.value) {
|
||||
let matrix = Painter.current.face_matrices[Painter.current.face];
|
||||
if (!matrix[Math.floor(px)] || !matrix[Math.floor(px)][Math.floor(py)]) {
|
||||
return pxcolor;
|
||||
}
|
||||
}
|
||||
return tool.brush.changePixel(px, py, pxcolor, local_opacity, {color, opacity: b_opacity, ctx, x, y, size, softness, texture, event});
|
||||
})
|
||||
}
|
||||
@ -845,6 +866,15 @@ const Painter = {
|
||||
colorPicker(texture, x, y) {
|
||||
var ctx = Painter.getCanvas(texture).getContext('2d')
|
||||
let color = Painter.getPixelColor(ctx, x, y);
|
||||
if (settings.pick_color_opacity.value) {
|
||||
let opacity = Math.floor(color.getAlpha()*256);
|
||||
for (let id in BarItems) {
|
||||
let tool = BarItems[id];
|
||||
if (tool.tool_settings && tool.tool_settings.brush_opacity) {
|
||||
tool.tool_settings.brush_opacity = opacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
ColorPanel.set(color);
|
||||
},
|
||||
// Util
|
||||
@ -858,7 +888,7 @@ const Painter = {
|
||||
added.a = added.a*opacity
|
||||
|
||||
var mix = {};
|
||||
mix.a = limitNumber(1 - (1 - added.a) * (1 - base.a), 0, 1); // alpha
|
||||
mix.a = Math.clamp(1 - (1 - added.a) * (1 - base.a), 0, 1); // alpha
|
||||
mix.r = Math.round((added.r * added.a / mix.a) + (base.r * base.a * (1 - added.a) / mix.a)); // red
|
||||
mix.g = Math.round((added.g * added.a / mix.a) + (base.g * base.a * (1 - added.a) / mix.a)); // green
|
||||
mix.b = Math.round((added.b * added.a / mix.a) + (base.b * base.a * (1 - added.a) / mix.a)); // blue
|
||||
@ -866,6 +896,67 @@ const Painter = {
|
||||
added.a = original_a
|
||||
return mix;
|
||||
},
|
||||
blendColors(base, added, opacity, blend_mode) {
|
||||
if (Math.isNumber(base)) base = Jimp.intToRGBA(base)
|
||||
if (Math.isNumber(added)) added = Jimp.intToRGBA(added)
|
||||
|
||||
var original_a = added.a
|
||||
added.a = added.a*opacity
|
||||
|
||||
var mix = {};
|
||||
mix.a = Math.clamp(1 - (1 - added.a) * (1 - base.a), 0, 1); // alpha
|
||||
|
||||
['r', 'g', 'b'].forEach(ch => {
|
||||
let normal_base = base[ch] / 255;
|
||||
let normal_added = added[ch] / 255;
|
||||
if (base.a == 0) normal_base = normal_added;
|
||||
|
||||
switch (blend_mode) {
|
||||
|
||||
case 'behind':
|
||||
mix[ch] = (normal_base * base.a / mix.a) + (normal_added * added.a * (1 - base.a) / mix.a);
|
||||
break;
|
||||
|
||||
case 'color':
|
||||
mix[ch] = ((normal_base / normal_added) * added.a) + (normal_base * (1-added.a));
|
||||
break;
|
||||
|
||||
case 'multiply':
|
||||
mix[ch] = ((normal_base * normal_added) * added.a) + (normal_base * (1-added.a));
|
||||
break;
|
||||
|
||||
case 'divide':
|
||||
mix[ch] = ((normal_base / normal_added) * added.a) + (normal_base * (1-added.a));
|
||||
break;
|
||||
|
||||
case 'add':
|
||||
mix[ch] = ((normal_base + normal_added) * added.a) + (normal_base * (1-added.a));
|
||||
break;
|
||||
|
||||
case 'subtract':
|
||||
mix[ch] = ((normal_base - normal_added) * added.a) + (normal_base * (1-added.a));
|
||||
break;
|
||||
|
||||
// Todo: Equations for remaining blend modes
|
||||
case 'screen':
|
||||
mix[ch] = ((normal_base / normal_added) * added.a) + (normal_base * (1-added.a));
|
||||
break;
|
||||
|
||||
case 'hard_light':
|
||||
mix[ch] = ((normal_base / normal_added) * added.a) + (normal_base * (1-added.a));
|
||||
break;
|
||||
|
||||
case 'difference':
|
||||
mix[ch] = ((normal_base - normal_added) * added.a) + (normal_base * (1-added.a));
|
||||
break;
|
||||
|
||||
}
|
||||
mix[ch] = Math.clamp(Math.round(255 * mix[ch]), 0, 255);
|
||||
})
|
||||
|
||||
added.a = original_a
|
||||
return mix;
|
||||
},
|
||||
getMirrorElement(element) {
|
||||
let center = Format.centered_grid ? 0 : 8;
|
||||
let e = 0.01
|
||||
@ -1127,23 +1218,31 @@ BARS.defineActions(function() {
|
||||
opacity: true,
|
||||
offset_even_radius: true,
|
||||
changePixel(px, py, pxcolor, local_opacity, {color, opacity, ctx, x, y, size, softness, texture, event}) {
|
||||
if (Painter.current.face_matrices[Painter.current.face] && settings.paint_side_restrict.value) {
|
||||
let matrix = Painter.current.face_matrices[Painter.current.face];
|
||||
if (!matrix[Math.floor(px)] || !matrix[Math.floor(px)][Math.floor(py)]) {
|
||||
return pxcolor;
|
||||
}
|
||||
}
|
||||
let blend_mode = BarItems.blend_mode.value;
|
||||
var a = opacity * local_opacity;
|
||||
var before = Painter.getAlphaMatrix(texture, px, py)
|
||||
Painter.setAlphaMatrix(texture, px, py, a);
|
||||
if (a > before) {
|
||||
a = (a - before) / (1 - before);
|
||||
} else if (before) {
|
||||
a = 0;
|
||||
|
||||
if (blend_mode == 'set_opacity') {
|
||||
console.log(a)
|
||||
if (Painter.lock_alpha && pxcolor.a == 0) return pxcolor;
|
||||
return {r: color.r, g: color.g, b: color.b, a}
|
||||
|
||||
} else {
|
||||
var before = Painter.getAlphaMatrix(texture, px, py)
|
||||
Painter.setAlphaMatrix(texture, px, py, a);
|
||||
if (a > before) {
|
||||
a = (a - before) / (1 - before);
|
||||
} else if (before) {
|
||||
a = 0;
|
||||
}
|
||||
let result_color;
|
||||
if (blend_mode == 'default') {
|
||||
result_color = Painter.combineColors(pxcolor, color, a);
|
||||
} else {
|
||||
result_color = Painter.blendColors(pxcolor, color, a, blend_mode);
|
||||
}
|
||||
if (Painter.lock_alpha) result_color.a = pxcolor.a
|
||||
return result_color;
|
||||
}
|
||||
var result_color = Painter.combineColors(pxcolor, color, a);
|
||||
if (Painter.lock_alpha) result_color.a = pxcolor.a
|
||||
return result_color;
|
||||
}
|
||||
},
|
||||
allowed_view_modes: ['textured'],
|
||||
@ -1308,8 +1407,10 @@ BARS.defineActions(function() {
|
||||
modes: ['paint'],
|
||||
condition: {modes: ['paint']},
|
||||
keybind: new Keybind({key: 'm'}),
|
||||
onCanvasClick() {
|
||||
Blockbench.showQuickMessage('message.copy_paste_tool_viewport')
|
||||
onCanvasClick(data) {
|
||||
if (data && data.element) {
|
||||
Blockbench.showQuickMessage('message.copy_paste_tool_viewport')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -1341,6 +1442,23 @@ BARS.defineActions(function() {
|
||||
ellipse_h: {name: true, icon: 'radio_button_unchecked'},
|
||||
}
|
||||
})
|
||||
new BarSelect('blend_mode', {
|
||||
category: 'paint',
|
||||
condition: () => (Toolbox && ((Toolbox.selected.brush?.blend_modes) || ['draw_shape_tool'].includes(Toolbox.selected.id))),
|
||||
options: {
|
||||
default: true,
|
||||
set_opacity: true,
|
||||
color: true,
|
||||
behind: true,
|
||||
multiply: true,
|
||||
divide: true,
|
||||
add: true,
|
||||
subtract: true,
|
||||
overlay: true,
|
||||
hard_light: true,
|
||||
difference: true,
|
||||
}
|
||||
})
|
||||
new BarSelect('fill_mode', {
|
||||
category: 'paint',
|
||||
condition: () => Toolbox && Toolbox.selected.id === 'fill_tool',
|
||||
|
File diff suppressed because one or more lines are too long
14
lang/en.json
14
lang/en.json
@ -763,6 +763,8 @@
|
||||
"settings.sync_color.desc": "Synchronize the color between different Blockbench instances",
|
||||
"settings.color_wheel": "Color Wheel",
|
||||
"settings.color_wheel.desc": "Use the color wheel as the main color picker",
|
||||
"settings.pick_color_opacity": "Pick Color Opacity",
|
||||
"settings.pick_color_opacity.desc": "Pick the color opacity with the Color Picker and set it as brush opacity",
|
||||
"settings.paint_side_restrict": "Restrict Brush to Side",
|
||||
"settings.paint_side_restrict.desc": "Restrict brushes to only paint on the current side",
|
||||
"settings.paint_with_stylus_only": "Paint with Stylus Only",
|
||||
@ -874,6 +876,18 @@
|
||||
"action.slider_brush_softness": "Softness",
|
||||
"action.slider_brush_softness.desc": "Softness of the brush in percent",
|
||||
"action.brush_shape": "Brush Shape",
|
||||
"action.blend_mode": "Blend Mode",
|
||||
"action.blend_mode.default": "Default",
|
||||
"action.blend_mode.set_opacity": "Set Opacity",
|
||||
"action.blend_mode.color": "Color",
|
||||
"action.blend_mode.behind": "Behind",
|
||||
"action.blend_mode.multiply": "Multiply",
|
||||
"action.blend_mode.divide": "Divide",
|
||||
"action.blend_mode.add": "Add",
|
||||
"action.blend_mode.subtract": "Subtract",
|
||||
"action.blend_mode.overlay": "Overlay",
|
||||
"action.blend_mode.hard_light": "Hard Light",
|
||||
"action.blend_mode.difference": "Difference",
|
||||
|
||||
"action.uv_slider_pos_x": "Move Horizontal",
|
||||
"action.uv_slider_pos_x.desc": "Move the UV selection of all selected cubes horizontally",
|
||||
|
Loading…
Reference in New Issue
Block a user