Files
armorpaint/Sources/arm/Layers.hx
T

417 lines
14 KiB
Haxe
Raw Normal View History

2019-02-02 18:49:19 +01:00
package arm;
2019-06-20 11:23:01 +02:00
import kha.Image;
2019-03-13 16:03:40 +01:00
import kha.graphics4.TextureFormat;
2019-05-10 19:28:59 +02:00
import kha.graphics4.TextureUnit;
import kha.graphics4.ConstantLocation;
2019-06-20 11:23:01 +02:00
import kha.graphics4.PipelineState;
import kha.graphics4.VertexStructure;
import kha.graphics4.VertexData;
import kha.graphics4.BlendingFactor;
import kha.graphics4.CompareMode;
2019-02-02 18:49:19 +01:00
import iron.RenderPath;
2019-04-16 22:34:47 +02:00
import arm.ui.UITrait;
2019-06-23 14:50:41 +02:00
import arm.data.LayerSlot;
2019-11-13 15:17:10 +01:00
import arm.node.MaterialParser;
2019-06-20 11:23:01 +02:00
import arm.render.RenderPathPaint;
2019-06-23 14:50:41 +02:00
import arm.util.MeshUtil;
2019-05-10 19:28:59 +02:00
import arm.Tool;
2019-09-13 10:14:17 +02:00
import arm.Project;
2019-02-02 18:49:19 +01:00
class Layers {
2019-04-16 00:04:28 +02:00
2019-12-12 14:34:11 +01:00
public static var pipeMerge: PipelineState = null;
2019-12-09 00:28:10 +01:00
public static var pipeCopy: PipelineState;
public static var pipeMask: PipelineState;
public static var tex0: TextureUnit;
public static var tex1: TextureUnit;
2019-12-12 14:34:11 +01:00
public static var texmask: TextureUnit;
2019-12-09 00:28:10 +01:00
public static var texa: TextureUnit;
public static var opac: ConstantLocation;
public static var blending: ConstantLocation;
public static var tex0Mask: TextureUnit;
public static var texaMask: TextureUnit;
public static var imga: Image = null;
public static var expa: Image = null;
public static var expb: Image = null;
public static var expc: Image = null;
public static var pipeCursor: PipelineState;
public static var cursorVP: ConstantLocation;
public static var cursorInvVP: ConstantLocation;
public static var cursorMouse: ConstantLocation;
2020-02-04 17:26:07 +01:00
public static var cursorTexStep: ConstantLocation;
2019-12-09 00:28:10 +01:00
public static var cursorRadius: ConstantLocation;
public static var cursorTex: TextureUnit;
public static var cursorGbufferD: TextureUnit;
2019-08-13 14:36:15 +02:00
public static inline var defaultBase = 0.5;
public static inline var defaultRough = 0.4;
2019-10-06 19:03:59 +02:00
2019-12-09 00:28:10 +01:00
public static function initLayers(g: kha.graphics4.Graphics) {
2019-02-02 18:49:19 +01:00
g.end();
2019-06-23 14:50:41 +02:00
var layers = Project.layers;
2019-02-02 18:49:19 +01:00
layers[0].texpaint.g4.begin();
2020-01-05 10:58:03 +01:00
layers[0].texpaint.g4.clear(kha.Color.fromFloats(defaultBase, defaultBase, defaultBase, 1.0)); // Base
2019-02-02 18:49:19 +01:00
layers[0].texpaint.g4.end();
layers[0].texpaint_nor.g4.begin();
2019-03-13 16:03:40 +01:00
layers[0].texpaint_nor.g4.clear(kha.Color.fromFloats(0.5, 0.5, 1.0, 0.0)); // Nor
2019-02-02 18:49:19 +01:00
layers[0].texpaint_nor.g4.end();
layers[0].texpaint_pack.g4.begin();
2019-08-13 14:36:15 +02:00
layers[0].texpaint_pack.g4.clear(kha.Color.fromFloats(1.0, defaultRough, 0.0, 0.0)); // Occ, rough, met
2019-02-02 18:49:19 +01:00
layers[0].texpaint_pack.g4.end();
g.begin();
iron.App.removeRender(initLayers);
2019-06-23 14:50:41 +02:00
Context.layerPreviewDirty = true;
Context.ddirty = 3;
2019-02-02 18:49:19 +01:00
}
2019-12-09 00:28:10 +01:00
public static function resizeLayers(g: kha.graphics4.Graphics) {
2019-06-23 15:50:07 +02:00
var C = Config.raw;
2020-01-22 16:25:40 +01:00
if (App.resHandle.position >= Std.int(Res16384)) { // Save memory for >=16k
2019-12-12 14:34:11 +01:00
C.undo_steps = 1;
2019-02-02 18:49:19 +01:00
if (UITrait.inst.undoHandle != null) UITrait.inst.undoHandle.value = C.undo_steps;
2019-06-23 14:50:41 +02:00
while (History.undoLayers.length > C.undo_steps) { var l = History.undoLayers.pop(); l.unload(); }
2019-02-02 18:49:19 +01:00
}
g.end();
2019-06-23 14:50:41 +02:00
for (l in Project.layers) l.resizeAndSetBits();
for (l in History.undoLayers) l.resizeAndSetBits();
2019-03-12 23:20:48 +01:00
var rts = RenderPath.active.renderTargets;
2019-03-27 18:26:37 +01:00
rts.get("texpaint_blend0").image.unload();
rts.get("texpaint_blend0").raw.width = Config.getTextureRes();
rts.get("texpaint_blend0").raw.height = Config.getTextureRes();
2019-06-20 11:23:01 +02:00
rts.get("texpaint_blend0").image = Image.createRenderTarget(Config.getTextureRes(), Config.getTextureRes(), TextureFormat.L8);
2019-03-27 18:26:37 +01:00
rts.get("texpaint_blend1").image.unload();
rts.get("texpaint_blend1").raw.width = Config.getTextureRes();
rts.get("texpaint_blend1").raw.height = Config.getTextureRes();
2019-06-20 11:23:01 +02:00
rts.get("texpaint_blend1").image = Image.createRenderTarget(Config.getTextureRes(), Config.getTextureRes(), TextureFormat.L8);
2019-06-23 14:50:41 +02:00
Context.brushBlendDirty = true;
2019-07-02 12:09:47 +02:00
if (rts.get("texpaint_blur") != null) {
rts.get("texpaint_blur").image.unload();
var size = Std.int(Config.getTextureRes() * 0.95);
rts.get("texpaint_blur").raw.width = size;
rts.get("texpaint_blur").raw.height = size;
rts.get("texpaint_blur").image = Image.createRenderTarget(size, size);
}
2019-12-12 00:59:10 +01:00
#if kha_direct3d12
arm.render.RenderPathRaytrace.ready = false; // Rebuild baketex
#end
2019-02-02 18:49:19 +01:00
g.begin();
2019-06-23 14:50:41 +02:00
Context.ddirty = 2;
2019-02-02 18:49:19 +01:00
iron.App.removeRender(resizeLayers);
}
2019-12-09 00:28:10 +01:00
public static function setLayerBits(g: kha.graphics4.Graphics) {
2019-06-18 08:36:19 +02:00
g.end();
2019-06-23 14:50:41 +02:00
for (l in Project.layers) l.resizeAndSetBits();
for (l in History.undoLayers) l.resizeAndSetBits();
2019-06-18 08:36:19 +02:00
g.begin();
iron.App.removeRender(setLayerBits);
}
2019-04-16 00:04:28 +02:00
public static function makePipe() {
2019-12-12 14:34:11 +01:00
pipeMerge = new PipelineState();
pipeMerge.vertexShader = Reflect.field(kha.Shaders, "layer_merge_vert");
pipeMerge.fragmentShader = Reflect.field(kha.Shaders, "layer_merge_frag");
2019-06-20 11:23:01 +02:00
var vs = new VertexStructure();
vs.add("pos", VertexData.Float2);
2019-12-12 14:34:11 +01:00
pipeMerge.inputLayout = [vs];
pipeMerge.compile();
tex0 = pipeMerge.getTextureUnit("tex0"); // Always binding texpaint.a for blending
tex1 = pipeMerge.getTextureUnit("tex1");
texmask = pipeMerge.getTextureUnit("texmask");
texa = pipeMerge.getTextureUnit("texa");
opac = pipeMerge.getConstantLocation("opac");
blending = pipeMerge.getConstantLocation("blending");
2019-04-16 00:04:28 +02:00
2019-06-20 11:23:01 +02:00
pipeCopy = new PipelineState();
2019-11-11 17:14:51 +01:00
pipeCopy.vertexShader = Reflect.field(kha.Shaders, "layer_view_vert");
pipeCopy.fragmentShader = Reflect.field(kha.Shaders, "layer_view_frag");
2019-06-20 11:23:01 +02:00
var vs = new VertexStructure();
vs.add("pos", VertexData.Float3);
vs.add("tex", VertexData.Float2);
vs.add("col", VertexData.Float4);
2019-04-16 00:04:28 +02:00
pipeCopy.inputLayout = [vs];
pipeCopy.compile();
2019-06-20 11:23:01 +02:00
pipeMask = new PipelineState();
2019-11-11 17:14:51 +01:00
pipeMask.vertexShader = Reflect.field(kha.Shaders, "layer_merge_vert");
pipeMask.fragmentShader = Reflect.field(kha.Shaders, "mask_merge_frag");
2019-06-20 11:23:01 +02:00
var vs = new VertexStructure();
vs.add("pos", VertexData.Float2);
2019-04-16 00:04:28 +02:00
pipeMask.inputLayout = [vs];
pipeMask.compile();
tex0Mask = pipeMask.getTextureUnit("tex0");
texaMask = pipeMask.getTextureUnit("texa");
}
2019-05-20 15:23:13 +02:00
public static function makeCursorPipe() {
2019-06-20 11:23:01 +02:00
pipeCursor = new PipelineState();
2019-11-11 17:14:51 +01:00
pipeCursor.vertexShader = Reflect.field(kha.Shaders, "cursor_vert");
pipeCursor.fragmentShader = Reflect.field(kha.Shaders, "cursor_frag");
2019-06-20 11:23:01 +02:00
var vs = new VertexStructure();
vs.add("pos", VertexData.Short4Norm);
vs.add("nor", VertexData.Short2Norm);
vs.add("tex", VertexData.Short2Norm);
2019-05-20 15:23:13 +02:00
pipeCursor.inputLayout = [vs];
2019-06-20 11:23:01 +02:00
pipeCursor.blendSource = BlendingFactor.SourceAlpha;
pipeCursor.blendDestination = BlendingFactor.InverseSourceAlpha;
2019-05-20 15:23:13 +02:00
pipeCursor.depthWrite = false;
2019-06-20 11:23:01 +02:00
pipeCursor.depthMode = CompareMode.Always;
2019-05-20 15:23:13 +02:00
pipeCursor.compile();
cursorVP = pipeCursor.getConstantLocation("VP");
cursorInvVP = pipeCursor.getConstantLocation("invVP");
cursorMouse = pipeCursor.getConstantLocation("mouse");
2020-02-04 17:26:07 +01:00
cursorTexStep = pipeCursor.getConstantLocation("texStep");
2019-06-01 16:51:31 +02:00
cursorRadius = pipeCursor.getConstantLocation("radius");
2019-05-20 15:23:13 +02:00
cursorGbufferD = pipeCursor.getTextureUnit("gbufferD");
2019-05-29 16:20:16 +02:00
cursorTex = pipeCursor.getTextureUnit("tex");
2019-05-20 15:23:13 +02:00
}
2019-04-16 00:04:28 +02:00
public static function makeTempImg() {
2019-06-23 14:50:41 +02:00
var l = Project.layers[0];
2019-04-16 00:04:28 +02:00
if (imga != null && imga.width != l.texpaint.width) {
2019-12-07 16:49:28 +01:00
RenderPath.active.renderTargets.get("temptex0").unload();
RenderPath.active.renderTargets.remove("temptex0");
2019-04-16 00:04:28 +02:00
imga = null;
}
if (imga == null) {
2019-12-07 16:49:28 +01:00
{
var t = new RenderTargetRaw();
t.name = "temptex0";
t.width = l.texpaint.width;
t.height = l.texpaint.height;
2019-12-09 00:28:10 +01:00
t.format = "RGBA32";
2019-12-07 16:49:28 +01:00
var rt = RenderPath.active.createRenderTarget(t);
imga = rt.image;
}
2019-04-16 00:04:28 +02:00
}
2019-02-02 18:49:19 +01:00
}
2019-05-15 16:46:21 +02:00
public static function makeExportImg() {
2019-06-23 14:50:41 +02:00
var l = Project.layers[0];
2019-05-15 16:46:21 +02:00
if (expa != null && expa.width != l.texpaint.width) {
expa.unload();
expb.unload();
expc.unload();
expa = null;
expb = null;
expc = null;
}
if (expa == null) {
2019-06-20 11:23:01 +02:00
expa = Image.createRenderTarget(l.texpaint.width, l.texpaint.height);
expb = Image.createRenderTarget(l.texpaint.width, l.texpaint.height);
expc = Image.createRenderTarget(l.texpaint.width, l.texpaint.height);
2019-05-15 16:46:21 +02:00
}
}
2019-12-09 00:28:10 +01:00
public static function mergeSelectedLayer(g: kha.graphics4.Graphics) {
2019-12-12 14:34:11 +01:00
if (pipeMerge == null) makePipe();
2019-02-02 18:49:19 +01:00
2019-06-23 14:50:41 +02:00
var l0 = Project.layers[0];
var l1 = Context.layer;
2019-10-06 19:03:59 +02:00
2019-06-23 14:50:41 +02:00
for (i in 1...Project.layers.length) { // Merge down
if (Project.layers[i] == l1) {
l0 = Project.layers[i - 1];
2019-04-16 00:04:28 +02:00
break;
}
}
2019-02-02 18:49:19 +01:00
g.end();
2019-04-16 00:04:28 +02:00
makeTempImg();
2019-02-02 18:49:19 +01:00
2019-04-16 00:04:28 +02:00
if (l1.texpaint_mask != null) {
l1.applyMask();
}
2019-02-02 18:49:19 +01:00
2019-12-12 14:34:11 +01:00
// Merge into layer below
if (iron.data.ConstData.screenAlignedVB == null) iron.data.ConstData.createScreenAlignedData();
imga.g2.begin(false); // Copy to temp
2019-04-16 00:04:28 +02:00
imga.g2.pipeline = pipeCopy;
imga.g2.drawImage(l0.texpaint, 0, 0);
2020-01-17 00:38:22 +01:00
imga.g2.pipeline = null;
2019-04-16 00:04:28 +02:00
imga.g2.end();
2019-12-12 14:34:11 +01:00
l0.texpaint.g4.begin();
l0.texpaint.g4.setPipeline(pipeMerge);
2019-04-16 00:04:28 +02:00
l0.texpaint.g4.setTexture(tex0, l1.texpaint);
2019-12-12 14:34:11 +01:00
var empty = RenderPath.active.renderTargets.get("empty_white").image;
l0.texpaint.g4.setTexture(tex1, empty);
l0.texpaint.g4.setTexture(texmask, empty);
2019-04-16 00:04:28 +02:00
l0.texpaint.g4.setTexture(texa, imga);
l0.texpaint.g4.setFloat(opac, l1.maskOpacity);
2019-09-19 00:04:05 +02:00
l0.texpaint.g4.setInt(blending, l1.blending);
2019-04-16 00:04:28 +02:00
l0.texpaint.g4.setVertexBuffer(iron.data.ConstData.screenAlignedVB);
l0.texpaint.g4.setIndexBuffer(iron.data.ConstData.screenAlignedIB);
l0.texpaint.g4.drawIndexedVertices();
l0.texpaint.g4.end();
2019-02-02 18:49:19 +01:00
2019-12-12 14:34:11 +01:00
imga.g2.begin(false);
imga.g2.pipeline = pipeCopy;
imga.g2.drawImage(l0.texpaint_nor, 0, 0);
2020-01-17 00:38:22 +01:00
imga.g2.pipeline = null;
2019-12-12 14:34:11 +01:00
imga.g2.end();
l0.texpaint_nor.g4.begin();
l0.texpaint_nor.g4.setPipeline(pipeMerge);
l0.texpaint_nor.g4.setTexture(tex0, l1.texpaint);
l0.texpaint_nor.g4.setTexture(tex1, l1.texpaint_nor);
l0.texpaint_nor.g4.setTexture(texmask, empty);
l0.texpaint_nor.g4.setTexture(texa, imga);
l0.texpaint_nor.g4.setFloat(opac, l1.maskOpacity);
l0.texpaint.g4.setInt(blending, -1);
l0.texpaint_nor.g4.setVertexBuffer(iron.data.ConstData.screenAlignedVB);
l0.texpaint_nor.g4.setIndexBuffer(iron.data.ConstData.screenAlignedIB);
l0.texpaint_nor.g4.drawIndexedVertices();
l0.texpaint_nor.g4.end();
imga.g2.begin(false);
imga.g2.pipeline = pipeCopy;
imga.g2.drawImage(l0.texpaint_pack, 0, 0);
2020-01-17 00:38:22 +01:00
imga.g2.pipeline = null;
2019-12-12 14:34:11 +01:00
imga.g2.end();
l0.texpaint_pack.g4.begin();
l0.texpaint_pack.g4.setPipeline(pipeMerge);
l0.texpaint_pack.g4.setTexture(tex0, l1.texpaint);
l0.texpaint_pack.g4.setTexture(tex1, l1.texpaint_pack);
l0.texpaint_pack.g4.setTexture(texmask, empty);
l0.texpaint_pack.g4.setTexture(texa, imga);
l0.texpaint_pack.g4.setFloat(opac, l1.maskOpacity);
l0.texpaint.g4.setInt(blending, -1);
l0.texpaint_pack.g4.setVertexBuffer(iron.data.ConstData.screenAlignedVB);
l0.texpaint_pack.g4.setIndexBuffer(iron.data.ConstData.screenAlignedIB);
l0.texpaint_pack.g4.drawIndexedVertices();
l0.texpaint_pack.g4.end();
2019-02-02 18:49:19 +01:00
g.begin();
2019-11-11 15:35:00 +01:00
Context.layer.delete();
2019-04-16 00:04:28 +02:00
iron.App.removeRender(mergeSelectedLayer);
2019-06-23 14:50:41 +02:00
Context.setLayer(l0);
Context.layerPreviewDirty = true;
2019-02-02 18:49:19 +01:00
}
2019-04-16 22:34:47 +02:00
2019-12-09 00:28:10 +01:00
public static function isFillMaterial(): Bool {
2019-06-23 14:50:41 +02:00
var m = Context.material;
for (l in Project.layers) if (l.material_mask == m) return true;
2019-04-16 22:34:47 +02:00
return false;
}
public static function updateFillLayers(fills = 1) {
2019-06-23 14:50:41 +02:00
var layers = Project.layers;
var selectedLayer = Context.layer;
var isMask = Context.layerIsMask;
var selectedTool = Context.tool;
2019-12-09 00:28:10 +01:00
var current: kha.graphics4.Graphics2 = null;
2019-04-16 22:34:47 +02:00
var first = true;
for (l in layers) {
2019-10-21 23:18:44 +02:00
if (l.material_mask == Context.material) {
2019-04-16 22:34:47 +02:00
if (first) {
current = @:privateAccess kha.graphics4.Graphics2.current;
if (current != null) current.end();
2019-06-23 14:50:41 +02:00
Context.pdirty = fills;
Context.layerIsMask = false;
Context.tool = ToolFill;
2019-04-16 22:34:47 +02:00
}
2019-06-23 14:50:41 +02:00
Context.layer = l;
setObjectMask();
2019-04-16 22:34:47 +02:00
if (first) {
first = false;
2019-06-20 11:23:01 +02:00
MaterialParser.parsePaintMaterial();
2019-04-16 22:34:47 +02:00
}
2019-10-06 19:03:59 +02:00
2019-04-16 22:34:47 +02:00
for (i in 0...fills) {
2019-06-20 11:23:01 +02:00
RenderPathPaint.commandsPaint();
2019-04-16 22:34:47 +02:00
}
}
}
if (!first) {
2019-06-23 14:50:41 +02:00
Context.pdirty = 0;
Context.ddirty = 2;
Context.rdirty = 2;
2019-04-16 22:34:47 +02:00
if (current != null) current.begin(false);
2019-06-23 14:50:41 +02:00
Context.layer = selectedLayer;
Context.layerIsMask = isMask;
setObjectMask();
Context.tool = selectedTool;
}
}
public static function setObjectMask() {
var ar = ["None"];
2019-06-24 22:35:17 +02:00
for (p in Project.paintObjects) ar.push(p.name);
2019-06-23 14:50:41 +02:00
var mask = Context.layer.objectMask;
if (UITrait.inst.layerFilter > 0) mask = UITrait.inst.layerFilter;
if (mask > 0) {
if (Context.mergedObject != null) Context.mergedObject.visible = false;
2019-06-24 22:35:17 +02:00
var o = Project.paintObjects[0];
for (p in Project.paintObjects) if (p.name == ar[mask]) { o = p; break; }
2019-06-23 14:50:41 +02:00
Context.selectPaintObject(o);
}
else {
if (Context.mergedObject == null) {
MeshUtil.mergeMesh();
}
Context.selectPaintObject(Context.mainObject());
Context.paintObject.skip_context = "paint";
Context.mergedObject.visible = true;
}
}
2019-12-09 00:28:10 +01:00
public static function newLayer(clear = true): LayerSlot {
2019-06-23 14:50:41 +02:00
if (Project.layers.length > 255) return null;
var l = new LayerSlot();
2020-01-24 00:25:18 +01:00
l.objectMask = UITrait.inst.layerFilter;
2019-06-23 14:50:41 +02:00
Project.layers.push(l);
Context.setLayer(l);
2019-11-11 15:35:00 +01:00
if (clear) iron.App.notifyOnRender(l.clear);
2019-06-23 14:50:41 +02:00
Context.layerPreviewDirty = true;
return l;
}
2020-01-26 13:54:27 +01:00
public static function newGroup(): LayerSlot {
if (Project.layers.length > 255) return null;
var l = new LayerSlot("", true);
Project.layers.push(l);
Context.setLayer(l);
return l;
}
2019-06-23 14:50:41 +02:00
public static function createFillLayer() {
2019-12-09 00:28:10 +01:00
function makeFill(g: kha.graphics4.Graphics) {
2019-06-26 16:34:36 +02:00
g.end();
2019-06-27 13:35:58 +02:00
var l = newLayer(false);
2019-06-26 16:34:36 +02:00
History.newLayer();
l.objectMask = UITrait.inst.layerFilter;
History.toFillLayer();
2019-11-11 15:35:00 +01:00
l.toFillLayer();
2019-06-26 16:34:36 +02:00
g.begin();
iron.App.removeRender(makeFill);
}
iron.App.notifyOnRender(makeFill);
2019-06-23 14:50:41 +02:00
}
2019-12-09 00:28:10 +01:00
public static function createImageMask(asset: TAsset) {
2019-06-23 14:50:41 +02:00
var l = Context.layer;
if (l != Project.layers[0]) {
2019-06-26 16:34:36 +02:00
History.newMask();
2019-06-23 14:50:41 +02:00
l.createMask(0x00000000, true, UITrait.inst.getImage(asset));
Context.setLayer(l, true);
Context.layerPreviewDirty = true;
2019-04-16 22:34:47 +02:00
}
}
2019-02-02 18:49:19 +01:00
}