From 0d8f4bdaf5707ca5305fc4757fd56039021657d9 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Tue, 16 Apr 2019 00:04:28 +0200 Subject: [PATCH] Layer merge and mask apply --- Sources/arm/ConstData.hx | 185 +++++++++++++++++++++++++------------ Sources/arm/LayerSlot.hx | 26 ++++++ Sources/arm/Layers.hx | 138 +++++++++++++++++++++------ Sources/arm/ui/UITrait.hx | 8 +- Sources/arm/ui/UIView2D.hx | 4 +- 5 files changed, 265 insertions(+), 96 deletions(-) diff --git a/Sources/arm/ConstData.hx b/Sources/arm/ConstData.hx index c10b668b..be711115 100644 --- a/Sources/arm/ConstData.hx +++ b/Sources/arm/ConstData.hx @@ -2,77 +2,32 @@ package arm; class ConstData { - // Simple 2D view shader - + // 2D layer view #if kha_direct3d11 - public static var painterVert = " + public static var layerViewVert = " uniform float4x4 projectionMatrix; -static float4 gl_Position; -static float3 vertexPosition; -static float2 texCoord; -static float2 texPosition; -static float4 color; -static float4 vertexColor; -struct SPIRV_Cross_Input { - float3 vertexPosition : TEXCOORD0; - float2 texPosition : TEXCOORD1; - float4 vertexColor : TEXCOORD2; -}; -struct SPIRV_Cross_Output { - float4 color : TEXCOORD0; - float2 texCoord : TEXCOORD1; - float4 gl_Position : SV_Position; -}; -void vert_main() { - gl_Position = mul(float4(vertexPosition, 1.0f), projectionMatrix); - texCoord = texPosition; - color = vertexColor; - gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5; -} -SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) { - vertexPosition = stage_input.vertexPosition; - texPosition = stage_input.texPosition; - vertexColor = stage_input.vertexColor; - vert_main(); +struct SPIRV_Cross_Output { float4 color : TEXCOORD0; float2 texCoord : TEXCOORD1; float4 gl_Position : SV_Position; }; +SPIRV_Cross_Output main(float3 vertexPosition : TEXCOORD0, float2 texPosition : TEXCOORD1, float4 vertexColor : TEXCOORD2) { SPIRV_Cross_Output stage_output; - stage_output.gl_Position = gl_Position; - stage_output.texCoord = texCoord; - stage_output.color = color; + stage_output.gl_Position = mul(float4(vertexPosition, 1.0f), projectionMatrix); + stage_output.gl_Position.z = (stage_output.gl_Position.z + stage_output.gl_Position.w) * 0.5; + stage_output.texCoord = texPosition; + stage_output.color = vertexColor; return stage_output; } "; - public static var painterFrag = " + public static var layerViewFrag = " Texture2D tex; SamplerState _tex_sampler; -static float2 texCoord; -static float4 color; -static float4 FragColor; -struct SPIRV_Cross_Input { - float4 color : TEXCOORD0; - float2 texCoord : TEXCOORD1; -}; -struct SPIRV_Cross_Output { - float4 FragColor : SV_Target0; -}; -void frag_main() { - float4 texcolor = tex.Sample(_tex_sampler, texCoord) * color; - FragColor = texcolor; -} -SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) { - texCoord = stage_input.texCoord; - color = stage_input.color; - frag_main(); - SPIRV_Cross_Output stage_output; - stage_output.FragColor = FragColor; - return stage_output; +float4 main(float4 color : TEXCOORD0, float2 texCoord : TEXCOORD1) : SV_Target0 { + return tex.SampleLevel(_tex_sampler, texCoord, 0) * color; } "; #else // kha_opengl - public static var painterVert = " -#version 330 + public static var layerViewVert = "#version 330 in vec3 vertexPosition; in vec2 texPosition; in vec4 vertexColor; @@ -85,16 +40,124 @@ void main() { color = vertexColor; } "; - public static var painterFrag = " -#version 330 + public static var layerViewFrag = "#version 330 uniform sampler2D tex; in vec2 texCoord; in vec4 color; out vec4 FragColor; void main() { - vec4 texcolor = texture(tex, texCoord) * color; - FragColor = texcolor; + FragColor = textureLod(tex, texCoord, 0) * color; } "; #end + + + // 2D layer merge + #if kha_direct3d11 + + public static var layerMergeVert = " +struct SPIRV_Cross_Output { float2 texCoord : TEXCOORD0; float4 gl_Position : SV_Position; }; +SPIRV_Cross_Output main(float2 pos : TEXCOORD0) { + SPIRV_Cross_Output stage_output; + stage_output.gl_Position = float4(pos.xy, 0.0, 1.0); + stage_output.gl_Position.z = (stage_output.gl_Position.z + stage_output.gl_Position.w) * 0.5; + const float2 madd = float2(0.5, 0.5); + stage_output.texCoord = pos.xy * madd + madd; + stage_output.texCoord.y = 1.0 - stage_output.texCoord.y; + return stage_output; +} +"; + public static var layerMergeFrag = " +Texture2D tex0; +SamplerState _tex0_sampler; +Texture2D tex1; +SamplerState _tex1_sampler; +Texture2D tex2; +SamplerState _tex2_sampler; +Texture2D texa; +SamplerState _texa_sampler; +Texture2D texb; +SamplerState _texb_sampler; +Texture2D texc; +SamplerState _texc_sampler; +uniform float opac; +struct SPIRV_Cross_Output { float4 color0 : SV_Target0; float4 color1 : SV_Target1; float4 color2 : SV_Target2; }; +SPIRV_Cross_Output main(float2 texCoord : TEXCOORD0) { + float4 col0 = tex0.SampleLevel(_tex0_sampler, texCoord, 0); + float4 col1 = tex1.SampleLevel(_tex1_sampler, texCoord, 0); + float4 col2 = tex2.SampleLevel(_tex2_sampler, texCoord, 0); + float4 cola = texa.SampleLevel(_texa_sampler, texCoord, 0); + float4 colb = texb.SampleLevel(_texb_sampler, texCoord, 0); + float4 colc = texc.SampleLevel(_texc_sampler, texCoord, 0); + float str = col0.a * opac; + float invstr = 1.0 - str; + SPIRV_Cross_Output stage_output; + stage_output.color0 = float4(cola.rgb * invstr + col0.rgb * str, max(col0.a, cola.a)); + stage_output.color1 = float4(colb * invstr + col1 * str); + stage_output.color2 = float4(colc * invstr + col2 * str); + return stage_output; +} +"; + public static var maskMergeFrag = " +Texture2D tex0; +SamplerState _tex0_sampler; +Texture2D texa; +SamplerState _texa_sampler; +struct SPIRV_Cross_Output { float4 color0 : SV_Target0; }; +SPIRV_Cross_Output main(float2 texCoord : TEXCOORD0) { + float4 col0 = tex0.SampleLevel(_tex0_sampler, texCoord, 0); + float mask = texa.SampleLevel(_texa_sampler, texCoord, 0).r; + SPIRV_Cross_Output stage_output; + stage_output.color0 = float4(col0.rgb, col0.a * mask); + return stage_output; +} +"; + + #else // kha_opengl + + public static var layerMergeVert = "#version 330 +in vec2 pos; +out vec2 texCoord; +void main() { + gl_Position = vec4(pos.xy, 0.0, 1.0); + const vec2 madd = vec2(0.5, 0.5); + texCoord = pos.xy * madd + madd; +} +"; + public static var layerMergeFrag = "#version 330 +uniform sampler2D tex0; +uniform sampler2D tex1; +uniform sampler2D tex2; +uniform sampler2D texa; +uniform sampler2D texb; +uniform sampler2D texc; +uniform float opac; +in vec2 texCoord; +out vec4 FragColor[3]; +void main() { + vec4 col0 = textureLod(tex0, texCoord, 0); + vec4 col1 = textureLod(tex1, texCoord, 0); + vec4 col2 = textureLod(tex2, texCoord, 0); + vec4 cola = textureLod(texa, texCoord, 0); + vec4 colb = textureLod(texb, texCoord, 0); + vec4 colc = textureLod(texc, texCoord, 0); + float str = col0.a * opac; + float invstr = 1.0 - str; + FragColor[0] = vec4(cola.rgb * invstr + col0.rgb * str, max(col0.a, cola.a)); + FragColor[1] = vec4(colb * invstr + col1 * str); + FragColor[2] = vec4(colc * invstr + col2 * str); +} +"; + public static var maskMergeFrag = "#version 330 +uniform sampler2D tex0; +uniform sampler2D texa; +in vec2 texCoord; +out vec4 FragColor; +void main() { + vec4 col0 = textureLod(tex0, texCoord, 0); + float mask = textureLod(texa, texCoord, 0).r; + FragColor = vec4(col0.rgb, col0.a * mask); +} +"; + #end } diff --git a/Sources/arm/LayerSlot.hx b/Sources/arm/LayerSlot.hx index ba3b8c4d..8daac988 100644 --- a/Sources/arm/LayerSlot.hx +++ b/Sources/arm/LayerSlot.hx @@ -180,4 +180,30 @@ class LayerSlot { texpaint_mask_preview.unload(); } + + public function applyMask() { + if (texpaint_mask == null) return; + + if (Layers.pipe == null) Layers.makePipe(); + Layers.makeTempImg(); + + // Copy layer to temp + Layers.imga.g2.begin(false); + Layers.imga.g2.pipeline = Layers.pipeCopy; + Layers.imga.g2.drawImage(texpaint, 0, 0); + Layers.imga.g2.end(); + + // Merge mask + if (iron.data.ConstData.screenAlignedVB == null) iron.data.ConstData.createScreenAlignedData(); + texpaint.g4.begin(); + texpaint.g4.setPipeline(Layers.pipeMask); + texpaint.g4.setTexture(Layers.tex0Mask, Layers.imga); + texpaint.g4.setTexture(Layers.texaMask, texpaint_mask); + texpaint.g4.setVertexBuffer(iron.data.ConstData.screenAlignedVB); + texpaint.g4.setIndexBuffer(iron.data.ConstData.screenAlignedIB); + texpaint.g4.drawIndexedVertices(); + texpaint.g4.end(); + + deleteMask(); + } } diff --git a/Sources/arm/Layers.hx b/Sources/arm/Layers.hx index b46abe3d..47e97f15 100644 --- a/Sources/arm/Layers.hx +++ b/Sources/arm/Layers.hx @@ -6,6 +6,22 @@ import iron.RenderPath; import arm.ui.*; class Layers { + + public static var pipe:kha.graphics4.PipelineState = null; + public static var pipeCopy:kha.graphics4.PipelineState; + public static var pipeMask:kha.graphics4.PipelineState; + static var tex0:kha.graphics4.TextureUnit; + static var tex1:kha.graphics4.TextureUnit; + static var tex2:kha.graphics4.TextureUnit; + static var texa:kha.graphics4.TextureUnit; + static var texb:kha.graphics4.TextureUnit; + static var texc:kha.graphics4.TextureUnit; + static var opac:kha.graphics4.ConstantLocation; + public static var tex0Mask:kha.graphics4.TextureUnit; + public static var texaMask:kha.graphics4.TextureUnit; + public static var imga:kha.Image = null; + public static var imgb:kha.Image = null; + public static var imgc:kha.Image = null; public static function initLayers(g:kha.graphics4.Graphics) { g.end(); @@ -136,54 +152,116 @@ class Layers { UITrait.inst.setLayer(UITrait.inst.layers[0]); } - static function makePipe() { - UITrait.inst.pipe = new kha.graphics4.PipelineState(); - UITrait.inst.pipe.vertexShader = kha.graphics4.VertexShader.fromSource(ConstData.painterVert); - UITrait.inst.pipe.fragmentShader = kha.graphics4.FragmentShader.fromSource(ConstData.painterFrag); + public static function makePipe() { + pipe = new kha.graphics4.PipelineState(); + pipe.vertexShader = kha.graphics4.VertexShader.fromSource(ConstData.layerMergeVert); + pipe.fragmentShader = kha.graphics4.FragmentShader.fromSource(ConstData.layerMergeFrag); + var vs = new kha.graphics4.VertexStructure(); + vs.add("pos", kha.graphics4.VertexData.Float2); + pipe.inputLayout = [vs]; + pipe.compile(); + tex0 = pipe.getTextureUnit("tex0"); + tex1 = pipe.getTextureUnit("tex1"); + tex2 = pipe.getTextureUnit("tex2"); + texa = pipe.getTextureUnit("texa"); + texb = pipe.getTextureUnit("texb"); + texc = pipe.getTextureUnit("texc"); + opac = pipe.getConstantLocation("opac"); + + pipeCopy = new kha.graphics4.PipelineState(); + pipeCopy.vertexShader = kha.graphics4.VertexShader.fromSource(ConstData.layerViewVert); + pipeCopy.fragmentShader = kha.graphics4.FragmentShader.fromSource(ConstData.layerViewFrag); var vs = new kha.graphics4.VertexStructure(); vs.add("pos", kha.graphics4.VertexData.Float3); vs.add("tex", kha.graphics4.VertexData.Float2); vs.add("col", kha.graphics4.VertexData.Float4); - UITrait.inst.pipe.inputLayout = [vs]; - UITrait.inst.pipe.blendSource = kha.graphics4.BlendingFactor.SourceAlpha; - UITrait.inst.pipe.blendDestination = kha.graphics4.BlendingFactor.InverseSourceAlpha; - UITrait.inst.pipe.colorWriteMaskAlpha = false; // TODO: use texpaint.a to merge all layer channels instead - UITrait.inst.pipe.compile(); + pipeCopy.inputLayout = [vs]; + pipeCopy.compile(); + + pipeMask = new kha.graphics4.PipelineState(); + pipeMask.vertexShader = kha.graphics4.VertexShader.fromSource(ConstData.layerMergeVert); + pipeMask.fragmentShader = kha.graphics4.FragmentShader.fromSource(ConstData.maskMergeFrag); + var vs = new kha.graphics4.VertexStructure(); + vs.add("pos", kha.graphics4.VertexData.Float2); + pipeMask.inputLayout = [vs]; + pipeMask.compile(); + tex0Mask = pipeMask.getTextureUnit("tex0"); + texaMask = pipeMask.getTextureUnit("texa"); } - public static function applySelectedLayer(g:kha.graphics4.Graphics) { - if (UITrait.inst.pipe == null) makePipe(); + public static function makeTempImg() { + var l = UITrait.inst.layers[0]; + if (imga != null && imga.width != l.texpaint.width) { + imga.unload(); + imgb.unload(); + imgc.unload(); + imga = null; + imgb = null; + imgc = null; + } + if (imga == null) { + imga = kha.Image.createRenderTarget(l.texpaint.width, l.texpaint.height); + imgb = kha.Image.createRenderTarget(l.texpaint.width, l.texpaint.height); + imgc = kha.Image.createRenderTarget(l.texpaint.width, l.texpaint.height); + } + } + + public static function mergeSelectedLayer(g:kha.graphics4.Graphics) { + if (pipe == null) makePipe(); var l0 = UITrait.inst.layers[0]; var l1 = UITrait.inst.selectedLayer; - // for (i in 1...UITrait.inst.layers.length) { // Merge down - // if (UITrait.inst.layers[i] == l1) { - // l0 = UITrait.inst.layers[i - 1]; - // break; - // } - // } + for (i in 1...UITrait.inst.layers.length) { // Merge down + if (UITrait.inst.layers[i] == l1) { + l0 = UITrait.inst.layers[i - 1]; + break; + } + } g.end(); - l0.texpaint.g2.begin(false); - l0.texpaint.g2.pipeline = UITrait.inst.pipe; - l0.texpaint.g2.drawImage(l1.texpaint, 0, 0); - l0.texpaint.g2.end(); + makeTempImg(); - l0.texpaint_nor.g2.begin(false); - l0.texpaint_nor.g2.pipeline = UITrait.inst.pipe; - l0.texpaint_nor.g2.drawImage(l1.texpaint_nor, 0, 0); - l0.texpaint_nor.g2.end(); + if (l1.texpaint_mask != null) { + l1.applyMask(); + } - l0.texpaint_pack.g2.begin(false); - l0.texpaint_pack.g2.pipeline = UITrait.inst.pipe; - l0.texpaint_pack.g2.drawImage(l1.texpaint_pack, 0, 0); - l0.texpaint_pack.g2.end(); + // Copy layer0 to temp + imga.g2.begin(false); + imga.g2.pipeline = pipeCopy; + imga.g2.drawImage(l0.texpaint, 0, 0); + imga.g2.end(); + imgb.g2.begin(false); + imgb.g2.pipeline = pipeCopy; + imgb.g2.drawImage(l0.texpaint_nor, 0, 0); + imgb.g2.end(); + imgc.g2.begin(false); + imgc.g2.pipeline = pipeCopy; + imgc.g2.drawImage(l0.texpaint_pack, 0, 0); + imgc.g2.end(); + + // Merge into layer0 + if (iron.data.ConstData.screenAlignedVB == null) iron.data.ConstData.createScreenAlignedData(); + l0.texpaint.g4.begin([l0.texpaint_nor, l0.texpaint_pack]); + l0.texpaint.g4.setPipeline(pipe); + l0.texpaint.g4.setTexture(tex0, l1.texpaint); + l0.texpaint.g4.setTexture(tex1, l1.texpaint_nor); + l0.texpaint.g4.setTexture(tex2, l1.texpaint_pack); + l0.texpaint.g4.setTexture(texa, imga); + l0.texpaint.g4.setTexture(texb, imgb); + l0.texpaint.g4.setTexture(texc, imgc); + l0.texpaint.g4.setFloat(opac, l1.maskOpacity); + l0.texpaint.g4.setVertexBuffer(iron.data.ConstData.screenAlignedVB); + l0.texpaint.g4.setIndexBuffer(iron.data.ConstData.screenAlignedIB); + l0.texpaint.g4.drawIndexedVertices(); + l0.texpaint.g4.end(); g.begin(); deleteSelectedLayer(); - iron.App.removeRender(applySelectedLayer); + iron.App.removeRender(mergeSelectedLayer); + UITrait.inst.setLayer(l0); + UITrait.inst.layerPreviewDirty = true; } } diff --git a/Sources/arm/ui/UITrait.hx b/Sources/arm/ui/UITrait.hx index 8b16bd80..51fa1337 100644 --- a/Sources/arm/ui/UITrait.hx +++ b/Sources/arm/ui/UITrait.hx @@ -162,7 +162,6 @@ class UITrait extends iron.Trait { var axisZ = false; var axisStart = 0.0; var row4 = [1/4, 1/4, 1/4, 1/4]; - public var pipe:kha.graphics4.PipelineState = null; public var brushNodesRadius = 1.0; public var brushNodesOpacity = 1.0; @@ -705,6 +704,7 @@ class UITrait extends iron.Trait { selectPaintObject(paintObjects[opos]); setLayer(layers[lpos]); selectedLayer.swap(lay); + layerPreviewDirty = true; } undoI = (undoI + 1) % C.undo_steps; undos++; @@ -1893,6 +1893,8 @@ class UITrait extends iron.Trait { } if (ui.button("Apply", Left)) { setLayer(l); + l.applyMask(); + setLayer(l); // Parse mesh material } }); } @@ -1920,7 +1922,7 @@ class UITrait extends iron.Trait { ui.text(l.name, Right); } else { - ui.fill(0, 0, ui._w, ui.t.ELEMENT_H * 14, ui.t.SEPARATOR_COL); + ui.fill(0, 0, ui._w, ui.t.ELEMENT_H * 16, ui.t.SEPARATOR_COL); ui.text(l.name, Right); if (ui.button("Delete", Left) && l != layers[0]) { selectedLayer = l; @@ -1946,7 +1948,7 @@ class UITrait extends iron.Trait { } if (ui.button("Merge Down", Left) && l != layers[0]) { setLayer(l); - iron.App.notifyOnRender(Layers.applySelectedLayer); + iron.App.notifyOnRender(Layers.mergeSelectedLayer); } if (ui.button("Duplicate", Left) && l != layers[0]) { setLayer(l); diff --git a/Sources/arm/ui/UIView2D.hx b/Sources/arm/ui/UIView2D.hx index 1fb7d0c5..04747c36 100644 --- a/Sources/arm/ui/UIView2D.hx +++ b/Sources/arm/ui/UIView2D.hx @@ -32,8 +32,8 @@ class UIView2D extends iron.Trait { inst = this; pipe = new kha.graphics4.PipelineState(); - pipe.vertexShader = kha.graphics4.VertexShader.fromSource(ConstData.painterVert); - pipe.fragmentShader = kha.graphics4.FragmentShader.fromSource(ConstData.painterFrag); + pipe.vertexShader = kha.graphics4.VertexShader.fromSource(ConstData.layerViewVert); + pipe.fragmentShader = kha.graphics4.FragmentShader.fromSource(ConstData.layerViewFrag); var vs = new kha.graphics4.VertexStructure(); vs.add("pos", kha.graphics4.VertexData.Float3); vs.add("tex", kha.graphics4.VertexData.Float2);