Add fill masks

This commit is contained in:
luboslenco
2020-09-02 13:38:20 +02:00
parent d36304f805
commit b2b898709b
14 changed files with 185 additions and 75 deletions
+36 -2
View File
@@ -119,7 +119,19 @@ class History {
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
var lay = undoLayers[undoI];
Context.layer.swap(lay);
Context.layer.material_mask = Project.materials[step.material];
Context.layer.fill_layer = Project.materials[step.material];
}
else if (step.name == tr("To Fill Mask")) {
Context.layer.toPaintMask();
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
var lay = undoLayers[undoI];
Context.layer.swapMask(lay);
}
else if (step.name == tr("To Paint Mask")) {
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
var lay = undoLayers[undoI];
Context.layer.swapMask(lay);
Context.layer.fill_mask = Project.materials[step.material];
}
else if (step.name == tr("Layer Opacity")) {
Context.setLayer(Project.layers[step.layer]);
@@ -212,7 +224,7 @@ class History {
else if (step.name == tr("To Fill Layer")) {
var lay = undoLayers[undoI];
Context.layer.swap(lay);
Context.layer.material_mask = Project.materials[step.material];
Context.layer.fill_layer = Project.materials[step.material];
undoI = (undoI + 1) % Config.raw.undo_steps;
}
else if (step.name == tr("To Paint Layer")) {
@@ -221,6 +233,18 @@ class History {
Context.layer.swap(lay);
undoI = (undoI + 1) % Config.raw.undo_steps;
}
else if (step.name == tr("To Fill Mask")) {
var lay = undoLayers[undoI];
Context.layer.swapMask(lay);
Context.layer.fill_mask = Project.materials[step.material];
undoI = (undoI + 1) % Config.raw.undo_steps;
}
else if (step.name == tr("To Paint Mask")) {
Context.layer.toPaintMask();
var lay = undoLayers[undoI];
Context.layer.swapMask(lay);
undoI = (undoI + 1) % Config.raw.undo_steps;
}
else if (step.name == tr("Layer Opacity")) {
Context.setLayer(Project.layers[step.layer]);
var t = Context.layer.maskOpacity;
@@ -322,6 +346,16 @@ class History {
push(tr("To Paint Layer"));
}
public static function toFillMask() {
copyToUndo(Context.layer.id, undoI, true);
push(tr("To Fill Mask"));
}
public static function toPaintMask() {
copyToUndo(Context.layer.id, undoI, true);
push(tr("To Paint Mask"));
}
public static function layerOpacity() {
push(tr("Layer Opacity"));
}
+45 -25
View File
@@ -387,7 +387,8 @@ class Layers {
public static function isFillMaterial(): Bool {
if (UIHeader.inst.worktab.position == SpaceMaterial) return true;
var m = Context.material;
for (l in Project.layers) if (l.material_mask == m) return true;
for (l in Project.layers) if (l.fill_layer == m) return true;
for (l in Project.layers) if (l.fill_mask == m) return true;
return false;
}
@@ -423,37 +424,56 @@ class Layers {
return;
}
var first = true;
for (l in layers) {
if (l.material_mask == Context.material) {
if (first) {
current = @:privateAccess kha.graphics4.Graphics2.current;
if (current != null) current.end();
Context.pdirty = fills;
Context.layerIsMask = false;
Context.tool = ToolFill;
}
var hasFillLayer = false;
var hasFillMask = false;
for (l in layers) if (l.fill_layer == Context.material) hasFillLayer = true;
for (l in layers) if (l.fill_mask == Context.material) hasFillMask = true;
Context.layer = l;
setObjectMask();
if (hasFillLayer || hasFillMask) {
if (first) {
MakeMaterial.parsePaintMaterial();
first = false;
}
current = @:privateAccess kha.graphics4.Graphics2.current;
if (current != null) current.end();
Context.pdirty = fills;
Context.tool = ToolFill;
// Decal layer
if (l.uvType == UVProject) {
l.clearLayer();
}
if (hasFillLayer) {
Context.layerIsMask = false;
MakeMaterial.parsePaintMaterial();
for (i in 0...fills) {
RenderPathPaint.commandsPaint();
for (l in layers) {
if (l.fill_layer == Context.material) {
Context.layer = l;
setObjectMask();
// Decal layer
if (l.uvType == UVProject) {
l.clearLayer();
}
for (i in 0...fills) {
RenderPathPaint.commandsPaint();
}
}
}
}
if (hasFillMask) {
Context.layerIsMask = true;
MakeMaterial.parsePaintMaterial();
for (l in layers) {
trace(Std.random(100));
if (l.fill_mask == Context.material) {
Context.layer = l;
setObjectMask();
for (i in 0...fills) {
RenderPathPaint.commandsPaint();
}
}
}
}
}
if (!first) {
Context.pdirty = 0;
Context.ddirty = 2;
Context.rdirty = 2;
+2 -1
View File
@@ -29,7 +29,8 @@ typedef TLayerData = {
public var uv_rot: Float;
public var uv_type: Int;
public var opacity_mask: Float;
public var material_mask: Int;
public var fill_layer: Int;
public var fill_mask: Int;
public var object_mask: Int;
public var blending: Int;
public var parent: Int;
+26 -4
View File
@@ -25,7 +25,8 @@ class LayerSlot {
public var texpaint_mask: Image = null; // Texture mask
public var texpaint_mask_preview: Image;
public var maskOpacity = 1.0; // Opacity mask
public var material_mask: MaterialSlot = null; // Fill layer
public var fill_layer: MaterialSlot = null;
public var fill_mask: MaterialSlot = null;
public var show_panel = false;
public var blending = BlendMix;
@@ -310,7 +311,7 @@ class LayerSlot {
l.visible = visible;
l.maskOpacity = maskOpacity;
l.material_mask = material_mask;
l.fill_layer = fill_layer;
l.objectMask = objectMask;
l.blending = blending;
l.paintBase = paintBase;
@@ -416,7 +417,7 @@ class LayerSlot {
public function toFillLayer() {
Context.setLayer(this);
material_mask = Context.material;
fill_layer = Context.material;
Layers.updateFillLayers(4);
function _parse(_) {
MakeMaterial.parsePaintMaterial();
@@ -429,7 +430,28 @@ class LayerSlot {
public function toPaintLayer() {
Context.setLayer(this);
material_mask = null;
fill_layer = null;
MakeMaterial.parsePaintMaterial();
Context.layerPreviewDirty = true;
UISidebar.inst.hwnd.redraws = 2;
}
public function toFillMask() {
Context.setLayer(this, true);
fill_mask = Context.material;
Layers.updateFillLayers(4);
function _parse(_) {
MakeMaterial.parsePaintMaterial();
Context.layerPreviewDirty = true;
UISidebar.inst.hwnd.redraws = 2;
iron.App.removeRender(_parse);
}
iron.App.notifyOnRender(_parse);
}
public function toPaintMask() {
Context.setLayer(this, true);
fill_mask = null;
MakeMaterial.parsePaintMaterial();
Context.layerPreviewDirty = true;
UISidebar.inst.hwnd.redraws = 2;
+2 -1
View File
@@ -59,7 +59,8 @@ class ExportArm {
uv_rot: l.angle,
uv_type: l.uvType,
opacity_mask: l.maskOpacity,
material_mask: l.material_mask != null ? Project.materials.indexOf(l.material_mask) : -1,
fill_layer: l.fill_layer != null ? Project.materials.indexOf(l.fill_layer) : -1,
fill_mask: l.fill_mask != null ? Project.materials.indexOf(l.fill_mask) : -1,
object_mask: l.objectMask,
blending: l.blending,
parent: l.parent != null ? Project.layers.indexOf(l.parent) : -1,
+5 -1
View File
@@ -309,7 +309,11 @@ class ImportArm {
var l = Project.layers[i];
var isGroup = ld.texpaint == null;
if (!isGroup) {
l.material_mask = ld.material_mask > -1 ? Project.materials[ld.material_mask] : null;
var material_mask = untyped ld.material_mask; // TODO: deprecated
if (material_mask != null) l.fill_layer = material_mask > -1 ? Project.materials[material_mask] : null;
else l.fill_layer = ld.fill_layer > -1 ? Project.materials[ld.fill_layer] : null;
l.fill_mask = ld.fill_mask > -1 ? Project.materials[ld.fill_mask] : null;
}
}
+5 -5
View File
@@ -80,7 +80,7 @@ class MakePaint {
vert.write('gl_Position = vec4(tpos, 0.0, 1.0);');
var decalLayer = Context.layer.material_mask != null && Context.layer.uvType == UVProject;
var decalLayer = Context.layer.fill_layer != null && Context.layer.uvType == UVProject;
if (decalLayer) {
vert.add_uniform('mat4 WVP', '_decalLayerMatrix');
}
@@ -95,7 +95,7 @@ class MakePaint {
frag.write_attrib('sp.y = 1.0 - sp.y;');
frag.write_attrib('sp.z -= 0.0001;'); // small bias
var uvType = Context.layer.material_mask != null ? Context.layer.uvType : Context.brushPaint;
var uvType = Context.layer.fill_layer != null ? Context.layer.uvType : Context.brushPaint;
if (uvType == UVProject) frag.ndcpos = true;
frag.add_uniform('vec4 inp', '_inputBrush');
@@ -192,7 +192,7 @@ class MakePaint {
MaterialParser.parse_subsurface = Context.material.paintSubs;
MaterialParser.parse_height = Context.material.paintHeight;
MaterialParser.parse_height_as_channel = true;
var uvType = Context.layer.material_mask != null ? Context.layer.uvType : Context.brushPaint;
var uvType = Context.layer.fill_layer != null ? Context.layer.uvType : Context.brushPaint;
MaterialParser.triplanar = uvType == UVTriplanar && !decal;
var sout = MaterialParser.parse(UINodes.inst.getCanvasMaterial(), con_paint, vert, frag, null, null, null, matcon);
MaterialParser.parse_emission = false;
@@ -216,7 +216,7 @@ class MakePaint {
frag.write('float height = $height;');
frag.write('float mat_opacity = $opac;');
frag.write('float opacity = mat_opacity;');
if (Context.layer.material_mask == null) {
if (Context.layer.fill_layer == null) {
frag.write('opacity *= brushOpacity;');
}
if (Context.material.paintEmis) {
@@ -349,7 +349,7 @@ class MakePaint {
frag.write('fragColor[0] = vec4(' + MakeMaterial.blendMode(frag, Context.brushBlending, 'sample_undo.rgb', 'basecol', 'str') + ', max(str, sample_undo.a));');
}
else {
if (Context.layer.material_mask != null) {
if (Context.layer.fill_layer != null) {
frag.write('fragColor[0] = vec4(' + MakeMaterial.blendMode(frag, Context.brushBlending, 'sample_undo.rgb', 'basecol', 'opacity') + ', mat_opacity);');
}
else {
+3 -3
View File
@@ -8,7 +8,7 @@ class MakeTexcoord {
public static function run(vert: NodeShader, frag: NodeShader) {
var fillLayer = Context.layer.material_mask != null;
var fillLayer = Context.layer.fill_layer != null;
var uvType = fillLayer ? Context.layer.uvType : Context.brushPaint;
var decal = Context.tool == ToolDecal || Context.tool == ToolText;
@@ -33,7 +33,7 @@ class MakeTexcoord {
frag.write_attrib('uvsp = vec2(uvsp.x * brushDirection.x - uvsp.y * brushDirection.y, uvsp.x * brushDirection.y + uvsp.y * brushDirection.x);');
}
var angle = Context.brushAngle + Context.brushNodesAngle;
var uvAngle = Context.layer.material_mask != null ? Context.layer.angle : angle;
var uvAngle = Context.layer.fill_layer != null ? Context.layer.angle : angle;
if (uvAngle != 0.0) {
frag.add_uniform('vec2 brushAngle', '_brushAngle');
frag.write_attrib('uvsp = vec2(uvsp.x * brushAngle.x - uvsp.y * brushAngle.y, uvsp.x * brushAngle.y + uvsp.y * brushAngle.x);');
@@ -58,7 +58,7 @@ class MakeTexcoord {
vert.write('texCoord = subtex * brushScale;');
var angle = Context.brushAngle + Context.brushNodesAngle;
var uvAngle = Context.layer.material_mask != null ? Context.layer.angle : angle;
var uvAngle = Context.layer.fill_layer != null ? Context.layer.angle : angle;
if (uvAngle > 0.0) {
vert.add_uniform('vec2 brushAngle', '_brushAngle');
vert.write('texCoord = vec2(texCoord.x * brushAngle.x - texCoord.y * brushAngle.y, texCoord.x * brushAngle.y + texCoord.y * brushAngle.x);');
+1 -1
View File
@@ -74,7 +74,7 @@ class BrushOutputNode extends LogicNode {
}
// Do not paint over fill layer
var fillLayer = Context.layer.material_mask != null && Context.tool != ToolPicker && !Context.layerIsMask;
var fillLayer = Context.layer.fill_layer != null && Context.tool != ToolPicker && !Context.layerIsMask;
// Do not paint over groups
var groupLayer = Context.layer.getChildren() != null;
+1 -1
View File
@@ -19,7 +19,7 @@ class Gizmo {
var isRender = UIHeader.inst.worktab.position == SpaceRender;
var isPaint = UIHeader.inst.worktab.position == SpacePaint;
var isObject = isRender && Context.object != null;
var isDecal = isPaint && Context.layer.material_mask != null && Context.layer.uvType == UVProject;
var isDecal = isPaint && Context.layer.fill_layer != null && Context.layer.uvType == UVProject;
var gizmo = Context.gizmo;
gizmo.visible = isObject || isDecal;
+1 -1
View File
@@ -43,7 +43,7 @@ class LineDraw {
public static function render(g4: kha.graphics4.Graphics) {
var isPaint = UIHeader.inst.worktab.position == SpacePaint;
var isDecal = isPaint && Context.layer.material_mask != null && Context.layer.uvType == UVProject;
var isDecal = isPaint && Context.layer.fill_layer != null && Context.layer.uvType == UVProject;
if (!isDecal) return;
mat = Context.layer.decalMat;
+1 -1
View File
@@ -479,7 +479,7 @@ class RenderPathPaint {
}
static function paintEnabled(): Bool {
var fillLayer = Context.layer.material_mask != null && !Context.layerIsMask;
var fillLayer = Context.layer.fill_layer != null && !Context.layerIsMask;
var groupLayer = Context.layer.getChildren() != null;
return !fillLayer && !groupLayer;
}
+2 -2
View File
@@ -69,7 +69,7 @@ class Uniforms {
}
if (link == "_brushScale") {
var nodesScale = Context.brushNodesScale;
var fill = Context.layer.material_mask != null;
var fill = Context.layer.fill_layer != null;
var val = (fill ? Context.layer.scale : Context.brushScale) * nodesScale;
return val;
}
@@ -140,7 +140,7 @@ class Uniforms {
}
if (link == "_brushAngle") {
var brushAngle = Context.brushAngle + Context.brushNodesAngle;
var angle = Context.layer.material_mask != null ? Context.layer.angle : brushAngle;
var angle = Context.layer.fill_layer != null ? Context.layer.angle : brushAngle;
angle *= (Math.PI / 180);
var pen = Input.getPen();
if (Config.raw.pressure_angle && pen.down()) {
+55 -27
View File
@@ -70,7 +70,7 @@ class TabLayers {
var checkw = (ui._windowW / 100 * 8) / ui.SCALE();
if (l.show_panel && l.getChildren() == null) {
var mult = l.material_mask != null ? 2 : 1;
var mult = l.fill_layer != null ? 2 : 1;
var ph = (step + off) * mult;
ui.fill(checkw, step * 2, (ui._windowW / ui.SCALE() - 2) - checkw, ph, ui.t.SEPARATOR_COL);
}
@@ -122,7 +122,7 @@ class TabLayers {
var contextMenu = false;
#if kha_opengl
ui.imageInvertY = l.material_mask != null;
ui.imageInvertY = l.fill_layer != null;
#end
var uix = ui._x;
@@ -135,8 +135,8 @@ class TabLayers {
var iconH = (ui.ELEMENT_H() - 3) * 2;
if (l.getChildren() == null) {
var icon = l.material_mask == null ? l.texpaint_preview : l.material_mask.imageIcon;
if (l.material_mask == null) {
var icon = l.fill_layer == null ? l.texpaint_preview : l.fill_layer.imageIcon;
if (l.fill_layer == null) {
// Checker
var r = Res.tile50(icons, 4, 1);
var _x = ui._x;
@@ -194,13 +194,19 @@ class TabLayers {
// ui._x = _x;
// ui._y = _y;
ui.g.pipeline = UIView2D.inst.pipe;
#if kha_opengl
ui.currentWindow.texture.g4.setPipeline(UIView2D.inst.pipe);
#end
ui.currentWindow.texture.g4.setInt(UIView2D.inst.channelLocation, 1);
var state = ui.image(l.texpaint_mask_preview, 0xffffffff, (ui.ELEMENT_H() - 3) * 2);
ui.g.pipeline = null;
var state = State.Idle;
if (l.fill_mask != null) {
state = ui.image(l.fill_mask.imageIcon, 0xffffffff, (ui.ELEMENT_H() - 3) * 2);
}
else {
ui.g.pipeline = UIView2D.inst.pipe;
#if kha_opengl
ui.currentWindow.texture.g4.setPipeline(UIView2D.inst.pipe);
#end
ui.currentWindow.texture.g4.setInt(UIView2D.inst.channelLocation, 1);
state = ui.image(l.texpaint_mask_preview, 0xffffffff, (ui.ELEMENT_H() - 3) * 2);
ui.g.pipeline = null;
}
ui._x -= Std.int(4 * ui.SCALE());
ui._y -= 3;
@@ -208,15 +214,39 @@ class TabLayers {
ui.tooltipImage(l.texpaint_mask_preview);
}
if (ui.isHovered && ui.inputReleasedR) {
var add = l.fill_mask == null ? 2 : 0;
UIMenu.draw(function(ui: Zui) {
ui.text('${l.name} ' + tr("Mask"), Right, ui.t.HIGHLIGHT_COL);
if (l.fill_mask == null && ui.button(tr("To Fill Mask"), Left)) {
function makeFill(g: kha.graphics4.Graphics) {
g.end();
History.toFillMask();
l.toFillMask();
g.begin();
iron.App.removeRender(makeFill);
}
iron.App.notifyOnRender(makeFill);
}
if (l.fill_mask != null && ui.button(tr("To Paint Mask"), Left)) {
function makePaint(g: kha.graphics4.Graphics) {
g.end();
History.toPaintMask();
l.toPaintMask();
g.begin();
iron.App.removeRender(makePaint);
}
iron.App.notifyOnRender(makePaint);
}
if (l.fill_mask != null && ui.button(tr("Select Material"), Left)) {
Context.setMaterial(l.fill_mask);
}
if (ui.button(tr("Delete"), Left)) {
Context.setLayer(l, true);
History.deleteMask();
l.deleteMask();
Context.setLayer(l, false);
}
if (ui.button(tr("Clear to Black"), Left)) {
if (l.fill_mask == null && ui.button(tr("Clear to Black"), Left)) {
function clear(g: kha.graphics4.Graphics) {
g.end();
l.clearMask(0x00000000);
@@ -225,7 +255,7 @@ class TabLayers {
}
iron.App.notifyOnRender(clear);
}
if (ui.button(tr("Clear to White"), Left)) {
if (l.fill_mask == null && ui.button(tr("Clear to White"), Left)) {
function clear(g: kha.graphics4.Graphics) {
g.end();
l.clearMask(0xffffffff);
@@ -234,7 +264,7 @@ class TabLayers {
}
iron.App.notifyOnRender(clear);
}
if (ui.button(tr("Invert"), Left)) {
if (l.fill_mask == null && ui.button(tr("Invert"), Left)) {
function invert(g: kha.graphics4.Graphics) {
g.end();
l.invertMask();
@@ -255,7 +285,7 @@ class TabLayers {
}
iron.App.notifyOnRender(makeApply);
}
}, 6);
}, 5 + add);
}
if (state == State.Started) {
Context.setLayer(l, true);
@@ -286,7 +316,7 @@ class TabLayers {
if (contextMenu) {
var add = l.material_mask != null ? 1 : 0;
var add = l.fill_layer != null ? 1 : 0;
var menuElements = l.getChildren() != null ? 6 : (21 + add);
UIMenu.draw(function(ui: Zui) {
@@ -294,7 +324,7 @@ class TabLayers {
if (ui.button(tr("Export"), Left)) BoxExport.showTextures();
if (l.getChildren() == null && l.material_mask == null && ui.button(tr("To Fill Layer"), Left)) {
if (l.getChildren() == null && l.fill_layer == null && ui.button(tr("To Fill Layer"), Left)) {
function makeFill(g: kha.graphics4.Graphics) {
g.end();
History.toFillLayer();
@@ -304,7 +334,7 @@ class TabLayers {
}
iron.App.notifyOnRender(makeFill);
}
if (l.getChildren() == null && l.material_mask != null && ui.button(tr("To Paint Layer"), Left)) {
if (l.getChildren() == null && l.fill_layer != null && ui.button(tr("To Paint Layer"), Left)) {
function makePaint(g: kha.graphics4.Graphics) {
g.end();
History.toPaintLayer();
@@ -463,10 +493,8 @@ class TabLayers {
History.newMask();
}
if (l.material_mask != null) {
if (ui.button(tr("Select Material"), Left)) {
Context.setMaterial(l.material_mask);
}
if (l.fill_layer != null && ui.button(tr("Select Material"), Left)) {
Context.setMaterial(l.fill_layer);
}
if (l.getChildren() == null) {
@@ -572,7 +600,7 @@ class TabLayers {
if (objectHandle.changed) {
Context.setLayer(l);
MakeMaterial.parseMeshMaterial();
if (l.material_mask != null) { // Fill layer
if (l.fill_layer != null) { // Fill layer
iron.App.notifyOnRender(l.clear);
function updateFillLayers(_) {
Layers.updateFillLayers(4);
@@ -620,7 +648,7 @@ class TabLayers {
iron.App.notifyOnRender(Layers.setLayerBits);
}
if (l.material_mask != null) {
if (l.fill_layer != null) {
ui.row([8 / 100, 92 / 100 / 3, 92 / 100 / 3, 92 / 100 / 3]);
@:privateAccess ui.endElement();
@@ -628,7 +656,7 @@ class TabLayers {
scaleHandle.value = l.scale;
l.scale = ui.slider(scaleHandle, tr("UV Scale"), 0.0, 5.0, true);
if (scaleHandle.changed) {
Context.setMaterial(l.material_mask);
Context.setMaterial(l.fill_layer);
Context.setLayer(l);
Layers.updateFillLayers();
}
@@ -637,7 +665,7 @@ class TabLayers {
angleHandle.value = l.angle;
l.angle = ui.slider(angleHandle, tr("Angle"), 0.0, 360, true, 1);
if (angleHandle.changed) {
Context.setMaterial(l.material_mask);
Context.setMaterial(l.fill_layer);
Context.setLayer(l);
MakeMaterial.parsePaintMaterial();
Layers.updateFillLayers();
@@ -647,7 +675,7 @@ class TabLayers {
uvTypeHandle.position = l.uvType;
l.uvType = ui.combo(uvTypeHandle, [tr("UV Map"), tr("Triplanar"), tr("Project")], tr("TexCoord"));
if (uvTypeHandle.changed) {
Context.setMaterial(l.material_mask);
Context.setMaterial(l.fill_layer);
Context.setLayer(l);
MakeMaterial.parsePaintMaterial();
Layers.updateFillLayers();