Brush nodes
|
After Width: | Height: | Size: 10 KiB |
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"window_h": "900",
|
||||
"window_maximizable": true,
|
||||
"window_minimizable": true,
|
||||
"window_mode": 0,
|
||||
"window_msaa": "1",
|
||||
"window_resizable": true,
|
||||
"window_scale": 1.0,
|
||||
"window_vsync": true,
|
||||
"window_w": "1600"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 90 KiB |
@@ -29,7 +29,6 @@ class CamBall extends Trait {
|
||||
// Paint bounds
|
||||
if (mouse.x > iron.App.w()) return;
|
||||
// if (UINodes.show && mouse.y > UINodes.wy) return;
|
||||
// if (UINodesBrush.show && mouse.y > UINodesBrush.wy) return;
|
||||
|
||||
if (mouse.down("right") || (mouse.down("left") && kb.down("ctrl"))) {
|
||||
UITrait.dirty = true;
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package arm;
|
||||
|
||||
import armory.object.Object;
|
||||
import armory.system.Cycles;
|
||||
import zui.*;
|
||||
import zui.Nodes;
|
||||
import iron.data.SceneFormat;
|
||||
import iron.data.MaterialData;
|
||||
|
||||
@:access(arm.UINodes)
|
||||
class NodeCreator {
|
||||
|
||||
public static var numNodes = [2];
|
||||
|
||||
public static function draw(uinodes:UINodes, cat:Int) {
|
||||
var ui = uinodes.ui;
|
||||
var getNodeX = uinodes.getNodeX;
|
||||
var getNodeY = uinodes.getNodeY;
|
||||
var nodes = UINodes.nodes;
|
||||
var canvas = UINodes.canvas;
|
||||
|
||||
if (cat == 0) { // Input
|
||||
if (ui.button("On Brush")) {
|
||||
var node_id = uinodes.getNodeId(canvas.nodes);
|
||||
var n:TNode = {
|
||||
id: node_id,
|
||||
name: "On Brush",
|
||||
type: "OnBrushNode",
|
||||
x: mouse.x - wx,
|
||||
y: mouse.y - wy,
|
||||
color: 0xff4982a0,
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
id: uinodes.getSocketId(canvas.nodes),
|
||||
node_id: node_id,
|
||||
name: "Out",
|
||||
type: "ACTION",
|
||||
color: 0xff63c763,
|
||||
default_value: null
|
||||
},
|
||||
{
|
||||
id: uinodes.getSocketId(canvas.nodes),
|
||||
node_id: node_id,
|
||||
name: "Position",
|
||||
type: "VECTOR",
|
||||
color: 0xff63c763,
|
||||
default_value: null
|
||||
}
|
||||
],
|
||||
buttons: []
|
||||
};
|
||||
canvas.nodes.push(n);
|
||||
uinodes.nodeDrag = n;
|
||||
uinodes.nodeSelected = n;
|
||||
}
|
||||
if (ui.button("Brush Output")) {
|
||||
var node_id = uinodes.getNodeId(canvas.nodes);
|
||||
var n:TNode = {
|
||||
id: node_id,
|
||||
name: "Brush Output",
|
||||
type: "PaintNode",
|
||||
x: mouse.x - wx,
|
||||
y: mouse.y - wy,
|
||||
color: 0xff4982a0,
|
||||
inputs: [
|
||||
{
|
||||
id: uinodes.getSocketId(canvas.nodes),
|
||||
node_id: node_id,
|
||||
name: "In",
|
||||
type: "ACTION",
|
||||
color: 0xff63c763,
|
||||
default_value: null
|
||||
},
|
||||
{
|
||||
id: uinodes.getSocketId(canvas.nodes),
|
||||
node_id: node_id,
|
||||
name: "Position",
|
||||
type: "VECTOR",
|
||||
color: 0xff63c763,
|
||||
default_value: null
|
||||
}
|
||||
],
|
||||
buttons: []
|
||||
};
|
||||
canvas.nodes.push(n);
|
||||
uinodes.nodeDrag = n;
|
||||
uinodes.nodeSelected = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,15 @@ class UINodes extends armory.Trait {
|
||||
public var _matcon:TMaterialContext = null;
|
||||
var _materialcontext:MaterialContext = null;
|
||||
|
||||
public static var nodes = new Nodes();
|
||||
static var canvas:TNodeCanvas = null;
|
||||
static var canvasMap:Map<UITrait.MaterialSlot, TNodeCanvas> = null;
|
||||
static var canvasBlob:String;
|
||||
|
||||
static var canvasBrush:TNodeCanvas = null;
|
||||
static var canvasBrushBlob:String;
|
||||
public static var isBrush = false;
|
||||
|
||||
static var font:kha.Font;
|
||||
|
||||
public function new() {
|
||||
@@ -38,23 +47,30 @@ class UINodes extends armory.Trait {
|
||||
// Load font for UI labels
|
||||
iron.data.Data.getFont('droid_sans.ttf', function(f:kha.Font) {
|
||||
|
||||
iron.data.Data.getBlob('default_material.json', function(b:kha.Blob) {
|
||||
iron.data.Data.getBlob('default_material.json', function(b1:kha.Blob) {
|
||||
iron.data.Data.getBlob('default_brush.json', function(b2:kha.Blob) {
|
||||
|
||||
canvasBlob = b1.toString();
|
||||
canvasBrushBlob = b2.toString();
|
||||
|
||||
kha.Assets.loadImage('color_wheel', function(image:kha.Image) {
|
||||
|
||||
canvas = haxe.Json.parse(b.toString());
|
||||
canvas = haxe.Json.parse(canvasBlob);
|
||||
canvasBrush = haxe.Json.parse(canvasBrushBlob);
|
||||
parseBrush();
|
||||
|
||||
font = f;
|
||||
var t = Reflect.copy(zui.Themes.dark);
|
||||
t.FILL_WINDOW_BG = true;
|
||||
t.ELEMENT_H = 18;
|
||||
t.BUTTON_H = 16;
|
||||
// ui = new Zui({font: f, theme: t, scaleFactor: 2.5}); ////
|
||||
ui = new Zui({font: f, theme: t, color_wheel: image});
|
||||
var scale = armory.data.Config.raw.window_scale;
|
||||
ui = new Zui({font: f, theme: t, color_wheel: image, scaleFactor: scale});
|
||||
ui.scrollEnabled = false;
|
||||
armory.Scene.active.notifyOnInit(sceneInit);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -74,6 +90,19 @@ class UINodes extends armory.Trait {
|
||||
notifyOnUpdate(update);
|
||||
}
|
||||
|
||||
public function updateCanvasMap() {
|
||||
if (UITrait.selected != null) {
|
||||
if (canvasMap == null) canvasMap = new Map();
|
||||
var c = canvasMap.get(UITrait.selected);
|
||||
if (c == null) {
|
||||
c = haxe.Json.parse(canvasBlob);
|
||||
canvasMap.set(UITrait.selected, c);
|
||||
canvas = c;
|
||||
}
|
||||
else canvas = c;
|
||||
}
|
||||
}
|
||||
|
||||
var mx = 0.0;
|
||||
var my = 0.0;
|
||||
// var wh = 300;
|
||||
@@ -83,9 +112,13 @@ class UINodes extends armory.Trait {
|
||||
var mchanged = false;
|
||||
public static var changed = false;
|
||||
function update() {
|
||||
if (frame == 8) parseMaterial(); // Temp cpp fix
|
||||
if (frame == 8) {
|
||||
parseMaterial(); // Temp cpp fix
|
||||
}
|
||||
frame++;
|
||||
|
||||
updateCanvasMap();
|
||||
|
||||
//
|
||||
var mouse = iron.system.Input.getMouse();
|
||||
mreleased = mouse.released();
|
||||
@@ -97,7 +130,7 @@ class UINodes extends armory.Trait {
|
||||
}
|
||||
if ((mreleased && mchanged) || changed) {
|
||||
mchanged = changed = false;
|
||||
parseMaterial();
|
||||
isBrush ? parseBrush : parseMaterial();
|
||||
}
|
||||
//
|
||||
|
||||
@@ -124,18 +157,21 @@ class UINodes extends armory.Trait {
|
||||
}
|
||||
|
||||
if (keyboard.started("x") || keyboard.started("backspace")) {
|
||||
nodes.removeNode(nodes.nodeSelected, canvas);
|
||||
var c = isBrush ? canvasBrush : canvas;
|
||||
nodes.removeNode(nodes.nodeSelected, c);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (keyboard.started("p")) {
|
||||
trace(haxe.Json.stringify(canvas));
|
||||
var c = isBrush ? canvasBrush : canvas;
|
||||
trace(haxe.Json.stringify(c));
|
||||
}
|
||||
|
||||
if (keyboard.started("r")) {
|
||||
parseBrush();
|
||||
}
|
||||
}
|
||||
|
||||
public static var nodes = new Nodes();
|
||||
static var canvas:TNodeCanvas = null;
|
||||
|
||||
function getNodeX():Int {
|
||||
var mouse = iron.system.Input.getMouse();
|
||||
return Std.int((mouse.x - wx - nodes.PAN_X()) / nodes.SCALE);
|
||||
@@ -204,7 +240,8 @@ class UINodes extends armory.Trait {
|
||||
|
||||
// Recompile material on change
|
||||
ui.changed = false;
|
||||
nodes.nodeCanvas(ui, canvas);
|
||||
var c = isBrush ? canvasBrush : canvas;
|
||||
nodes.nodeCanvas(ui, c);
|
||||
|
||||
ui.g.color = ui.t.WINDOW_BG_COL;
|
||||
ui.g.fillRect(0, 0, ww, 24);
|
||||
@@ -493,13 +530,15 @@ class UINodes extends armory.Trait {
|
||||
// return con_mesh;
|
||||
// }
|
||||
|
||||
function getMOut():Bool {
|
||||
for (n in canvas.nodes) if (n.type == "OUTPUT_MATERIAL_PBR") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function parseMaterial() {
|
||||
UITrait.dirty = true;
|
||||
|
||||
var mout = false;
|
||||
for (n in canvas.nodes) if (n.type == "OUTPUT_MATERIAL_PBR") { mout = true; break; }
|
||||
|
||||
if (mout) {
|
||||
if (getMOut()) {
|
||||
|
||||
iron.data.Data.getMaterial("Scene", "Material", function(m:iron.data.MaterialData) {
|
||||
|
||||
@@ -604,4 +643,9 @@ class UINodes extends armory.Trait {
|
||||
NodeCreator.createImageTexture(inst);
|
||||
nodes.nodeSelected.buttons[0].default_value = assetIndex;
|
||||
}
|
||||
|
||||
function parseBrush() {
|
||||
armory.system.Logic.packageName = "arm.logicnode";
|
||||
var tree = armory.system.Logic.parse(canvasBrush, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
package arm;
|
||||
|
||||
import armory.object.Object;
|
||||
import armory.system.Cycles;
|
||||
import zui.*;
|
||||
import zui.Nodes;
|
||||
import iron.data.SceneFormat;
|
||||
import iron.data.MaterialData;
|
||||
|
||||
class UINodesBrush extends armory.Trait {
|
||||
|
||||
public static var show = false;
|
||||
|
||||
public static var wx:Int;
|
||||
public static var wy:Int;
|
||||
|
||||
var ui:Zui;
|
||||
var drawMenu = false;
|
||||
var showMenu = false;
|
||||
var hideMenu = false;
|
||||
var popupX = 0;
|
||||
var popupY = 0;
|
||||
|
||||
static var font:kha.Font;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
// Load font for UI labels
|
||||
iron.data.Data.getFont('droid_sans.ttf', function(f:kha.Font) {
|
||||
|
||||
iron.data.Data.getBlob('default_brush.json', function(b:kha.Blob) {
|
||||
|
||||
canvas = haxe.Json.parse(b.toString());
|
||||
parseBrush();
|
||||
|
||||
font = f;
|
||||
|
||||
var t = Reflect.copy(zui.Themes.dark);
|
||||
t.FILL_WINDOW_BG = true;
|
||||
t.ELEMENT_H = 18;
|
||||
t.BUTTON_H = 16;
|
||||
ui = new Zui({font: f, theme: t});
|
||||
ui.scrollEnabled = false;
|
||||
armory.Scene.active.notifyOnInit(sceneInit);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function sceneInit() {
|
||||
// Store references to cube and plane objects
|
||||
notifyOnRender2D(render2D);
|
||||
notifyOnUpdate(update);
|
||||
}
|
||||
|
||||
var wh = 300;
|
||||
|
||||
function update() {
|
||||
if (!show) return;
|
||||
if (!UITrait.uienabled) return;
|
||||
var mouse = iron.system.Input.getMouse();
|
||||
var keyboard = iron.system.Input.getKeyboard();
|
||||
|
||||
wx = 200;
|
||||
wy = iron.App.h() - wh;
|
||||
if (mouse.x < wx || mouse.y < wy) return;
|
||||
|
||||
if (ui.isTyping) return;
|
||||
|
||||
if (mouse.released("right") || keyboard.started("a")) {
|
||||
showMenu = true;
|
||||
popupX = Std.int(mouse.x);
|
||||
popupY = Std.int(mouse.y);
|
||||
}
|
||||
else if (mouse.released()) {
|
||||
hideMenu = true;
|
||||
}
|
||||
|
||||
if (keyboard.started("x")) {
|
||||
var n = uinodes.nodeSelected;
|
||||
var i = 0;
|
||||
while (i < canvas.links.length) {
|
||||
var l = canvas.links[i];
|
||||
if (l.from_id == n.id || l.to_id == n.id) {
|
||||
canvas.links.splice(i, 1);
|
||||
}
|
||||
else i++;
|
||||
}
|
||||
canvas.nodes.remove(n);
|
||||
}
|
||||
|
||||
if (keyboard.started("p")) {
|
||||
trace(haxe.Json.stringify(canvas));
|
||||
}
|
||||
}
|
||||
|
||||
static var uinodes = new Nodes();
|
||||
|
||||
public static var canvas:TNodeCanvas = null;
|
||||
|
||||
static var bg:kha.Image = null;
|
||||
|
||||
function render2D(g:kha.graphics2.Graphics) {
|
||||
if (!show) return;
|
||||
|
||||
if (!UITrait.uienabled && ui.inputRegistered) ui.unregisterInput();
|
||||
if (UITrait.uienabled && !ui.inputRegistered) ui.registerInput();
|
||||
|
||||
g.end();
|
||||
|
||||
if (bg == null) {
|
||||
var w = iron.App.w() - 200;
|
||||
var h = wh;
|
||||
bg = kha.Image.createRenderTarget(w, h);
|
||||
bg.g2.begin(true, 0xff141414);
|
||||
for (i in 0...Std.int(h / 40) + 1) {
|
||||
bg.g2.color = 0xff303030;
|
||||
bg.g2.drawLine(0, i * 40, w, i * 40);
|
||||
bg.g2.color = 0xff202020;
|
||||
bg.g2.drawLine(0, i * 40 + 20, w, i * 40 + 20);
|
||||
}
|
||||
for (i in 0...Std.int(w / 40) + 1) {
|
||||
bg.g2.color = 0xff303030;
|
||||
bg.g2.drawLine(i * 40, 0, i * 40, h);
|
||||
bg.g2.color = 0xff202020;
|
||||
bg.g2.drawLine(i * 40 + 20, 0, i * 40 + 20, h);
|
||||
}
|
||||
bg.g2.end();
|
||||
}
|
||||
|
||||
// Start with UI
|
||||
ui.begin(g);
|
||||
|
||||
// Make window
|
||||
var mouse = iron.system.Input.getMouse();
|
||||
wx = 200;
|
||||
wy = iron.App.h() - wh;
|
||||
var hwin = Id.handle();
|
||||
if (ui.window(hwin, wx, wy, iron.App.w() - 200, wh)) {
|
||||
|
||||
ui.g.color = 0xffffffff;
|
||||
ui.g.drawImage(bg, 0, 0);
|
||||
|
||||
ui.g.font = font;
|
||||
ui.g.fontSize = 42;
|
||||
var title = "Brush";
|
||||
// var title = "Brush (right-click to add node)";
|
||||
var titlew = ui.g.font.width(42, title);
|
||||
var titleh = ui.g.font.height(42);
|
||||
ui.g.drawString(title, iron.App.w() - 200 - titlew - 20, wh - titleh - 10);
|
||||
|
||||
uinodes.nodeCanvas(ui, canvas);
|
||||
}
|
||||
|
||||
ui.endWindow();
|
||||
|
||||
if (drawMenu) {
|
||||
ui.beginLayout(g, popupX, popupY, 120);
|
||||
|
||||
if (ui.button("On Brush")) {
|
||||
var node_id = uinodes.getNodeId(canvas.nodes);
|
||||
var n:TNode = {
|
||||
id: node_id,
|
||||
name: "On Brush",
|
||||
type: "OnBrushNode",
|
||||
x: mouse.x - wx,
|
||||
y: mouse.y - wy,
|
||||
color: 0xff4982a0,
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
id: uinodes.getSocketId(canvas.nodes),
|
||||
node_id: node_id,
|
||||
name: "Out",
|
||||
type: "ACTION",
|
||||
color: 0xff63c763,
|
||||
default_value: null
|
||||
},
|
||||
{
|
||||
id: uinodes.getSocketId(canvas.nodes),
|
||||
node_id: node_id,
|
||||
name: "Position",
|
||||
type: "VECTOR",
|
||||
color: 0xff63c763,
|
||||
default_value: null
|
||||
}
|
||||
],
|
||||
buttons: []
|
||||
};
|
||||
canvas.nodes.push(n);
|
||||
uinodes.nodeDrag = n;
|
||||
uinodes.nodeSelected = n;
|
||||
}
|
||||
if (ui.button("Paint")) {
|
||||
var node_id = uinodes.getNodeId(canvas.nodes);
|
||||
var n:TNode = {
|
||||
id: node_id,
|
||||
name: "Paint",
|
||||
type: "PaintNode",
|
||||
x: mouse.x - wx,
|
||||
y: mouse.y - wy,
|
||||
color: 0xff4982a0,
|
||||
inputs: [
|
||||
{
|
||||
id: uinodes.getSocketId(canvas.nodes),
|
||||
node_id: node_id,
|
||||
name: "In",
|
||||
type: "ACTION",
|
||||
color: 0xff63c763,
|
||||
default_value: null
|
||||
},
|
||||
{
|
||||
id: uinodes.getSocketId(canvas.nodes),
|
||||
node_id: node_id,
|
||||
name: "Position",
|
||||
type: "VECTOR",
|
||||
color: 0xff63c763,
|
||||
default_value: null
|
||||
}
|
||||
],
|
||||
outputs: [
|
||||
{
|
||||
id: uinodes.getSocketId(canvas.nodes),
|
||||
node_id: node_id,
|
||||
name: "Out",
|
||||
type: "ACTION",
|
||||
color: 0xff63c763,
|
||||
default_value: null
|
||||
}
|
||||
],
|
||||
buttons: []
|
||||
};
|
||||
canvas.nodes.push(n);
|
||||
uinodes.nodeDrag = n;
|
||||
uinodes.nodeSelected = n;
|
||||
}
|
||||
|
||||
if (ui.button("Parse")) {
|
||||
parseBrush();
|
||||
}
|
||||
|
||||
ui.endLayout();
|
||||
}
|
||||
|
||||
ui.end();
|
||||
|
||||
g.begin(false);
|
||||
|
||||
if (showMenu) {
|
||||
showMenu = false;
|
||||
drawMenu = true;
|
||||
|
||||
}
|
||||
if (hideMenu) {
|
||||
hideMenu = false;
|
||||
drawMenu = false;
|
||||
}
|
||||
}
|
||||
|
||||
function parseBrush() {
|
||||
armory.system.Logic.packageName = "arm.logicnode";
|
||||
var tree = armory.system.Logic.parse(canvas, false);
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,16 @@ typedef TPreferences = {
|
||||
// public var materials:Array<>;
|
||||
// }
|
||||
|
||||
class MaterialSlot {
|
||||
public function new() {}
|
||||
}
|
||||
|
||||
class BrushSlot {
|
||||
public function new() {}
|
||||
}
|
||||
|
||||
@:access(zui.Zui)
|
||||
@:access(iron.data.Data)
|
||||
class UITrait extends armory.Trait {
|
||||
|
||||
public static var uienabled = true;
|
||||
@@ -43,7 +53,7 @@ class UITrait extends armory.Trait {
|
||||
var ui:Zui;
|
||||
var uimodal:Zui;
|
||||
|
||||
public static var windowW = 240; // Panel width
|
||||
public static var windowW = 280; // Panel width
|
||||
|
||||
function loadBundled(names:Array<String>, done:Void->Void) {
|
||||
var loaded = 0;
|
||||
@@ -79,7 +89,6 @@ class UITrait extends armory.Trait {
|
||||
// Paint bounds
|
||||
if (paintX > iron.App.w()) return false;
|
||||
// if (UINodes.show && paintY > UINodes.wy) return false;
|
||||
// if (UINodesBrush.show && paintY > UINodesBrush.wy) return false;
|
||||
|
||||
// Prevent painting the same spot - save perf & reduce projection paint jittering caused by _sub offset
|
||||
if (paintX == lastPaintX && paintY == lastPaintY) painted++;
|
||||
@@ -155,6 +164,8 @@ class UITrait extends armory.Trait {
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
windowW = Std.int(windowW * armory.data.Config.raw.window_scale);
|
||||
|
||||
iron.object.Uniforms.externalFloatLinks = [linkFloat];
|
||||
iron.object.Uniforms.externalVec2Links = [linkVec2];
|
||||
|
||||
@@ -163,10 +174,10 @@ class UITrait extends armory.Trait {
|
||||
zui.Themes.dark.FILL_WINDOW_BG = true;
|
||||
zui.Nodes.getEnumTexts = getEnumTexts;
|
||||
zui.Nodes.mapEnum = mapEnum;
|
||||
ui = new Zui( { font: f } );
|
||||
uimodal = new Zui( { font: f } );
|
||||
// ui = new Zui( { font: f, scaleFactor: 8, theme: zui.Themes.light } ); ////
|
||||
loadBundled(['brush', 'mat', 'matbrush', 'cay_thumb'], done);
|
||||
var scale = armory.data.Config.raw.window_scale;
|
||||
ui = new Zui( { font: f, scaleFactor: scale } );
|
||||
uimodal = new Zui( { font: f, scaleFactor: scale } );
|
||||
loadBundled(['cursor', 'mat', 'mat_empty', 'brush', 'cay_thumb'], done);
|
||||
});
|
||||
|
||||
kha.System.notifyOnDropFiles(function(filePath:String) {
|
||||
@@ -184,9 +195,11 @@ class UITrait extends armory.Trait {
|
||||
}
|
||||
|
||||
function checkImageFormat(path:String):Bool {
|
||||
if (!StringTools.endsWith(path, ".jpg") &&
|
||||
!StringTools.endsWith(path, ".png") &&
|
||||
!StringTools.endsWith(path, ".hdr")) {
|
||||
var p = path.toLowerCase();
|
||||
if (!StringTools.endsWith(p, ".jpg") &&
|
||||
!StringTools.endsWith(p, ".png") &&
|
||||
!StringTools.endsWith(p, ".tga") &&
|
||||
!StringTools.endsWith(p, ".hdr")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -256,6 +269,12 @@ class UITrait extends armory.Trait {
|
||||
updateUI();
|
||||
// updateSplash();
|
||||
updateFiles();
|
||||
|
||||
var kb = iron.system.Input.getKeyboard();
|
||||
if (kb.started("tab")) {
|
||||
UINodes.show = !UINodes.show;
|
||||
resize();
|
||||
}
|
||||
}
|
||||
|
||||
function updateUI() {
|
||||
@@ -394,7 +413,13 @@ class UITrait extends armory.Trait {
|
||||
if (arm.App.realw() == 0 || arm.App.realh() == 0) return;
|
||||
|
||||
if (dropPath != "") {
|
||||
if (StringTools.endsWith(dropPath, ".obj")) importMesh(dropPath);
|
||||
var p = dropPath.toLowerCase();
|
||||
if (StringTools.endsWith(p, ".obj") ||
|
||||
StringTools.endsWith(p, ".fbx") ||
|
||||
// StringTools.endsWith(p, ".blend") ||
|
||||
StringTools.endsWith(p, ".gltf")) {
|
||||
importMesh(dropPath);
|
||||
}
|
||||
else {
|
||||
importAsset(dropPath);
|
||||
// Place image node
|
||||
@@ -421,7 +446,7 @@ class UITrait extends armory.Trait {
|
||||
// var ready = showFiles || dirty;
|
||||
// TODO: Texture params get overwritten
|
||||
// if (ready) for (t in UINodes.inst._matcon.bind_textures) t.params_set = null;
|
||||
if (UINodes.inst._matcon != null) for (t in UINodes.inst._matcon.bind_textures) t.params_set = null;
|
||||
// if (UINodes.inst._matcon != null) for (t in UINodes.inst._matcon.bind_textures) t.params_set = null;
|
||||
|
||||
// iron.Scene.active.camera.renderPath.ready = ready;
|
||||
// dirty = false;
|
||||
@@ -443,6 +468,7 @@ class UITrait extends armory.Trait {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var outputType = 0;
|
||||
var isBase = true;
|
||||
var isOpac = true;
|
||||
var isOcc = true;
|
||||
@@ -450,24 +476,39 @@ class UITrait extends armory.Trait {
|
||||
var isMet = true;
|
||||
var isNor = true;
|
||||
var hwnd = Id.handle();
|
||||
var materials:Array<MaterialSlot> = null;
|
||||
public static var selected:MaterialSlot;
|
||||
var brushes:Array<BrushSlot> = null;
|
||||
public static var selectedBrush:BrushSlot;
|
||||
function renderUI(g:kha.graphics2.Graphics) {
|
||||
if (!show) return;
|
||||
|
||||
if (materials == null) {
|
||||
materials = [];
|
||||
materials.push(new MaterialSlot());
|
||||
selected = materials[0];
|
||||
}
|
||||
|
||||
if (brushes == null) {
|
||||
brushes = [];
|
||||
brushes.push(new BrushSlot());
|
||||
selectedBrush = brushes[0];
|
||||
}
|
||||
|
||||
if (!UITrait.uienabled && ui.inputRegistered) ui.unregisterInput();
|
||||
if (UITrait.uienabled && !ui.inputRegistered) ui.registerInput();
|
||||
|
||||
var matImg = bundled.get('mat');
|
||||
var matBrushImg = bundled.get('matbrush');
|
||||
var envThumbCay = bundled.get('cay_thumb');
|
||||
var brushImg = bundled.get('brush');
|
||||
var envThumbCay = bundled.get('cay_thumb');
|
||||
var cursorImg = bundled.get('cursor');
|
||||
var mouse = iron.system.Input.getMouse();
|
||||
g.color = 0xffffffff;
|
||||
|
||||
// Brush
|
||||
if (UITrait.uienabled) {
|
||||
var psize = Std.int(brushImg.width * brushRadius);
|
||||
var psize = Std.int(cursorImg.width * brushRadius);
|
||||
// g.imageScaleQuality = kha.graphics2.ImageScaleQuality.High;
|
||||
g.drawScaledImage(brushImg, mouse.x - psize / 2, mouse.y - psize / 2, psize, psize);
|
||||
g.drawScaledImage(cursorImg, mouse.x - psize / 2, mouse.y - psize / 2, psize, psize);
|
||||
}
|
||||
|
||||
g.end();
|
||||
@@ -491,6 +532,7 @@ class UITrait extends armory.Trait {
|
||||
ui.text(message);
|
||||
}
|
||||
|
||||
ui.row([1/2,1/2]);
|
||||
if (ui.button("Import Mesh")) {
|
||||
showFiles = true;
|
||||
foldersOnly = false;
|
||||
@@ -499,11 +541,7 @@ class UITrait extends armory.Trait {
|
||||
}
|
||||
}
|
||||
else if (ui.isHovered) ui.tooltip("Drop .obj mesh here");
|
||||
|
||||
if (ui.button("Export Textures")) {
|
||||
|
||||
|
||||
|
||||
var textureSize = getTextureRes();
|
||||
|
||||
showFiles = true;
|
||||
@@ -559,41 +597,57 @@ class UITrait extends armory.Trait {
|
||||
// #end
|
||||
|
||||
pixels = texpaint_pack.getPixels(); // occ, rough, met
|
||||
for (i in 0...textureSize * textureSize) {
|
||||
rgb.set(i * 3 + 0, pixels.get(i * 4));
|
||||
rgb.set(i * 3 + 1, pixels.get(i * 4));
|
||||
rgb.set(i * 3 + 2, pixels.get(i * 4));
|
||||
}
|
||||
bo = new haxe.io.BytesOutput();
|
||||
var pngwriter = new iron.format.png.Writer(bo);
|
||||
pngwriter.write(iron.format.png.Tools.buildRGB(textureSize, textureSize, rgb));
|
||||
#if kha_krom
|
||||
if (isOcc) Krom.fileSaveBytes(path + "/tex_occ.png", bo.getBytes().getData());
|
||||
#end
|
||||
|
||||
for (i in 0...textureSize * textureSize) {
|
||||
rgb.set(i * 3 + 0, pixels.get(i * 4 + 1));
|
||||
rgb.set(i * 3 + 1, pixels.get(i * 4 + 1));
|
||||
rgb.set(i * 3 + 2, pixels.get(i * 4 + 1));
|
||||
}
|
||||
bo = new haxe.io.BytesOutput();
|
||||
var pngwriter = new iron.format.png.Writer(bo);
|
||||
pngwriter.write(iron.format.png.Tools.buildRGB(textureSize, textureSize, rgb));
|
||||
#if kha_krom
|
||||
if (isRough) Krom.fileSaveBytes(path + "/tex_rough.png", bo.getBytes().getData());
|
||||
#end
|
||||
if (outputType == 0) {
|
||||
for (i in 0...textureSize * textureSize) {
|
||||
rgb.set(i * 3 + 0, pixels.get(i * 4));
|
||||
rgb.set(i * 3 + 1, pixels.get(i * 4));
|
||||
rgb.set(i * 3 + 2, pixels.get(i * 4));
|
||||
}
|
||||
bo = new haxe.io.BytesOutput();
|
||||
var pngwriter = new iron.format.png.Writer(bo);
|
||||
pngwriter.write(iron.format.png.Tools.buildRGB(textureSize, textureSize, rgb));
|
||||
#if kha_krom
|
||||
if (isOcc) Krom.fileSaveBytes(path + "/tex_occ.png", bo.getBytes().getData());
|
||||
#end
|
||||
|
||||
for (i in 0...textureSize * textureSize) {
|
||||
rgb.set(i * 3 + 0, pixels.get(i * 4 + 2));
|
||||
rgb.set(i * 3 + 1, pixels.get(i * 4 + 2));
|
||||
rgb.set(i * 3 + 2, pixels.get(i * 4 + 2));
|
||||
for (i in 0...textureSize * textureSize) {
|
||||
rgb.set(i * 3 + 0, pixels.get(i * 4 + 1));
|
||||
rgb.set(i * 3 + 1, pixels.get(i * 4 + 1));
|
||||
rgb.set(i * 3 + 2, pixels.get(i * 4 + 1));
|
||||
}
|
||||
bo = new haxe.io.BytesOutput();
|
||||
var pngwriter = new iron.format.png.Writer(bo);
|
||||
pngwriter.write(iron.format.png.Tools.buildRGB(textureSize, textureSize, rgb));
|
||||
#if kha_krom
|
||||
if (isRough) Krom.fileSaveBytes(path + "/tex_rough.png", bo.getBytes().getData());
|
||||
#end
|
||||
|
||||
for (i in 0...textureSize * textureSize) {
|
||||
rgb.set(i * 3 + 0, pixels.get(i * 4 + 2));
|
||||
rgb.set(i * 3 + 1, pixels.get(i * 4 + 2));
|
||||
rgb.set(i * 3 + 2, pixels.get(i * 4 + 2));
|
||||
}
|
||||
bo = new haxe.io.BytesOutput();
|
||||
var pngwriter = new iron.format.png.Writer(bo);
|
||||
pngwriter.write(iron.format.png.Tools.buildRGB(textureSize, textureSize, rgb));
|
||||
#if kha_krom
|
||||
if (isMet) Krom.fileSaveBytes(path + "/tex_met.png", bo.getBytes().getData());
|
||||
#end
|
||||
}
|
||||
else { // UE4
|
||||
for (i in 0...textureSize * textureSize) {
|
||||
rgb.set(i * 3 + 0, pixels.get(i * 4));
|
||||
rgb.set(i * 3 + 1, pixels.get(i * 4 + 1));
|
||||
rgb.set(i * 3 + 2, pixels.get(i * 4 + 2));
|
||||
}
|
||||
bo = new haxe.io.BytesOutput();
|
||||
var pngwriter = new iron.format.png.Writer(bo);
|
||||
pngwriter.write(iron.format.png.Tools.buildRGB(textureSize, textureSize, rgb));
|
||||
#if kha_krom
|
||||
if (isOcc) Krom.fileSaveBytes(path + "/tex_orm.png", bo.getBytes().getData());
|
||||
#end
|
||||
}
|
||||
bo = new haxe.io.BytesOutput();
|
||||
var pngwriter = new iron.format.png.Writer(bo);
|
||||
pngwriter.write(iron.format.png.Tools.buildRGB(textureSize, textureSize, rgb));
|
||||
#if kha_krom
|
||||
if (isMet) Krom.fileSaveBytes(path + "/tex_met.png", bo.getBytes().getData());
|
||||
#end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,6 +660,7 @@ class UITrait extends armory.Trait {
|
||||
}
|
||||
ui.combo(Id.handle(), ["8bit"], "Color", true);
|
||||
ui.combo(Id.handle(), ["png"], "Format", true);
|
||||
outputType = ui.combo(Id.handle(), ["Generic", "UE4 (ORM)"], "Output", true);
|
||||
ui.text("Channels");
|
||||
ui.row([1/2, 1/2]);
|
||||
isBase = ui.check(Id.handle({selected: isBase}), "Base Color");
|
||||
@@ -618,7 +673,7 @@ class UITrait extends armory.Trait {
|
||||
isNor = ui.check(Id.handle({selected: isNor}), "Normal Map");
|
||||
}
|
||||
|
||||
if (ui.panel(Id.handle({selected: false}), "Camera")) {
|
||||
if (ui.panel(Id.handle({selected: true}), "Camera")) {
|
||||
|
||||
ui.row([1/2,1/2]);
|
||||
cameraType = ui.combo(Id.handle({position: cameraType}), ["Orbit", "Fly"], "Camera");
|
||||
@@ -662,7 +717,7 @@ class UITrait extends armory.Trait {
|
||||
// }
|
||||
// ui.separator();
|
||||
|
||||
if (ui.panel(Id.handle({selected: false}), "Environment")) {
|
||||
if (ui.panel(Id.handle({selected: true}), "Lighting")) {
|
||||
ui.image(envThumbCay);
|
||||
var p = iron.Scene.active.world.getGlobalProbe();
|
||||
ui.row([1/2, 1/2]);
|
||||
@@ -675,12 +730,36 @@ class UITrait extends armory.Trait {
|
||||
}
|
||||
}
|
||||
|
||||
if (ui.panel(Id.handle({selected: true}), "Brush")) {
|
||||
ui.image(matBrushImg);
|
||||
// if (ui.button("Nodes")) {
|
||||
// UINodesBrush.show = !UINodesBrush.show;
|
||||
// UINodes.show = false;
|
||||
// }
|
||||
if (ui.panel(Id.handle({selected: true}), "Brushes")) {
|
||||
|
||||
ui.row([1/2,1/2]);
|
||||
if (ui.button("New")) {
|
||||
brushes.push(new BrushSlot());
|
||||
}
|
||||
if (ui.button("Nodes")) {
|
||||
if (UINodes.show && UINodes.isBrush) UINodes.show = false;
|
||||
else { UINodes.show = true; UINodes.isBrush = true; }
|
||||
resize();
|
||||
}
|
||||
|
||||
var img = bundled.get("brush");
|
||||
var img2 = bundled.get("mat_empty");
|
||||
ui.row([1/5,1/5,1/5,1/5,1/5]);
|
||||
for (i in 0...5) {
|
||||
var im = img;
|
||||
if (brushes.length <= i) im = img2;
|
||||
|
||||
if (im == img && selectedBrush == brushes[i]) {
|
||||
ui.g.color = 0xff205d9c;
|
||||
ui.g.fillRect(ui._x + 1, ui._y - 2, im.width + 3, im.height + 3);
|
||||
ui.g.color = 0xffffffff;
|
||||
}
|
||||
|
||||
if (ui.image(im) == State.Started && im == img) {
|
||||
selectedBrush = brushes[i];
|
||||
}
|
||||
}
|
||||
|
||||
ui.row([1/2, 1/2]);
|
||||
var paintHandle = Id.handle();
|
||||
brushPaint = ui.combo(paintHandle, ["UV", "Project"], "Paint");
|
||||
@@ -700,48 +779,69 @@ class UITrait extends armory.Trait {
|
||||
brushOpacity = ui.slider(Id.handle({value: brushOpacity}), "Opacity", 0.0, 1.0, true);
|
||||
ui.row([1/2, 1/2]);
|
||||
brushStrength = ui.slider(Id.handle({value: brushStrength}), "Strength", 0.0, 1.0, true);
|
||||
brushScale = ui.slider(Id.handle({value: brushScale}), "Scale", 0.0, 1.0, true);
|
||||
}
|
||||
ui.separator();
|
||||
brushScale = ui.slider(Id.handle({value: brushScale}), "Scale", 0.0, 2.0, true);
|
||||
|
||||
if (ui.panel(Id.handle({selected: true}), "Material")) {
|
||||
ui.image(matImg);
|
||||
if (ui.button("Nodes")) {
|
||||
UINodes.show = !UINodes.show;
|
||||
UINodesBrush.show = false;
|
||||
resize();
|
||||
}
|
||||
// ui.text("Paint");
|
||||
// ui.row([1/2, 1/2]);
|
||||
// paintBase = ui.check(Id.handle({selected: paintBase}), "Base Color");
|
||||
// paintOpac = ui.check(Id.handle({selected: paintOpac}), "Opacity");
|
||||
// ui.row([1/2, 1/2]);
|
||||
// paintOcc = ui.check(Id.handle({selected: paintOcc}), "Occlusion");
|
||||
// paintRough = ui.check(Id.handle({selected: paintRough}), "Roughness");
|
||||
// ui.row([1/2, 1/2]);
|
||||
// paintMet = ui.check(Id.handle({selected: paintMet}), "Metallic");
|
||||
// paintNor = ui.check(Id.handle({selected: paintNor}), "Normal Map");
|
||||
ui.row([1/3,1/3,1/3]);
|
||||
|
||||
var baseHandle = Id.handle({selected: paintBase});
|
||||
paintBase = ui.check(baseHandle, "Base Color");
|
||||
if (baseHandle.changed) {
|
||||
UINodes.inst.updateCanvasMap();
|
||||
UINodes.inst.parseMaterial();
|
||||
}
|
||||
|
||||
var norHandle = Id.handle({selected: paintNor});
|
||||
paintNor = ui.check(norHandle, "Normal Map");
|
||||
if (norHandle.changed) {
|
||||
UINodes.inst.updateCanvasMap();
|
||||
UINodes.inst.parseMaterial();
|
||||
}
|
||||
|
||||
var roughHandle = Id.handle({selected: paintRough});
|
||||
paintRough = ui.check(roughHandle, "Rough Met Occ");
|
||||
paintRough = ui.check(roughHandle, "ORM");
|
||||
if (roughHandle.changed) {
|
||||
UINodes.inst.updateCanvasMap();
|
||||
UINodes.inst.parseMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
ui.text("v0.1", zui.Zui.Align.Right);
|
||||
if (ui.panel(Id.handle({selected: true}), "Materials")) {
|
||||
|
||||
ui.row([1/2,1/2]);
|
||||
if (ui.button("New")) {
|
||||
materials.push(new MaterialSlot());
|
||||
}
|
||||
if (ui.button("Nodes")) {
|
||||
if (UINodes.show && !UINodes.isBrush) UINodes.show = false;
|
||||
else { UINodes.show = true; UINodes.isBrush = false; }
|
||||
resize();
|
||||
}
|
||||
|
||||
var img = bundled.get("mat");
|
||||
var img2 = bundled.get("mat_empty");
|
||||
ui.row([1/5,1/5,1/5,1/5,1/5]);
|
||||
for (i in 0...5) {
|
||||
var im = img;
|
||||
if (materials.length <= i) im = img2;
|
||||
|
||||
if (im == img && selected == materials[i]) {
|
||||
ui.g.color = 0xff205d9c;
|
||||
ui.g.fillRect(ui._x + 1, ui._y - 2, im.width + 3, im.height + 3);
|
||||
ui.g.color = 0xffffffff;
|
||||
}
|
||||
|
||||
if (ui.image(im) == State.Started && im == img) {
|
||||
selected = materials[i];
|
||||
UINodes.inst.updateCanvasMap();
|
||||
UINodes.inst.parseMaterial();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (ui.panel(Id.handle({selected: true}), "Layers")) {
|
||||
// }
|
||||
|
||||
ui.text("v0.2", zui.Zui.Align.Right);
|
||||
}
|
||||
|
||||
if (ui.tab(htab, "Assets")) {
|
||||
@@ -860,72 +960,87 @@ class UITrait extends armory.Trait {
|
||||
}
|
||||
|
||||
function importMesh(path:String) {
|
||||
if (!StringTools.endsWith(path, ".obj")) {
|
||||
showMessage("Error: Unknown mesh format");
|
||||
return;
|
||||
}
|
||||
var p = path.toLowerCase();
|
||||
if (StringTools.endsWith(p, ".obj")) importObj(path);
|
||||
else if (StringTools.endsWith(p, ".gltf")) importGltf(path);
|
||||
else if (StringTools.endsWith(p, ".fbx")) importFbx(path);
|
||||
// else if (StringTools.endsWith(p, ".blend")) importBlend(path);
|
||||
else showMessage("Error: Unknown mesh format");
|
||||
}
|
||||
|
||||
function importObj(path:String) {
|
||||
iron.data.Data.getBlob(path, function(b:kha.Blob) {
|
||||
|
||||
var obj = new iron.format.obj.Loader(b.toString());
|
||||
|
||||
if (obj.indexedVertices == null) {
|
||||
var obj = new iron.format.obj.ObjParser(b);
|
||||
if (obj.texa == null) {
|
||||
showMessage("Error: Invalid mesh - no UVs found");
|
||||
return;
|
||||
}
|
||||
makeMesh(obj);
|
||||
});
|
||||
}
|
||||
|
||||
var pa = new TFloat32Array(obj.indexedVertices.length);
|
||||
for (i in 0...pa.length) pa[i] = obj.indexedVertices[i];
|
||||
var uva = new TFloat32Array(obj.indexedUVs.length);
|
||||
for (i in 0...uva.length) uva[i] = obj.indexedUVs[i];
|
||||
var na = new TFloat32Array(obj.indexedNormals.length);
|
||||
for (i in 0...na.length) na[i] = obj.indexedNormals[i];
|
||||
var ia = new TUint32Array(obj.indices.length);
|
||||
for (i in 0...ia.length) ia[i] = obj.indices[i];
|
||||
function importGltf(path:String) {
|
||||
iron.data.Data.getBlob(path, function(b:kha.Blob) {
|
||||
var obj = new iron.format.gltf.GltfParser(b);
|
||||
if (obj.texa == null) {
|
||||
showMessage("Error: Invalid mesh - no UVs found");
|
||||
return;
|
||||
}
|
||||
makeMesh(obj);
|
||||
});
|
||||
}
|
||||
|
||||
var raw:TMeshData = {
|
||||
name: "Mesh",
|
||||
vertex_arrays: [
|
||||
{
|
||||
values: pa,
|
||||
attrib: "pos"
|
||||
},
|
||||
{
|
||||
values: na,
|
||||
attrib: "nor"
|
||||
},
|
||||
{
|
||||
values: uva,
|
||||
attrib: "tex"
|
||||
}
|
||||
],
|
||||
index_arrays: [
|
||||
{
|
||||
values: ia,
|
||||
material: 0
|
||||
}
|
||||
]
|
||||
};
|
||||
function importFbx(path:String) {
|
||||
iron.data.Data.getBlob(path, function(b:kha.Blob) {
|
||||
var obj = new iron.format.fbx.FbxParser(b);
|
||||
if (obj.texa == null) {
|
||||
showMessage("Error: Invalid mesh - no UVs found");
|
||||
return;
|
||||
}
|
||||
makeMesh(obj);
|
||||
});
|
||||
}
|
||||
|
||||
new MeshData(raw, function(md:MeshData) {
|
||||
currentObject.data.delete();
|
||||
iron.App.notifyOnRender(clearTargetsHandler);
|
||||
|
||||
currentObject.setData(md);
|
||||
|
||||
// Scale to bounds
|
||||
md.geom.calculateAABB();
|
||||
var r = Math.sqrt(md.geom.aabb.x * md.geom.aabb.x + md.geom.aabb.y * md.geom.aabb.y + md.geom.aabb.z * md.geom.aabb.z);
|
||||
if (r > 3) {
|
||||
currentObject.transform.scale.set(3 / r, 3 / r, 3 / r);
|
||||
currentObject.transform.buildMatrix();
|
||||
}
|
||||
function importBlend(path:String) {
|
||||
iron.data.Data.getBlob(path, function(b:kha.Blob) {
|
||||
var obj = new blend.Loader(b);
|
||||
// if (obj.texa == null) {
|
||||
// showMessage("Error: Invalid mesh - no UVs found");
|
||||
// return;
|
||||
// }
|
||||
// makeMesh(obj);
|
||||
});
|
||||
}
|
||||
|
||||
// Face camera
|
||||
currentObject.transform.setRotation(Math.PI / 2, 0, 0);
|
||||
|
||||
UITrait.dirty = true;
|
||||
});
|
||||
function makeMesh(mesh:Dynamic) {
|
||||
var raw:TMeshData = {
|
||||
name: "Mesh",
|
||||
vertex_arrays: [
|
||||
{ values: mesh.posa, attrib: "pos" },
|
||||
{ values: mesh.nora, attrib: "nor" },
|
||||
{ values: mesh.texa, attrib: "tex" }
|
||||
],
|
||||
index_arrays: [
|
||||
{ values: mesh.inda, material: 0 }
|
||||
]
|
||||
};
|
||||
|
||||
new MeshData(raw, function(md:MeshData) {
|
||||
currentObject.data.delete();
|
||||
iron.App.notifyOnRender(clearTargetsHandler);
|
||||
|
||||
currentObject.setData(md);
|
||||
|
||||
// Scale to bounds
|
||||
md.geom.calculateAABB();
|
||||
var r = Math.sqrt(md.geom.aabb.x * md.geom.aabb.x + md.geom.aabb.y * md.geom.aabb.y + md.geom.aabb.z * md.geom.aabb.z);
|
||||
currentObject.transform.scale.set(3 / r, 3 / r, 3 / r);
|
||||
currentObject.transform.buildMatrix();
|
||||
|
||||
// Face camera
|
||||
// currentObject.transform.setRotation(Math.PI / 2, 0, 0);
|
||||
|
||||
UITrait.dirty = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||