From 2afe3f703e552dbea905945b25d17b2d3182091a Mon Sep 17 00:00:00 2001 From: luboslenco Date: Mon, 16 Mar 2020 22:07:24 +0100 Subject: [PATCH] Directional brush --- Assets/common/default_brush.json | 2 +- Sources/arm/data/LayerSlot.hx | 4 +-- Sources/arm/io/ExportArm.hx | 4 +-- Sources/arm/io/ImportArm.hx | 4 +-- Sources/arm/node/MakePaint.hx | 16 ++++++++++- Sources/arm/node/MakeTexcoord.hx | 22 ++++++++++----- Sources/arm/node/NodesBrush.hx | 33 ++++++++++++++++------- Sources/arm/node/brush/BrushOutputNode.hx | 13 ++++++--- Sources/arm/render/Uniforms.hx | 12 ++++++++- Sources/arm/ui/TabLayers.hx | 12 ++++----- Sources/arm/ui/UITrait.hx | 12 +++++---- 11 files changed, 95 insertions(+), 39 deletions(-) diff --git a/Assets/common/default_brush.json b/Assets/common/default_brush.json index b7e8f399..5de497ae 100644 --- a/Assets/common/default_brush.json +++ b/Assets/common/default_brush.json @@ -1 +1 @@ -{"name":"Brush","nodes":[{"id":3,"name":"Input","type":"InputNode","x":83,"y":192,"color":-11959648,"inputs":[{"id":3,"node_id":3,"name":"Lazy Radius","type":"VALUE","color":-6184543,"default_value":0.0},{"id":3,"node_id":3,"name":"Lazy Step","type":"VALUE","color":-6184543,"default_value":0.0}],"outputs":[{"id":3,"node_id":3,"name":"Position","type":"VECTOR","color":-10238109,"default_value":null}],"buttons":[]},{"id":5,"name":"Brush Output","type":"BrushOutputNode","x":311,"y":192,"color":-11959648,"inputs":[{"id":5,"node_id":5,"name":"Position","type":"VECTOR","color":-10238109,"default_value":[0,0,0]},{"id":5,"node_id":5,"name":"Radius","type":"VALUE","color":-6184543,"default_value":1.0},{"id":5,"node_id":5,"name":"Opacity","type":"VALUE","color":-6184543,"default_value":1},{"id":5,"node_id":5,"name":"Hardness","type":"VALUE","color":-6184543,"default_value":1},{"id":5,"node_id":5,"name":"UV Scale","type":"VALUE","color":-6184543,"default_value":1.0},{"id":5,"node_id":5,"name":"Stencil","type":"VALUE","color":-6184543,"default_value":1.0}],"outputs":[],"buttons":[]}],"links":[{"id":0,"from_id":3,"from_socket":0,"to_id":5,"to_socket":0}]} \ No newline at end of file +{"name":"Brush","nodes":[{"id":3,"name":"Input","type":"InputNode","x":83,"y":218,"color":-11959648,"inputs":[{"id":3,"node_id":3,"name":"Lazy Radius","type":"VALUE","color":-6184543,"default_value":0.0},{"id":3,"node_id":3,"name":"Lazy Step","type":"VALUE","color":-6184543,"default_value":0.0}],"outputs":[{"id":3,"node_id":3,"name":"Position","type":"VECTOR","color":-10238109,"default_value":null}],"buttons":[]},{"id":5,"name":"Brush Output","type":"BrushOutputNode","x":311,"y":192,"color":-11959648,"inputs":[{"id":5,"node_id":5,"name":"Position","type":"VECTOR","color":-10238109,"default_value":[0,0,0]},{"id":5,"node_id":5,"name":"Radius","type":"VALUE","color":-6184543,"default_value":1.0},{"id":5,"node_id":5,"name":"Scale","type":"VALUE","color":-6184543,"default_value":1.0},{"id":5,"node_id":5,"name":"Angle","type":"VALUE","color":-6184543,"default_value":0.0},{"id":5,"node_id":5,"name":"Opacity","type":"VALUE","color":-6184543,"default_value":1.0},{"id":5,"node_id":5,"name":"Hardness","type":"VALUE","color":-6184543,"default_value":1.0},{"id":5,"node_id":5,"name":"Stencil","type":"VALUE","color":-6184543,"default_value":1.0}],"outputs":[],"buttons":[{"name": "Directional","type": "BOOL","default_value": false,"output": 0}]}],"links":[{"id":0,"from_id":3,"from_socket":0,"to_id":5,"to_socket":0}]} \ No newline at end of file diff --git a/Sources/arm/data/LayerSlot.hx b/Sources/arm/data/LayerSlot.hx index 31560ae3..e419b3c8 100644 --- a/Sources/arm/data/LayerSlot.hx +++ b/Sources/arm/data/LayerSlot.hx @@ -30,8 +30,8 @@ class LayerSlot { public var blending = BlendMix; public var objectMask = 0; - public var uvScale = 1.0; - public var uvRot = 0.0; + public var scale = 1.0; + public var angle = 0.0; public var uvType = UVMap; public var paintBase = true; public var paintOpac = true; diff --git a/Sources/arm/io/ExportArm.hx b/Sources/arm/io/ExportArm.hx index b0119ced..c18c21bc 100644 --- a/Sources/arm/io/ExportArm.hx +++ b/Sources/arm/io/ExportArm.hx @@ -53,8 +53,8 @@ class ExportArm { texpaint_nor: l.texpaint_nor != null ? Lz4.encode(l.texpaint_nor.getPixels()) : null, texpaint_pack: l.texpaint_pack != null ? Lz4.encode(l.texpaint_pack.getPixels()) : null, texpaint_mask: l.texpaint_mask != null ? Lz4.encode(l.texpaint_mask.getPixels()) : null, - uv_scale: l.uvScale, - uv_rot: l.uvRot, + uv_scale: l.scale, + 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, diff --git a/Sources/arm/io/ImportArm.hx b/Sources/arm/io/ImportArm.hx index a9e2db7a..02469fa9 100644 --- a/Sources/arm/io/ImportArm.hx +++ b/Sources/arm/io/ImportArm.hx @@ -232,8 +232,8 @@ class ImportArm { l.texpaint_mask.g2.end(); } - l.uvScale = ld.uv_scale; - l.uvRot = ld.uv_rot; + l.scale = ld.uv_scale; + l.angle = ld.uv_rot; l.uvType = ld.uv_type; l.maskOpacity = ld.opacity_mask; l.material_mask = ld.material_mask > -1 ? Project.materials[ld.material_mask] : null; diff --git a/Sources/arm/node/MakePaint.hx b/Sources/arm/node/MakePaint.hx index 92d0d96c..7a51a611 100644 --- a/Sources/arm/node/MakePaint.hx +++ b/Sources/arm/node/MakePaint.hx @@ -243,13 +243,27 @@ class MakePaint { frag.write('binp_mask.x *= aspectRatio;'); frag.write('binp_mask = binp_mask * 0.5 + 0.5;'); frag.write('vec2 pa_mask = bsp.xy - binp_mask.xy;'); + // if (UITrait.inst.brushDirectional) { + // frag.add_uniform('vec2 brushDirection', '_brushDirection'); + // frag.write('pa_mask.xy = vec2(pa_mask.x * brushDirection.x - pa_mask.y * brushDirection.y, pa_mask.x * brushDirection.y + pa_mask.y * brushDirection.x);'); + // } + if (UITrait.inst.brushDirectional) { + frag.write('float maskAngle = atan2(-inp.y + inplast.y, inp.x - inplast.x) - 3.141592 / 2;'); + frag.write('pa_mask.xy = vec2(pa_mask.x * cos(maskAngle) - pa_mask.y * sin(maskAngle), pa_mask.x * sin(maskAngle) + pa_mask.y * cos(maskAngle));'); + } + var angle = UITrait.inst.brushAngle + UITrait.inst.brushNodesAngle; + if (angle != 0.0) { + var a = angle * (Math.PI / 180); + frag.write('pa_mask.xy = vec2(pa_mask.x * ${Math.cos(a)} - pa_mask.y * ${Math.sin(a)}, pa_mask.x * ${Math.sin(a)} + pa_mask.y * ${Math.cos(a)});'); + } frag.write('pa_mask /= brushRadius;'); if (UITrait.inst.brush3d) { frag.add_uniform('vec3 eye', '_cameraPosition'); frag.write('pa_mask *= distance(eye, winp.xyz) / 1.5;'); } frag.write('pa_mask = pa_mask.xy * 0.5 + 0.5;'); - frag.write('opacity *= textureLod(texbrushmask, pa_mask, 0.0).r;'); + frag.write('float4 mask_sample = textureLod(texbrushmask, pa_mask, 0.0);'); + frag.write('opacity *= mask_sample.r * mask_sample.a;'); } if (Context.tool == ToolParticle) { // particle mask diff --git a/Sources/arm/node/MakeTexcoord.hx b/Sources/arm/node/MakeTexcoord.hx index 0388ca2a..3646ac87 100644 --- a/Sources/arm/node/MakeTexcoord.hx +++ b/Sources/arm/node/MakeTexcoord.hx @@ -31,9 +31,18 @@ class MakeTexcoord { frag.write_attrib('vec2 texCoord = uvsp * brushScale;'); - var uvRot = Context.layer.material_mask != null ? Context.layer.uvRot : UITrait.inst.brushRot; - if (uvRot > 0.0) { - var a = uvRot * (Math.PI / 180); + // if (UITrait.inst.brushDirectional) { + // frag.add_uniform('vec2 brushDirection', '_brushDirection'); + // frag.write('texCoord = vec2(texCoord.x * brushDirection.x - texCoord.y * brushDirection.y, texCoord.x * brushDirection.y + texCoord.y * brushDirection.x);'); + // } + if (UITrait.inst.brushDirectional) { + frag.write('float maskAngleBrush = atan2(-inp.y + inplast.y, inp.x - inplast.x) - 3.141592 / 2;'); + frag.write('texCoord = vec2(texCoord.x * cos(maskAngleBrush) - texCoord.y * sin(maskAngleBrush), texCoord.x * sin(maskAngleBrush) + texCoord.y * cos(maskAngleBrush));'); + } + var angle = UITrait.inst.brushAngle + UITrait.inst.brushNodesAngle; + var uvAngle = Context.layer.material_mask != null ? Context.layer.angle : angle; + if (uvAngle != 0.0) { + var a = uvAngle * (Math.PI / 180); frag.write('texCoord = vec2(texCoord.x * ${Math.cos(a)} - texCoord.y * ${Math.sin(a)}, texCoord.x * ${Math.sin(a)} + texCoord.y * ${Math.cos(a)});'); } } @@ -42,9 +51,10 @@ class MakeTexcoord { vert.add_out('vec2 texCoord'); vert.write('texCoord = subtex * brushScale;'); - var uvRot = Context.layer.material_mask != null ? Context.layer.uvRot : UITrait.inst.brushRot; - if (uvRot > 0.0) { - var a = uvRot * (Math.PI / 180); + var angle = UITrait.inst.brushAngle + UITrait.inst.brushNodesAngle; + var uvAngle = Context.layer.material_mask != null ? Context.layer.angle : angle; + if (uvAngle > 0.0) { + var a = uvAngle * (Math.PI / 180); vert.write('texCoord = vec2(texCoord.x * ${Math.cos(a)} - texCoord.y * ${Math.sin(a)}, texCoord.x * ${Math.sin(a)} + texCoord.y * ${Math.cos(a)});'); } } diff --git a/Sources/arm/node/NodesBrush.hx b/Sources/arm/node/NodesBrush.hx index f3ac64c5..26cbb07f 100644 --- a/Sources/arm/node/NodesBrush.hx +++ b/Sources/arm/node/NodesBrush.hx @@ -72,6 +72,22 @@ class NodesBrush { // { // id: 0, // node_id: 0, + // name: "Scale", + // type: "VALUE", + // color: 0xffa1a1a1, + // default_value: 1.0 + // }, + // { + // id: 0, + // node_id: 0, + // name: "Angle", + // type: "VALUE", + // color: 0xffa1a1a1, + // default_value: 0.0 + // }, + // { + // id: 0, + // node_id: 0, // name: "Opacity", // type: "VALUE", // color: 0xffa1a1a1, @@ -88,14 +104,6 @@ class NodesBrush { // { // id: 0, // node_id: 0, - // name: "UV Scale", - // type: "VALUE", - // color: 0xffa1a1a1, - // default_value: 1.0 - // }, - // { - // id: 0, - // node_id: 0, // name: "Stencil", // type: "VALUE", // color: 0xffa1a1a1, @@ -103,7 +111,14 @@ class NodesBrush { // } // ], // outputs: [], - // buttons: [] + // buttons: [ + // { + // name: "Directional", + // type: "BOOL", + // default_value: false, + // output: 0 + // } + // ] // }, { id: 0, diff --git a/Sources/arm/node/brush/BrushOutputNode.hx b/Sources/arm/node/brush/BrushOutputNode.hx index 231ec504..f4423555 100644 --- a/Sources/arm/node/brush/BrushOutputNode.hx +++ b/Sources/arm/node/brush/BrushOutputNode.hx @@ -7,6 +7,8 @@ import arm.Tool; @:keep class BrushOutputNode extends LogicNode { + public var Directional = false; // button 0 + public function new(tree: LogicTree) { super(tree); UITrait.inst.runBrush = run; @@ -19,8 +21,10 @@ class BrushOutputNode extends LogicNode { UITrait.inst.paintVec = inputs[0].get(); UITrait.inst.brushNodesRadius = inputs[1].get(); + UITrait.inst.brushNodesScale = inputs[2].get(); + UITrait.inst.brushNodesAngle = inputs[3].get(); - var opac: Dynamic = inputs[2].get(); // Float or texture name + var opac: Dynamic = inputs[4].get(); // Float or texture name if (opac == null) opac = 1.0; if (Std.is(opac, String)) { UITrait.inst.brushNodesOpacity = 1.0; @@ -33,10 +37,9 @@ class BrushOutputNode extends LogicNode { UITrait.inst.brushMaskImage = null; } - UITrait.inst.brushNodesHardness = inputs[3].get(); - UITrait.inst.brushNodesScale = inputs[4].get(); + UITrait.inst.brushNodesHardness = inputs[5].get(); - var stencil: Dynamic = inputs[5].get(); // Float or texture name + var stencil: Dynamic = inputs[6].get(); // Float or texture name if (stencil == null) stencil = 1.0; if (Std.is(stencil, String)) { var index = Project.assetNames.indexOf(stencil); @@ -51,6 +54,8 @@ class BrushOutputNode extends LogicNode { lastStencil != UITrait.inst.brushStencilImage) { MaterialParser.parsePaintMaterial(); } + + UITrait.inst.brushDirectional = Directional; } override function run(from: Int) { diff --git a/Sources/arm/render/Uniforms.hx b/Sources/arm/render/Uniforms.hx index 5024a765..06608480 100644 --- a/Sources/arm/render/Uniforms.hx +++ b/Sources/arm/render/Uniforms.hx @@ -56,7 +56,7 @@ class Uniforms { if (link == "_brushScale") { var nodesScale = UITrait.inst.brushNodesScale; var fill = Context.layer.material_mask != null; - var val = (fill ? Context.layer.uvScale : UITrait.inst.brushScale) * nodesScale; + var val = (fill ? Context.layer.scale : UITrait.inst.brushScale) * nodesScale; return val; } if (link == "_texpaintSize") { @@ -134,6 +134,16 @@ class Uniforms { vec2.set(UITrait.inst.cloneDeltaX, UITrait.inst.cloneDeltaY, 0); return vec2; } + if (link == "_brushDirection") { + var x = UITrait.inst.paintVec.x; + var y = UITrait.inst.paintVec.y; + var lastx = UITrait.inst.lastPaintVecX; + var lasty = UITrait.inst.lastPaintVecY; + if (UITrait.inst.paint2d) { x -= 1.0; lastx -= 1.0; } + var angle = Math.atan2(-y + lasty, x - lastx) - Math.PI / 2; + vec2.set(Math.cos(angle), Math.sin(angle), 0); + return vec2; + } #end return null; } diff --git a/Sources/arm/ui/TabLayers.hx b/Sources/arm/ui/TabLayers.hx index af32e023..390b809f 100644 --- a/Sources/arm/ui/TabLayers.hx +++ b/Sources/arm/ui/TabLayers.hx @@ -554,17 +554,17 @@ class TabLayers { ui.row([8 / 100, 92 / 100 / 3, 92 / 100 / 3, 92 / 100 / 3]); @:privateAccess ui.endElement(); - var uvScaleHandle = Id.handle().nest(l.id, {value: l.uvScale}); - l.uvScale = ui.slider(uvScaleHandle, "UV Scale", 0.0, 5.0, true); - if (uvScaleHandle.changed) { + var scaleHandle = Id.handle().nest(l.id, {value: l.scale}); + l.scale = ui.slider(scaleHandle, "Scale", 0.0, 5.0, true); + if (scaleHandle.changed) { Context.setMaterial(l.material_mask); Context.setLayer(l); Layers.updateFillLayers(); } - var uvRotHandle = Id.handle().nest(l.id, {value: l.uvRot}); - l.uvRot = ui.slider(uvRotHandle, "UV Rotate", 0.0, 360, true, 1); - if (uvRotHandle.changed) { + var angleHandle = Id.handle().nest(l.id, {value: l.angle}); + l.angle = ui.slider(angleHandle, "Angle", 0.0, 360, true, 1); + if (angleHandle.changed) { Context.setMaterial(l.material_mask); Context.setLayer(l); MaterialParser.parsePaintMaterial(); diff --git a/Sources/arm/ui/UITrait.hx b/Sources/arm/ui/UITrait.hx index fb2f9c5a..50ec3973 100644 --- a/Sources/arm/ui/UITrait.hx +++ b/Sources/arm/ui/UITrait.hx @@ -181,7 +181,9 @@ class UITrait { public var brushStencilScale = 0.9; public var brushStencilScaling = false; public var brushNodesScale = 1.0; + public var brushNodesAngle = 0.0; public var brushNodesHardness = 1.0; + public var brushDirectional = false; public var brushRadius = 0.5; public var brushRadiusHandle = new Handle({value: 0.5}); @@ -191,7 +193,7 @@ class UITrait { public var brushOpacity = 1.0; public var brushOpacityHandle = new Handle({value: 1.0}); public var brushScale = 1.0; - public var brushRot = 0.0; + public var brushAngle = 0.0; public var brushHardness = 0.8; public var brushLazyRadius = 0.0; public var brushLazyStep = 0.0; @@ -1162,7 +1164,7 @@ class UITrait { Context.tool == ToolDecal || Context.tool == ToolText) { var brushScaleHandle = Id.handle({value: brushScale}); - brushScale = ui.slider(brushScaleHandle, "UV Scale", 0.01, 5.0, true); + brushScale = ui.slider(brushScaleHandle, "Scale", 0.01, 5.0, true); if (brushScaleHandle.changed) { if (Context.tool == ToolDecal || Context.tool == ToolText) { ui.g.end(); @@ -1171,9 +1173,9 @@ class UITrait { } } - var brushRotHandle = Id.handle({value: brushRot}); - brushRot = ui.slider(brushRotHandle, "UV Rotate", 0.0, 360.0, true, 1); - if (brushRotHandle.changed) { + var brushAngleHandle = Id.handle({value: brushAngle}); + brushAngle = ui.slider(brushAngleHandle, "Angle", 0.0, 360.0, true, 1); + if (brushAngleHandle.changed) { MaterialParser.parsePaintMaterial(); } }