Layer merge and mask apply

This commit is contained in:
luboslenco
2019-04-16 00:04:28 +02:00
parent dfe73b7c51
commit 0d8f4bdaf5
5 changed files with 265 additions and 96 deletions
+124 -61
View File
@@ -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<float4> 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<float4> tex0;
SamplerState _tex0_sampler;
Texture2D<float4> tex1;
SamplerState _tex1_sampler;
Texture2D<float4> tex2;
SamplerState _tex2_sampler;
Texture2D<float4> texa;
SamplerState _texa_sampler;
Texture2D<float4> texb;
SamplerState _texb_sampler;
Texture2D<float4> 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<float4> tex0;
SamplerState _tex0_sampler;
Texture2D<float4> 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
}
+26
View File
@@ -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();
}
}
+108 -30
View File
@@ -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;
}
}
+5 -3
View File
@@ -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);
+2 -2
View File
@@ -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);