From e624b0e6ea09118d1d32bc6c4d17ce59c2197207 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 13 Mar 2020 17:22:16 +0100 Subject: [PATCH] Stencil mask for brush --- Assets/painter/keymap_presets/blender.json | 4 +- Assets/painter/keymap_presets/default.json | 4 +- Sources/arm/Context.hx | 2 + Sources/arm/node/MakePaint.hx | 16 ++++++ Sources/arm/plugin/Camera.hx | 4 +- Sources/arm/render/Uniforms.hx | 8 +++ Sources/arm/ui/TabBrushes.hx | 3 ++ Sources/arm/ui/TabTextures.hx | 1 + Sources/arm/ui/UITrait.hx | 62 ++++++++++++++++++++-- Sources/arm/ui/UIView2D.hx | 12 +++-- 10 files changed, 106 insertions(+), 10 deletions(-) diff --git a/Assets/painter/keymap_presets/blender.json b/Assets/painter/keymap_presets/blender.json index 4140cc42..b5309ed1 100644 --- a/Assets/painter/keymap_presets/blender.json +++ b/Assets/painter/keymap_presets/blender.json @@ -3,7 +3,9 @@ "action_rotate": "middle", "action_pan": "shift+middle", "action_zoom": "ctrl+middle", - "action_rotate_light": "shift+middle", + "rotate_light": "shift+middle", + "set_clone_source": "alt", + "stencil_transform": "ctrl", "select_material": "shift+number", "cycle_layers": "ctrl+tab", "brush_radius": "f", diff --git a/Assets/painter/keymap_presets/default.json b/Assets/painter/keymap_presets/default.json index 699d4e37..1c2383ad 100644 --- a/Assets/painter/keymap_presets/default.json +++ b/Assets/painter/keymap_presets/default.json @@ -3,7 +3,9 @@ "action_rotate": "alt+left", "action_pan": "alt+middle", "action_zoom": "alt+right", - "action_rotate_light": "shift+middle", + "rotate_light": "shift+middle", + "set_clone_source": "alt", + "stencil_transform": "ctrl", "select_material": "shift+number", "cycle_layers": "ctrl+tab", "brush_radius": "f", diff --git a/Sources/arm/Context.hx b/Sources/arm/Context.hx index c5c66de2..dc3f1c12 100644 --- a/Sources/arm/Context.hx +++ b/Sources/arm/Context.hx @@ -72,7 +72,9 @@ class Context { if (Project.brushes.length <= i) return; brush = Project.brushes[i]; MaterialParser.parseBrush(); + UITrait.inst.parseBrushInputs(); UITrait.inst.hwnd1.redraws = 2; + UINodes.inst.hwnd.redraws = 2; } public static function setLayer(l: LayerSlot, isMask = false) { diff --git a/Sources/arm/node/MakePaint.hx b/Sources/arm/node/MakePaint.hx index e5050622..92d0d96c 100644 --- a/Sources/arm/node/MakePaint.hx +++ b/Sources/arm/node/MakePaint.hx @@ -221,6 +221,22 @@ class MakePaint { frag.write('opacity *= textureLod(textexttool, texCoord, 0.0).r;'); } + if (UITrait.inst.brushStencilImage != null && ( + Context.tool == ToolBrush || + Context.tool == ToolEraser || + Context.tool == ToolFill || + Context.tool == ToolClone || + Context.tool == ToolBlur || + Context.tool == ToolParticle || + decal)) { + frag.add_uniform('sampler2D texbrushstencil', '_texbrushstencil'); + frag.add_uniform('vec4 stencilTransform', '_stencilTransform'); + frag.write('vec2 stencil_uv = vec2((sp.xy - stencilTransform.xy) / stencilTransform.z * vec2(aspectRatio, 1.0));'); + frag.write('if (stencil_uv.x < 0 || stencil_uv.x > 1 || stencil_uv.y < 0 || stencil_uv.y > 1) discard;'); + frag.write('vec4 texbrushstencil_sample = textureLod(texbrushstencil, stencil_uv, 0.0);'); + frag.write('opacity *= texbrushstencil_sample.r * texbrushstencil_sample.a;'); + } + if (UITrait.inst.brushMaskImage != null && (Context.tool == ToolBrush || Context.tool == ToolEraser)) { frag.add_uniform('sampler2D texbrushmask', '_texbrushmask'); frag.write('vec2 binp_mask = inp.xy * 2.0 - 1.0;'); diff --git a/Sources/arm/plugin/Camera.hx b/Sources/arm/plugin/Camera.hx index 9e572116..13529ab1 100644 --- a/Sources/arm/plugin/Camera.hx +++ b/Sources/arm/plugin/Camera.hx @@ -67,14 +67,14 @@ class Camera { dist -= f; } - if (mouse.wheelDelta != 0) { + if (mouse.wheelDelta != 0 && !modif) { redraws = 2; var f = mouse.wheelDelta * (-0.1); camera.transform.move(camera.look(), f); dist -= f; } - if (Operator.shortcut(Config.keymap.action_rotate_light)) { + if (Operator.shortcut(Config.keymap.rotate_light)) { redraws = 2; var light = iron.Scene.active.lights[0]; var m = iron.math.Mat4.identity(); diff --git a/Sources/arm/render/Uniforms.hx b/Sources/arm/render/Uniforms.hx index f3d1d5cc..5024a765 100644 --- a/Sources/arm/render/Uniforms.hx +++ b/Sources/arm/render/Uniforms.hx @@ -281,6 +281,11 @@ class Uniforms { if (UITrait.inst.paint2d) vec2.x -= 1.0; return vec2; } + if (link == "_stencilTransform") { + vec2.set(UITrait.inst.brushStencilX, UITrait.inst.brushStencilY, UITrait.inst.brushStencilScale, 0.0); + if (UITrait.inst.paint2d) vec2.x -= 1.0; + return vec2; + } #end return null; } @@ -305,6 +310,9 @@ class Uniforms { if (link == "_texbrushmask") { return UITrait.inst.brushMaskImage; } + if (link == "_texbrushstencil") { + return UITrait.inst.brushStencilImage; + } if (link == "_texpaint_undo") { var i = History.undoI - 1 < 0 ? Config.raw.undo_steps - 1 : History.undoI - 1; return RenderPath.active.renderTargets.get("texpaint_undo" + i).image; diff --git a/Sources/arm/ui/TabBrushes.hx b/Sources/arm/ui/TabBrushes.hx index 041c1abe..59a78413 100644 --- a/Sources/arm/ui/TabBrushes.hx +++ b/Sources/arm/ui/TabBrushes.hx @@ -3,6 +3,7 @@ package arm.ui; import iron.system.Time; import zui.Zui; import arm.data.BrushSlot; +import arm.node.MaterialParser; class TabBrushes { @@ -14,6 +15,8 @@ class TabBrushes { if (ui.button("New")) { Context.brush = new BrushSlot(); Project.brushes.push(Context.brush); + MaterialParser.parseBrush(); + UITrait.inst.parseBrushInputs(); UINodes.inst.hwnd.redraws = 2; } if (ui.button("Import")) {} diff --git a/Sources/arm/ui/TabTextures.hx b/Sources/arm/ui/TabTextures.hx index 1a466432..3a704bf7 100644 --- a/Sources/arm/ui/TabTextures.hx +++ b/Sources/arm/ui/TabTextures.hx @@ -58,6 +58,7 @@ class TabTextures { if (Time.time() - UITrait.inst.selectTime < 0.25) UITrait.inst.show2DView(1); UITrait.inst.selectTime = Time.time(); + UIView2D.inst.hwnd.redraws = 2; } var _uix = ui._x; diff --git a/Sources/arm/ui/UITrait.hx b/Sources/arm/ui/UITrait.hx index 441785a5..ae55a437 100644 --- a/Sources/arm/ui/UITrait.hx +++ b/Sources/arm/ui/UITrait.hx @@ -26,6 +26,7 @@ import arm.io.ImportFont; import arm.io.ExportTexture; import arm.Tool; import arm.Project; +import arm.Res; @:access(zui.Zui) class UITrait { @@ -174,6 +175,11 @@ class UITrait { public var brushNodesOpacity = 1.0; public var brushMaskImage: Image = null; public var brushStencilImage: Image = null; + public var brushStencilX = 0.02; + public var brushStencilY = 0.02; + public var brushStencilRot = 0.0; + public var brushStencilScale = 0.9; + public var brushStencilScaling = false; public var brushNodesScale = 1.0; public var brushNodesHardness = 1.0; @@ -656,6 +662,18 @@ class UITrait { return 0.1; } + static function hitRect(mx: Float, my: Float, x: Int, y: Int, w: Int, h: Int) { + return mx > x && mx < x + w && my > y && my < y + h; + } + + function getBrushRect(): TRect { + var w = Std.int(brushStencilImage.width * (App.h() / brushStencilImage.height) * brushStencilScale); + var h = Std.int(App.h() * brushStencilScale); + var x = Std.int(App.x() + brushStencilX * App.w()); + var y = Std.int(App.y() + brushStencilY * App.h()); + return { w: w, h: h, x: x, y: y }; + } + function updateUI() { if (Log.messageTimer > 0) { @@ -668,7 +686,36 @@ class UITrait { var mouse = Input.getMouse(); var kb = Input.getKeyboard(); - var setCloneSource = Context.tool == ToolClone && Operator.shortcut("alt+" + Config.keymap.action_paint); + var setCloneSource = Context.tool == ToolClone && Operator.shortcut(Config.keymap.set_clone_source + "+" + Config.keymap.action_paint); + + if (brushStencilImage != null && Operator.shortcut(Config.keymap.stencil_transform)) { + var r = getBrushRect(); + if (mouse.started("left")) { + brushStencilScaling = + hitRect(mouse.x, mouse.y, r.x - 8, r.y - 8, 16, 16) || + hitRect(mouse.x, mouse.y, r.x - 8, r.h + r.y - 8, 16, 16) || + hitRect(mouse.x, mouse.y, r.w + r.x - 8, r.y - 8, 16, 16) || + hitRect(mouse.x, mouse.y, r.w + r.x - 8, r.h + r.y - 8, 16, 16); + } + var _scale = brushStencilScale; + if (mouse.down("left")) { + if (brushStencilScaling) { + var mult = mouse.x > r.x + r.w / 2 ? 1 : -1; + brushStencilScale += mouse.movementX / 500 * mult; + } + else { + brushStencilX += mouse.movementX / App.w(); + brushStencilY += mouse.movementY / App.h(); + } + } + else brushStencilScaling = false; + if (mouse.wheelDelta != 0) { + brushStencilScale -= mouse.wheelDelta / 10; + } + // Center after scale + brushStencilX += (_scale * brushStencilImage.width - brushStencilScale * brushStencilImage.width) / 2 / App.w(); + brushStencilY += (_scale * brushStencilImage.height - brushStencilScale * brushStencilImage.height) / 2 / App.h(); + } var down = Operator.shortcut(Config.keymap.action_paint) || setCloneSource || @@ -813,9 +860,18 @@ class UITrait { } if (brushStencilImage != null && Context.tool != ToolBake && Context.tool != ToolPicker && Context.tool != ToolColorId) { - g.color = 0xaaffffff; - g.drawImage(brushStencilImage, 0, 0); + var transform = Operator.shortcut(Config.keymap.stencil_transform); + g.color = 0x88ffffff; + var r = getBrushRect(); + g.drawScaledImage(brushStencilImage, r.x, r.y, r.w, r.h); g.color = 0xffffffff; + if (transform) { + g.drawRect(r.x, r.y, r.w, r.h); + g.drawRect(r.x - 8, r.y - 8, 16, 16); + g.drawRect(r.x - 8 + r.w, r.y - 8, 16, 16); + g.drawRect(r.x - 8, r.y - 8 + r.h, 16, 16); + g.drawRect(r.x - 8 + r.w, r.y - 8 + r.h, 16, 16); + } } // Show picked material next to cursor diff --git a/Sources/arm/ui/UIView2D.hx b/Sources/arm/ui/UIView2D.hx index 54968f52..325b77c5 100644 --- a/Sources/arm/ui/UIView2D.hx +++ b/Sources/arm/ui/UIView2D.hx @@ -95,7 +95,6 @@ class UIView2D { ui.g.drawImage(UINodes.inst.grid, (panX * panScale) % 40 - 40, (panY * panScale) % 40 - 40); // Texture - ui.g.pipeline = pipe; var l = Context.layer; var tex: Image = null; var channel = 0; @@ -127,9 +126,16 @@ class UIView2D { var th = tw; if (tex != null) { th = tw * (tex.height / tex.width); - drawLayer(tex, tx, ty, tw, th, channel); } - ui.g.pipeline = null; + + if (type == View2DLayer) { + ui.g.pipeline = pipe; + drawLayer(tex, tx, ty, tw, th, channel); + ui.g.pipeline = null; + } + else { + ui.g.drawScaledImage(tex, tx, ty, tw, th); + } // UV map if (type == View2DLayer && uvmapShow) {