Files
armorpaint/Sources/arm/History.hx
T

471 lines
14 KiB
Haxe
Raw Normal View History

2019-05-11 15:59:56 +02:00
package arm;
2019-12-04 23:48:42 +01:00
import zui.Nodes;
2019-05-11 15:59:56 +02:00
import arm.ui.UITrait;
import arm.ui.UIView2D;
2019-06-26 16:34:36 +02:00
import arm.ui.UIFiles;
2019-12-04 23:48:42 +01:00
import arm.ui.UINodes;
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-05-11 15:59:56 +02:00
class History {
2019-12-09 00:28:10 +01:00
public static var steps: Array<TStep>;
2019-06-23 14:50:41 +02:00
public static var undoI = 0; // Undo layer
public static var undos = 0; // Undos available
public static var redos = 0; // Redos available
public static var pushUndo = false; // Store undo on next paint
2019-12-09 00:28:10 +01:00
public static var undoLayers: Array<LayerSlot> = null;
2019-05-11 15:59:56 +02:00
2019-06-24 22:35:17 +02:00
public static function undo() {
2019-06-23 14:50:41 +02:00
if (undos > 0) {
2019-10-28 16:18:54 +01:00
var active = steps.length - 1 - redos;
2019-06-24 22:35:17 +02:00
var step = steps[active];
if (step.name == "New Layer") {
Context.layer = Project.layers[step.layer];
2019-11-11 15:35:00 +01:00
Context.layer.delete();
2019-06-24 22:35:17 +02:00
}
else if (step.name == "Delete Layer") {
var l = Layers.newLayer(false);
2019-06-26 16:34:36 +02:00
Project.layers.insert(step.layer, Project.layers.pop());
2019-06-24 22:35:17 +02:00
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
var lay = undoLayers[undoI];
l.swap(lay);
if (step.has_mask) {
l.createMask(0, false);
l.swapMask(lay);
2019-06-26 16:34:36 +02:00
Context.setLayer(l, true);
2019-06-24 22:35:17 +02:00
Context.layersPreviewDirty = true;
}
2019-10-22 12:01:30 +02:00
l.maskOpacity = step.layer_opacity;
l.blending = step.layer_blending;
l.objectMask = step.layer_object;
2019-06-24 22:35:17 +02:00
}
else if (step.name == "Duplicate Layer") {
Context.layer = Project.layers[step.layer + 1];
2019-11-11 15:35:00 +01:00
Context.layer.delete();
2019-06-24 22:35:17 +02:00
}
else if (step.name == "Order Layers") {
var target = Project.layers[step.prev_order];
Project.layers[step.prev_order] = Project.layers[step.layer];
Project.layers[step.layer] = target;
}
else if (step.name == "Merge Layers") {
Context.layer = Project.layers[step.layer];
2019-11-11 15:35:00 +01:00
Context.layer.delete();
2019-06-24 22:35:17 +02:00
Context.layer = Layers.newLayer(false);
2019-06-26 16:34:36 +02:00
Project.layers.insert(step.layer, Project.layers.pop());
2019-06-24 22:35:17 +02:00
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
var lay = undoLayers[undoI];
Context.layer.swap(lay);
Context.layer = Layers.newLayer(false);
2019-06-26 16:34:36 +02:00
Project.layers.insert(step.layer + 1, Project.layers.pop());
2019-06-24 22:35:17 +02:00
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
var lay = undoLayers[undoI];
Context.layer.swap(lay);
2019-06-26 16:34:36 +02:00
if (step.has_mask) {
Context.layer.createMask(0, false);
Context.layer.swapMask(lay);
Context.setLayer(Context.layer, true);
}
2019-10-22 12:01:30 +02:00
Context.layer.maskOpacity = step.layer_opacity;
Context.layer.blending = step.layer_blending;
Context.layer.objectMask = step.layer_object;
2019-06-26 16:34:36 +02:00
Context.layersPreviewDirty = true;
}
else if (step.name == "New Mask") {
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
var lay = undoLayers[undoI];
Context.setLayer(Project.layers[step.layer], true);
Context.layer.swapMask(lay);
Context.layer.deleteMask();
Context.setLayer(Project.layers[step.layer], false);
}
else if (step.name == "Delete Mask") {
Context.setLayer(Project.layers[step.layer], false);
Context.layer.createMask(0, false);
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
var lay = undoLayers[undoI];
Context.layer.swapMask(lay);
Context.layersPreviewDirty = true;
Context.setLayer(Context.layer, true);
}
else if (step.name == "Apply Mask") {
Context.layer = Project.layers[step.layer];
2019-11-11 15:35:00 +01:00
Context.layer.delete();
2019-06-26 16:34:36 +02:00
Context.layer = Layers.newLayer(false);
Project.layers.insert(step.layer, Project.layers.pop());
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
var lay = undoLayers[undoI];
Context.layer.swap(lay);
Context.layer.createMask(0, false);
Context.layer.swapMask(lay);
2019-06-24 22:35:17 +02:00
Context.layersPreviewDirty = true;
2019-06-26 16:34:36 +02:00
Context.setLayer(Context.layer, true);
}
else if (step.name == "To Fill Layer") {
2019-11-11 15:35:00 +01:00
Context.layer.toPaintLayer();
2019-06-26 16:34:36 +02:00
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
var lay = undoLayers[undoI];
Context.layer.swap(lay);
}
else if (step.name == "To Paint Layer") {
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
var lay = undoLayers[undoI];
Context.layer.swap(lay);
Context.layer.material_mask = Project.materials[step.material];
2019-06-24 22:35:17 +02:00
}
2019-10-18 11:54:25 +02:00
else if (step.name == "Layer Opacity") {
Context.setLayer(Project.layers[step.layer]);
var t = Context.layer.maskOpacity;
Context.layer.maskOpacity = step.layer_opacity;
step.layer_opacity = t;
MaterialParser.parseMeshMaterial();
}
else if (step.name == "Layer Blending") {
Context.setLayer(Project.layers[step.layer]);
var t = Context.layer.blending;
Context.layer.blending = step.layer_blending;
step.layer_blending = t;
MaterialParser.parseMeshMaterial();
}
2019-12-04 23:48:42 +01:00
else if (step.name == "Edit Nodes") {
swapCanvas(step);
}
2019-06-24 22:35:17 +02:00
else { // Paint operation
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
var lay = undoLayers[undoI];
2019-06-26 16:34:36 +02:00
Context.selectPaintObject(Project.paintObjects[step.object]);
Context.setLayer(Project.layers[step.layer], step.is_mask);
step.is_mask ? Context.layer.swapMask(lay) : Context.layer.swap(lay);
2019-06-23 14:50:41 +02:00
Context.layerPreviewDirty = true;
2019-05-11 15:59:56 +02:00
}
2019-06-23 14:50:41 +02:00
undos--;
redos++;
2019-06-24 22:35:17 +02:00
UITrait.inst.hwnd.redraws = 2;
2019-10-18 11:54:25 +02:00
Context.ddirty = 2;
2019-05-11 15:59:56 +02:00
if (UIView2D.inst.show) UIView2D.inst.hwnd.redraws = 2;
}
}
2019-06-24 22:35:17 +02:00
public static function redo() {
2019-06-23 14:50:41 +02:00
if (redos > 0) {
2019-10-28 16:18:54 +01:00
var active = steps.length - redos;
2019-06-24 22:35:17 +02:00
var step = steps[active];
if (step.name == "New Layer") {
Layers.newLayer();
2019-06-26 16:34:36 +02:00
Project.layers.insert(step.layer, Project.layers.pop());
2019-06-24 22:35:17 +02:00
}
else if (step.name == "Delete Layer") {
Context.layer = Project.layers[step.layer];
swapActive();
2019-11-11 15:35:00 +01:00
Context.layer.delete();
2019-06-24 22:35:17 +02:00
}
else if (step.name == "Duplicate Layer") {
Context.layer = Project.layers[step.layer];
Context.layer = Context.layer.duplicate();
}
else if (step.name == "Order Layers") {
var target = Project.layers[step.prev_order];
Project.layers[step.prev_order] = Project.layers[step.layer];
Project.layers[step.layer] = target;
}
else if (step.name == "Merge Layers") {
Context.layer = Project.layers[step.layer + 1];
2019-06-26 16:34:36 +02:00
iron.App.notifyOnRender(redoMergeLayers);
2019-06-24 22:35:17 +02:00
iron.App.notifyOnRender(Layers.mergeSelectedLayer);
}
2019-06-26 16:34:36 +02:00
else if (step.name == "New Mask") {
Context.layer = Project.layers[step.layer];
Context.layer.createMask(0, false);
Context.setLayer(Project.layers[step.layer], true);
var lay = undoLayers[undoI];
Context.layer.swapMask(lay);
Context.layerPreviewDirty = true;
undoI = (undoI + 1) % Config.raw.undo_steps;
}
else if (step.name == "Delete Mask") {
Context.layer = Project.layers[step.layer];
swapMaskActive();
Context.layer.deleteMask();
Context.setLayer(Context.layer, false);
}
else if (step.name == "Apply Mask") {
2019-12-09 00:28:10 +01:00
function makeApply(g: kha.graphics4.Graphics) {
2019-06-26 16:34:36 +02:00
g.end();
Context.layer = Project.layers[step.layer];
copyToUndoWithMask();
Context.layer.applyMask();
Context.setLayer(Context.layer, false);
g.begin();
iron.App.removeRender(makeApply);
}
iron.App.notifyOnRender(makeApply);
}
else if (step.name == "To Fill Layer") {
var lay = undoLayers[undoI];
Context.layer.swap(lay);
Context.layer.material_mask = Project.materials[step.material];
2019-10-18 11:54:25 +02:00
undoI = (undoI + 1) % Config.raw.undo_steps;
2019-06-26 16:34:36 +02:00
}
else if (step.name == "To Paint Layer") {
2019-11-11 15:35:00 +01:00
Context.layer.toPaintLayer();
2019-06-26 16:34:36 +02:00
var lay = undoLayers[undoI];
Context.layer.swap(lay);
2019-10-18 11:54:25 +02:00
undoI = (undoI + 1) % Config.raw.undo_steps;
}
else if (step.name == "Layer Opacity") {
Context.setLayer(Project.layers[step.layer]);
var t = Context.layer.maskOpacity;
Context.layer.maskOpacity = step.layer_opacity;
step.layer_opacity = t;
MaterialParser.parseMeshMaterial();
}
else if (step.name == "Layer Blending") {
Context.setLayer(Project.layers[step.layer]);
var t = Context.layer.blending;
Context.layer.blending = step.layer_blending;
step.layer_blending = t;
MaterialParser.parseMeshMaterial();
2019-06-26 16:34:36 +02:00
}
2019-12-04 23:48:42 +01:00
else if (step.name == "Edit Nodes") {
swapCanvas(step);
}
2019-06-24 22:35:17 +02:00
else { // Paint operation
var lay = undoLayers[undoI];
2019-06-26 16:34:36 +02:00
Context.selectPaintObject(Project.paintObjects[step.object]);
Context.setLayer(Project.layers[step.layer], step.is_mask);
step.is_mask ? Context.layer.swapMask(lay) : Context.layer.swap(lay);
2019-06-23 14:50:41 +02:00
Context.layerPreviewDirty = true;
2019-06-24 22:35:17 +02:00
undoI = (undoI + 1) % Config.raw.undo_steps;
2019-05-11 15:59:56 +02:00
}
2019-06-23 14:50:41 +02:00
undos++;
redos--;
2019-06-24 22:35:17 +02:00
UITrait.inst.hwnd.redraws = 2;
2019-10-18 11:54:25 +02:00
Context.ddirty = 2;
2019-05-11 15:59:56 +02:00
if (UIView2D.inst.show) UIView2D.inst.hwnd.redraws = 2;
}
}
public static function reset() {
2019-12-04 23:48:42 +01:00
steps = [{name: "New", layer: 0, object: 0, material: 0, brush: 0, is_mask: false, has_mask: false}];
2019-06-23 14:50:41 +02:00
undos = 0;
redos = 0;
undoI = 0;
2019-05-11 15:59:56 +02:00
}
2019-06-24 22:35:17 +02:00
public static function paint() {
var isMask = Context.layerIsMask;
2019-06-26 16:34:36 +02:00
copyToUndo(Context.layer.id, undoI, isMask);
2019-10-06 19:03:59 +02:00
2019-06-24 22:35:17 +02:00
pushUndo = false;
2019-07-02 21:56:39 +02:00
push(UITrait.inst.toolNames[Context.tool]);
2019-06-24 22:35:17 +02:00
}
public static function newLayer() {
push("New Layer");
}
public static function duplicateLayer() {
push("Duplicate Layer");
}
public static function deleteLayer() {
swapActive();
2019-06-26 16:34:36 +02:00
push("Delete Layer");
2019-06-24 22:35:17 +02:00
}
2019-12-09 00:28:10 +01:00
public static function orderLayers(prevOrder: Int) {
2019-06-24 22:35:17 +02:00
var step = push("Order Layers");
step.prev_order = prevOrder;
}
2019-12-09 00:28:10 +01:00
public static function mergeLayers(g: kha.graphics4.Graphics) {
2019-06-24 22:35:17 +02:00
copyMergingLayers();
var step = push("Merge Layers");
step.layer -= 1; // Merge down
steps.shift(); // Merge consumes 2 steps
2019-06-26 16:34:36 +02:00
undos--;
2019-06-24 22:35:17 +02:00
iron.App.removeRender(mergeLayers);
// TODO: use undo layer in Layers.mergeSelectedLayer to save memory
}
public static function newMask() {
push("New Mask");
}
public static function deleteMask() {
2019-06-26 16:34:36 +02:00
swapMaskActive();
2019-06-24 22:35:17 +02:00
push("Delete Mask");
}
public static function applyMask() {
2019-06-26 16:34:36 +02:00
copyToUndoWithMask();
2019-06-24 22:35:17 +02:00
push("Apply Mask");
}
2019-06-26 16:34:36 +02:00
public static function toFillLayer() {
copyToUndo(Context.layer.id, undoI, false);
push("To Fill Layer");
}
public static function toPaintLayer() {
copyToUndo(Context.layer.id, undoI, false);
push("To Paint Layer");
}
2019-10-18 11:54:25 +02:00
public static function layerOpacity() {
push("Layer Opacity");
}
// public static function layerObject() {
// push("Layer Object");
// }
public static function layerBlending() {
push("Layer Blending");
}
2019-06-26 16:34:36 +02:00
// public static function newMaterial() {}
// public static function deleteMaterial() {}
2019-12-09 00:28:10 +01:00
public static function editNodes(canvas: TNodeCanvas, canvas_type: Int) {
2019-12-04 23:48:42 +01:00
var step = push("Edit Nodes");
step.canvas_type = canvas_type;
step.canvas = haxe.Json.parse(haxe.Json.stringify(canvas));
}
2019-12-09 00:28:10 +01:00
static function push(name: String): TStep {
2019-06-26 16:34:36 +02:00
kha.Window.get(0).title = UIFiles.filename + "* - ArmorPaint";
2019-06-24 22:35:17 +02:00
if (undos < Config.raw.undo_steps) undos++;
if (redos > 0) {
for (i in 0...redos) steps.pop();
redos = 0;
}
2019-06-26 16:34:36 +02:00
var opos = Project.paintObjects.indexOf(cast Context.object);
var lpos = Project.layers.indexOf(Context.layer);
var mpos = Project.materials.indexOf(Context.material);
2019-12-04 23:48:42 +01:00
var bpos = Project.brushes.indexOf(Context.brush);
2019-06-26 16:34:36 +02:00
2019-06-24 22:35:17 +02:00
steps.push({
name: name,
layer: lpos,
object: opos,
2019-06-26 16:34:36 +02:00
material: mpos,
2019-12-04 23:48:42 +01:00
brush: bpos,
2019-06-26 16:34:36 +02:00
is_mask: Context.layerIsMask,
2019-10-18 11:54:25 +02:00
has_mask: Context.layer.texpaint_mask != null,
layer_opacity: Context.layer.maskOpacity,
layer_object: Context.layer.objectMask,
layer_blending: Context.layer.blending
2019-06-24 22:35:17 +02:00
});
2019-10-06 19:03:59 +02:00
2019-06-24 22:35:17 +02:00
while (steps.length > Config.raw.undo_steps + 1) steps.shift();
return steps[steps.length - 1];
}
2019-12-09 00:28:10 +01:00
static function redoMergeLayers(g: kha.graphics4.Graphics) {
2019-06-26 16:34:36 +02:00
copyMergingLayers();
iron.App.removeRender(redoMergeLayers);
}
static function copyMergingLayers() {
var lay = Context.layer;
copyToUndo(lay.id, undoI, false);
if (lay.texpaint_mask != null) {
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
copyToUndo(lay.id, undoI, true);
}
var below = Project.layers.indexOf(lay) - 1;
lay = Project.layers[below];
copyToUndo(lay.id, undoI, false);
}
static function copyToUndoWithMask() {
copyToUndo(Context.layer.id, undoI, false);
undoI = undoI - 1 < 0 ? Config.raw.undo_steps - 1 : undoI - 1;
copyToUndo(Context.layer.id, undoI, true);
}
2019-06-24 22:35:17 +02:00
static function swapActive() {
var undoLayer = undoLayers[undoI];
undoLayer.swap(Context.layer);
2019-06-26 16:34:36 +02:00
if (Context.layer.texpaint_mask != null) {
2019-06-24 22:35:17 +02:00
undoLayer.swapMask(Context.layer);
}
undoI = (undoI + 1) % Config.raw.undo_steps;
}
2019-06-26 16:34:36 +02:00
static function swapMaskActive() {
var undoLayer = undoLayers[undoI];
undoLayer.swapMask(Context.layer);
undoI = (undoI + 1) % Config.raw.undo_steps;
}
2019-12-09 00:28:10 +01:00
static function copyToUndo(fromId: Int, toId: Int, isMask: Bool) {
2019-06-24 22:35:17 +02:00
var path = iron.RenderPath.active;
if (isMask) {
path.setTarget("texpaint_mask_undo" + toId);
path.bindTarget("texpaint_mask" + fromId, "tex");
path.drawShader("shader_datas/copy_pass/copy_pass");
}
else {
path.setTarget("texpaint_undo" + toId, ["texpaint_nor_undo" + toId, "texpaint_pack_undo" + toId]);
path.bindTarget((isMask ? "texpaint_mask" : "texpaint") + fromId, "tex0");
path.bindTarget("texpaint_nor" + fromId, "tex1");
path.bindTarget("texpaint_pack" + fromId, "tex2");
path.drawShader("shader_datas/copy_mrt3_pass/copy_mrt3_pass");
}
undoI = (undoI + 1) % Config.raw.undo_steps;
}
2019-12-04 23:48:42 +01:00
2019-12-09 00:28:10 +01:00
static function swapCanvas(step: TStep) {
2019-12-04 23:48:42 +01:00
if (step.canvas_type == 0) {
var _canvas = Project.materials[step.material].canvas;
Project.materials[step.material].canvas = step.canvas;
step.canvas = _canvas;
2019-12-05 09:29:52 +01:00
Context.material = Project.materials[step.material];
2019-12-04 23:48:42 +01:00
}
else {
var _canvas = Project.brushes[step.brush].canvas;
Project.brushes[step.brush].canvas = step.canvas;
step.canvas = _canvas;
2019-12-05 09:29:52 +01:00
Context.brush = Project.brushes[step.brush];
2019-12-04 23:48:42 +01:00
}
2019-12-05 09:29:52 +01:00
2019-12-04 23:48:42 +01:00
function canvasChanged(_) {
UINodes.inst.canvasChanged();
iron.App.removeRender(canvasChanged);
}
iron.App.notifyOnRender(canvasChanged);
2019-12-05 09:29:52 +01:00
@:privateAccess UINodes.inst.getNodes().handle = new zui.Zui.Handle();
2019-12-06 00:13:32 +01:00
UINodes.inst.hwnd.redraws = 2;
2019-12-04 23:48:42 +01:00
}
2019-06-24 22:35:17 +02:00
}
typedef TStep = {
2019-12-09 00:28:10 +01:00
public var name: String;
public var layer: Int;
public var object: Int;
public var material: Int;
public var brush: Int;
public var is_mask: Bool; // Mask operation
public var has_mask: Bool; // Layer contains mask
@:optional public var layer_opacity: Float;
@:optional public var layer_object: Int;
@:optional public var layer_blending: Int;
@:optional public var prev_order: Int; // Previous layer position
@:optional public var canvas: TNodeCanvas; // Node history
@:optional public var canvas_type: Int;
2019-05-11 15:59:56 +02:00
}