diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..4b308e96 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,7 @@ +# The zlib/libpng License + +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +This notice may not be removed or altered from any source distribution. diff --git a/Libraries/iron_format/Sources/iron/format/obj/Loader.hx b/Libraries/iron_format/Sources/iron/format/obj/Loader.hx index d6c6110f..fd4d3b81 100644 --- a/Libraries/iron_format/Sources/iron/format/obj/Loader.hx +++ b/Libraries/iron_format/Sources/iron/format/obj/Loader.hx @@ -2,9 +2,9 @@ package iron.format.obj; class Loader { - public var indexedVertices:Array; - public var indexedUVs:Array; - public var indexedNormals:Array; + public var indexedVertices:Array = null; + public var indexedUVs:Array = null; + public var indexedNormals:Array = null; public var index:Int; // public var data:Array; @@ -54,20 +54,50 @@ class Loader { var sec2:Array = words[2].split("/"); var sec3:Array = words[3].split("/"); - vertexIndices.push(Std.int(Std.parseFloat(sec1[0]))); - vertexIndices.push(Std.int(Std.parseFloat(sec2[0]))); - vertexIndices.push(Std.int(Std.parseFloat(sec3[0]))); + var vi0 = Std.int(Std.parseFloat(sec1[0])); + var vi1 = Std.int(Std.parseFloat(sec2[0])); + var vi2 = Std.int(Std.parseFloat(sec3[0])); + vertexIndices.push(vi0); + vertexIndices.push(vi1); + vertexIndices.push(vi2); - uvIndices.push(Std.int(Std.parseFloat(sec1[1]))); - uvIndices.push(Std.int(Std.parseFloat(sec2[1]))); - uvIndices.push(Std.int(Std.parseFloat(sec3[1]))); + var vuv0 = Std.int(Std.parseFloat(sec1[1])); + var vuv1 = Std.int(Std.parseFloat(sec2[1])); + var vuv2 = Std.int(Std.parseFloat(sec3[1])); + uvIndices.push(vuv0); + uvIndices.push(vuv1); + uvIndices.push(vuv2); - normalIndices.push(Std.int(Std.parseFloat(sec1[2]))); - normalIndices.push(Std.int(Std.parseFloat(sec2[2]))); - normalIndices.push(Std.int(Std.parseFloat(sec3[2]))); + var vn0 = Std.int(Std.parseFloat(sec1[2])); + var vn1 = Std.int(Std.parseFloat(sec2[2])); + var vn2 = Std.int(Std.parseFloat(sec3[2])); + normalIndices.push(vn0); + normalIndices.push(vn1); + normalIndices.push(vn2); + + if (words.length > 4) { + var sec4:Array = words[4].split("/"); + + vertexIndices.push(vi2); + vertexIndices.push(Std.int(Std.parseFloat(sec4[0]))); + vertexIndices.push(vi0); + + uvIndices.push(vuv2); + uvIndices.push(Std.int(Std.parseFloat(sec4[1]))); + uvIndices.push(vuv0); + + normalIndices.push(vn2); + normalIndices.push(Std.int(Std.parseFloat(sec4[2]))); + normalIndices.push(vn0); + } } } + // UVs not found + if (tempUVs.length == 0) { + return; + } + for (i in 0...vertexIndices.length) { var vertex:Array = tempVertices[vertexIndices[i] - 1]; var uv:Array = tempUVs[uvIndices[i] - 1]; diff --git a/README.md b/README.md index 76af2a51..4debe32b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ -# armorpaint - ![](img.jpg) + +armorpaint +============== + +[Manual](http://armorpaint.org/manual/) - [Forums](http://forums.armory3d.org) + +ArmorPaint is a tool for 3D PBR texture painting. Powered by [Armory](http://armory3d.org). diff --git a/Sources/arm/NodeCreator.hx b/Sources/arm/NodeCreator.hx index 8d78f05a..ef7347f6 100644 --- a/Sources/arm/NodeCreator.hx +++ b/Sources/arm/NodeCreator.hx @@ -66,7 +66,7 @@ class NodeCreator { nodes.nodeSelected = n; } - public static var numNodes = [6, 1, 5, 5, 9]; + public static var numNodes = [2, 1, 5, 5, 8]; public static function draw(uinodes:UINodes, cat:Int) { var ui = uinodes.ui; @@ -142,162 +142,162 @@ class NodeCreator { nodes.nodeDrag = n; nodes.nodeSelected = n; } - if (ui.button("Camera Data")) { - var node_id = nodes.getNodeId(canvas.nodes); - var n:TNode = { - id: node_id, - name: "Camera Data", - type: "CAMERA", - x: getNodeX(), - y: getNodeY(), - color: 0xff4982a0, - inputs: [], - outputs: [ - { - id: nodes.getSocketId(canvas.nodes), - node_id: node_id, - name: "View Vector", - type: "VECTOR", - color: 0xff6363c7, - default_value: [0.0, 0.0, 0.0] - }, - { - id: nodes.getSocketId(canvas.nodes), - node_id: node_id, - name: "View Z Depth", - type: "VALUE", - color: 0xffa1a1a1, - default_value: 0.0 - }, - { - id: nodes.getSocketId(canvas.nodes), - node_id: node_id, - name: "View Distance", - type: "VALUE", - color: 0xffa1a1a1, - default_value: 0.0 - } - ], - buttons: [] - }; - canvas.nodes.push(n); - nodes.nodeDrag = n; - nodes.nodeSelected = n; - } - if (ui.button("Geometry")) { - var node_id = nodes.getNodeId(canvas.nodes); - var n:TNode = { - id: node_id, - name: "Geometry", - type: "NEW_GEOMETRY", - x: getNodeX(), - y: getNodeY(), - color: 0xff4982a0, - inputs: [], - outputs: [ - { - id: nodes.getSocketId(canvas.nodes), - node_id: node_id, - name: "Position", - type: "VECTOR", - color: 0xff6363c7, - default_value: [0.0, 0.0, 0.0] - }, - { - id: nodes.getSocketId(canvas.nodes), - node_id: node_id, - name: "Normal", - type: "VECTOR", - color: 0xff6363c7, - default_value: [0.0, 0.0, 0.0] - } - ], - buttons: [] - }; - canvas.nodes.push(n); - nodes.nodeDrag = n; - nodes.nodeSelected = n; - } - if (ui.button("Fresnel")) { - var node_id = nodes.getNodeId(canvas.nodes); - var n:TNode = { - id: node_id, - name: "Fresnel", - type: "FRESNEL", - x: getNodeX(), - y: getNodeY(), - color: 0xff4982a0, - inputs: [ - { - id: nodes.getSocketId(canvas.nodes), - node_id: node_id, - name: "IOR", - type: "VALUE", - color: 0xffa1a1a1, - default_value: 1.450, - min: 0.0, - max: 2.0 - } - ], - outputs: [ - { - id: nodes.getSocketId(canvas.nodes), - node_id: node_id, - name: "Fac", - type: "VALUE", - color: 0xffa1a1a1, - default_value: 0.0 - } - ], - buttons: [] - }; - canvas.nodes.push(n); - nodes.nodeDrag = n; - nodes.nodeSelected = n; - } - if (ui.button("Layer Weight")) { - var node_id = nodes.getNodeId(canvas.nodes); - var n:TNode = { - id: node_id, - name: "Layer Weight", - type: "LAYER_WEIGHT", - x: getNodeX(), - y: getNodeY(), - color: 0xff4982a0, - inputs: [ - { - id: nodes.getSocketId(canvas.nodes), - node_id: node_id, - name: "Blend", - type: "VALUE", - color: 0xffa1a1a1, - default_value: 0.5 - } - ], - outputs: [ - { - id: nodes.getSocketId(canvas.nodes), - node_id: node_id, - name: "Fresnel", - type: "VALUE", - color: 0xffa1a1a1, - default_value: 0.0 - }, - { - id: nodes.getSocketId(canvas.nodes), - node_id: node_id, - name: "Facing", - type: "VALUE", - color: 0xffa1a1a1, - default_value: 0.0 - } - ], - buttons: [] - }; - canvas.nodes.push(n); - nodes.nodeDrag = n; - nodes.nodeSelected = n; - } + // if (ui.button("Camera Data")) { + // var node_id = nodes.getNodeId(canvas.nodes); + // var n:TNode = { + // id: node_id, + // name: "Camera Data", + // type: "CAMERA", + // x: getNodeX(), + // y: getNodeY(), + // color: 0xff4982a0, + // inputs: [], + // outputs: [ + // { + // id: nodes.getSocketId(canvas.nodes), + // node_id: node_id, + // name: "View Vector", + // type: "VECTOR", + // color: 0xff6363c7, + // default_value: [0.0, 0.0, 0.0] + // }, + // { + // id: nodes.getSocketId(canvas.nodes), + // node_id: node_id, + // name: "View Z Depth", + // type: "VALUE", + // color: 0xffa1a1a1, + // default_value: 0.0 + // }, + // { + // id: nodes.getSocketId(canvas.nodes), + // node_id: node_id, + // name: "View Distance", + // type: "VALUE", + // color: 0xffa1a1a1, + // default_value: 0.0 + // } + // ], + // buttons: [] + // }; + // canvas.nodes.push(n); + // nodes.nodeDrag = n; + // nodes.nodeSelected = n; + // } + // if (ui.button("Geometry")) { + // var node_id = nodes.getNodeId(canvas.nodes); + // var n:TNode = { + // id: node_id, + // name: "Geometry", + // type: "NEW_GEOMETRY", + // x: getNodeX(), + // y: getNodeY(), + // color: 0xff4982a0, + // inputs: [], + // outputs: [ + // { + // id: nodes.getSocketId(canvas.nodes), + // node_id: node_id, + // name: "Position", + // type: "VECTOR", + // color: 0xff6363c7, + // default_value: [0.0, 0.0, 0.0] + // }, + // { + // id: nodes.getSocketId(canvas.nodes), + // node_id: node_id, + // name: "Normal", + // type: "VECTOR", + // color: 0xff6363c7, + // default_value: [0.0, 0.0, 0.0] + // } + // ], + // buttons: [] + // }; + // canvas.nodes.push(n); + // nodes.nodeDrag = n; + // nodes.nodeSelected = n; + // } + // if (ui.button("Fresnel")) { + // var node_id = nodes.getNodeId(canvas.nodes); + // var n:TNode = { + // id: node_id, + // name: "Fresnel", + // type: "FRESNEL", + // x: getNodeX(), + // y: getNodeY(), + // color: 0xff4982a0, + // inputs: [ + // { + // id: nodes.getSocketId(canvas.nodes), + // node_id: node_id, + // name: "IOR", + // type: "VALUE", + // color: 0xffa1a1a1, + // default_value: 1.450, + // min: 0.0, + // max: 2.0 + // } + // ], + // outputs: [ + // { + // id: nodes.getSocketId(canvas.nodes), + // node_id: node_id, + // name: "Fac", + // type: "VALUE", + // color: 0xffa1a1a1, + // default_value: 0.0 + // } + // ], + // buttons: [] + // }; + // canvas.nodes.push(n); + // nodes.nodeDrag = n; + // nodes.nodeSelected = n; + // } + // if (ui.button("Layer Weight")) { + // var node_id = nodes.getNodeId(canvas.nodes); + // var n:TNode = { + // id: node_id, + // name: "Layer Weight", + // type: "LAYER_WEIGHT", + // x: getNodeX(), + // y: getNodeY(), + // color: 0xff4982a0, + // inputs: [ + // { + // id: nodes.getSocketId(canvas.nodes), + // node_id: node_id, + // name: "Blend", + // type: "VALUE", + // color: 0xffa1a1a1, + // default_value: 0.5 + // } + // ], + // outputs: [ + // { + // id: nodes.getSocketId(canvas.nodes), + // node_id: node_id, + // name: "Fresnel", + // type: "VALUE", + // color: 0xffa1a1a1, + // default_value: 0.0 + // }, + // { + // id: nodes.getSocketId(canvas.nodes), + // node_id: node_id, + // name: "Facing", + // type: "VALUE", + // color: 0xffa1a1a1, + // default_value: 0.0 + // } + // ], + // buttons: [] + // }; + // canvas.nodes.push(n); + // nodes.nodeDrag = n; + // nodes.nodeSelected = n; + // } } if (cat == 1) { // Output if (ui.button("Material Output")) { @@ -991,43 +991,43 @@ class NodeCreator { nodes.nodeDrag = n; nodes.nodeSelected = n; } - if (ui.button("Wavelength")) { - var node_id = nodes.getNodeId(canvas.nodes); - var n:TNode = { - id: node_id, - name: "Wavelength", - type: "WAVELENGTH", - x: getNodeX(), - y: getNodeY(), - color: 0xff4982a0, - inputs: [ - { - id: nodes.getSocketId(canvas.nodes), - node_id: node_id, - name: "Wavelength", - type: "VALUE", - color: 0xffa1a1a1, - default_value: 500.0, - min: 450.0, - max: 600.0 - } - ], - outputs: [ - { - id: nodes.getSocketId(canvas.nodes), - node_id: node_id, - name: "Color", - type: "RGBA", - color: 0xffc7c729, - default_value: [0.8, 0.8, 0.8] - } - ], - buttons: [] - }; - canvas.nodes.push(n); - nodes.nodeDrag = n; - nodes.nodeSelected = n; - } + // if (ui.button("Wavelength")) { + // var node_id = nodes.getNodeId(canvas.nodes); + // var n:TNode = { + // id: node_id, + // name: "Wavelength", + // type: "WAVELENGTH", + // x: getNodeX(), + // y: getNodeY(), + // color: 0xff4982a0, + // inputs: [ + // { + // id: nodes.getSocketId(canvas.nodes), + // node_id: node_id, + // name: "Wavelength", + // type: "VALUE", + // color: 0xffa1a1a1, + // default_value: 500.0, + // min: 450.0, + // max: 600.0 + // } + // ], + // outputs: [ + // { + // id: nodes.getSocketId(canvas.nodes), + // node_id: node_id, + // name: "Color", + // type: "RGBA", + // color: 0xffc7c729, + // default_value: [0.8, 0.8, 0.8] + // } + // ], + // buttons: [] + // }; + // canvas.nodes.push(n); + // nodes.nodeDrag = n; + // nodes.nodeSelected = n; + // } if (ui.button("Mapping")) { var node_id = nodes.getNodeId(canvas.nodes); var n:TNode = { diff --git a/Sources/arm/UINodes.hx b/Sources/arm/UINodes.hx index 8e728298..3c1b5424 100644 --- a/Sources/arm/UINodes.hx +++ b/Sources/arm/UINodes.hx @@ -14,6 +14,7 @@ class UINodes extends armory.Trait { public static var wx:Int; public static var wy:Int; + public static var ww:Int; var ui:Zui; var drawMenu = false; @@ -126,7 +127,7 @@ class UINodes extends armory.Trait { hideMenu = true; } - if (keyboard.started("x")) { + if (keyboard.started("x") || keyboard.started("backspace")) { nodes.removeNode(nodes.nodeSelected, canvas); changed = true; } @@ -136,7 +137,7 @@ class UINodes extends armory.Trait { } } - static var nodes = new Nodes(); + public static var nodes = new Nodes(); static var canvas:TNodeCanvas = null; @@ -175,6 +176,8 @@ class UINodes extends armory.Trait { grid.g2.end(); } + public var hwnd = Id.handle(); + @:access(zui.Zui) function render2D(g:kha.graphics2.Graphics) { @@ -192,11 +195,10 @@ class UINodes extends armory.Trait { // ui.begin(rt.g2); //// // Make window - var ww = Std.int(iron.App.w()); + ww = Std.int(iron.App.w()); wx = Std.int(iron.App.w()); wy = 0; - var hwin = Id.handle(); - if (ui.window(hwin, wx, wy, ww, iron.App.h())) { + if (ui.window(hwnd, wx, wy, ww, iron.App.h())) { ui.g.color = 0xffffffff; ui.g.drawImage(grid, (nodes.panX * nodes.SCALE) % 40 - 40, (nodes.panY * nodes.SCALE) % 40 - 40); @@ -324,18 +326,23 @@ class UINodes extends armory.Trait { frag.write('bsp = bsp * 0.5 + 0.5;'); frag.add_uniform('sampler2D paintdb'); - frag.write('if (sp.z > texture(paintdb, vec2(sp.x, 1.0 - bsp.y)).r) discard;'); - - frag.write('vec2 binp = inp.xy * 2.0 - 1.0;'); - frag.write('binp.x *= aspectRatio;'); - frag.write('binp = binp * 0.5 + 0.5;'); - - frag.write('float dist = distance(bsp.xy, binp.xy);'); frag.add_uniform('float brushRadius', '_brushRadius'); frag.add_uniform('float brushOpacity', '_brushOpacity'); frag.add_uniform('float brushStrength', '_brushStrength'); - frag.write('if (dist > brushRadius) discard;'); + if (UITrait.brushType == 0) { // Draw + frag.write('if (sp.z > texture(paintdb, vec2(sp.x, 1.0 - bsp.y)).r) discard;'); + + frag.write('vec2 binp = inp.xy * 2.0 - 1.0;'); + frag.write('binp.x *= aspectRatio;'); + frag.write('binp = binp * 0.5 + 0.5;'); + + frag.write('float dist = distance(bsp.xy, binp.xy);'); + frag.write('if (dist > brushRadius) discard;'); + } + else { + frag.write('float dist = 0.0;'); + } // Texture projection - texcoords if (UITrait.brushPaint == 0 && con_paint.is_elem('tex')) { @@ -363,11 +370,15 @@ class UINodes extends armory.Trait { frag.write(' float str = brushOpacity * clamp((brushRadius - dist) * brushStrength, 0.0, 1.0);'); frag.write(' str = clamp(str, 0.0, 1.0);'); - + frag.write(' fragColor[0] = vec4(basecol, str);'); frag.write(' fragColor[1] = vec4(nortan, 1.0);'); // Encode normal, height, opacity, matid,.. frag.write(' fragColor[2] = vec4(occlusion, roughness, metallic, str);'); + if (!UITrait.paintBase) frag.write('fragColor[0].a = 0.0;'); + if (!UITrait.paintNor) frag.write('fragColor[1].a = 0.0;'); + if (!UITrait.paintRough) frag.write('fragColor[2].a = 0.0;'); + con_paint.data.shader_from_source = true; con_paint.data.vertex_shader = vert.get(); con_paint.data.fragment_shader = frag.get(); @@ -490,7 +501,7 @@ class UINodes extends armory.Trait { // return con_mesh; // } - function parseMaterial() { + public function parseMaterial() { UITrait.dirty = true; var mout = false; diff --git a/Sources/arm/UITrait.hx b/Sources/arm/UITrait.hx index 5771ebbb..e793644a 100644 --- a/Sources/arm/UITrait.hx +++ b/Sources/arm/UITrait.hx @@ -27,12 +27,18 @@ class UITrait extends armory.Trait { public static var dragAsset:TAsset = null; public static var showFiles = false; + public static var foldersOnly = false; public static var filesDone:String->Void; public static var showSplash = false; public static var show = true; public static var dirty = true; + var message = ""; + var messageTimer = 0.0; + var dropPath = ""; + var dropX = 0.0; + var dropY = 0.0; var bundled:Map = new Map(); var ui:Zui; var uimodal:Zui; @@ -93,6 +99,15 @@ class UITrait extends armory.Trait { public static var brushStrength = 1.0; public static var brushBias = 1.0; public static var brushPaint = 0; + public static var brushType = 0; + + public static var paintBase = true; + public static var paintOpac = true; + public static var paintOcc = true; + public static var paintRough = true; + public static var paintMet = true; + public static var paintNor = true; + function linkFloat(link:String):Null { if (link == '_brushRadius') { @@ -156,13 +171,31 @@ class UITrait extends armory.Trait { kha.System.notifyOnDropFiles(function(filePath:String) { dropPath = StringTools.rtrim(filePath); + var mouse = iron.system.Input.getMouse(); + dropX = mouse.x; + dropY = mouse.y; }); } - function importAsset(path:String) { + function showMessage(s:String) { + messageTimer = 3.0; + message = s; + hwnd.redraws = 2; + } + + function checkImageFormat(path:String):Bool { if (!StringTools.endsWith(path, ".jpg") && !StringTools.endsWith(path, ".png") && - !StringTools.endsWith(path, ".hdr")) return; + !StringTools.endsWith(path, ".hdr")) { + return false; + } + return true; + } + + function importAsset(path:String) { + if (!checkImageFormat(path)) { + showMessage("Error: Unknown asset format"); + } iron.data.Data.getImage(path, function(image:kha.Image) { var ar = path.split("/"); @@ -210,6 +243,11 @@ class UITrait extends armory.Trait { function resize() { iron.Scene.active.camera.buildProjection(); + + if (UINodes.grid != null) { + UINodes.grid.unload(); + UINodes.grid = null; + } } function update() { @@ -220,6 +258,9 @@ class UITrait extends armory.Trait { } function updateUI() { + + messageTimer -= iron.system.Time.delta; + paint = false; var mouse = iron.system.Input.getMouse(); // if (mouse.started() && mouse.x < 50 && mouse.y < 50) show = !show; @@ -350,7 +391,15 @@ class UITrait extends armory.Trait { if (dropPath != "") { if (StringTools.endsWith(dropPath, ".obj")) importMesh(dropPath); - else importAsset(dropPath); + else { + importAsset(dropPath); + // Place image node + if (UINodes.show && dropX > UINodes.wx && dropX < UINodes.wx + UINodes.ww) { + UINodes.acceptDrag(assets.length - 1); + UINodes.nodes.nodeDrag = null; + UINodes.inst.hwnd.redraws = 2; + } + } dropPath = ""; } @@ -391,6 +440,7 @@ class UITrait extends armory.Trait { } var isBase = true; + var isOpac = true; var isOcc = true; var isRough = true; var isMet = true; @@ -433,8 +483,13 @@ class UITrait extends armory.Trait { // showSplash = true; // } + if (messageTimer > 0) { + ui.text(message); + } + if (ui.button("Import Mesh")) { showFiles = true; + foldersOnly = false; filesDone = function(path:String) { importMesh(path); } @@ -448,6 +503,7 @@ class UITrait extends armory.Trait { var textureSize = getTextureRes(); showFiles = true; + foldersOnly = true; // var path = 'C:\\Users\\lubos\\Documents\\'; filesDone = function(path:String) { var bo = new haxe.io.BytesOutput(); @@ -470,7 +526,7 @@ class UITrait extends armory.Trait { // var jpgwriter = new iron.format.jpg.Writer(bo); // jpgwriter.write(jpgdata); #if kha_krom - Krom.fileSaveBytes(path + "/tex_basecol.png", bo.getBytes().getData()); + if (isBase) Krom.fileSaveBytes(path + "/tex_basecol.png", bo.getBytes().getData()); #end pixels = texpaint_nor.getPixels(); @@ -483,7 +539,7 @@ class UITrait extends armory.Trait { var pngwriter = new iron.format.png.Writer(bo); pngwriter.write(iron.format.png.Tools.buildRGB(textureSize, textureSize, rgb)); #if kha_krom - Krom.fileSaveBytes(path + "/tex_nor.png", bo.getBytes().getData()); + if (isNor) Krom.fileSaveBytes(path + "/tex_nor.png", bo.getBytes().getData()); #end // for (i in 0...textureSize * textureSize) { @@ -508,7 +564,7 @@ class UITrait extends armory.Trait { var pngwriter = new iron.format.png.Writer(bo); pngwriter.write(iron.format.png.Tools.buildRGB(textureSize, textureSize, rgb)); #if kha_krom - Krom.fileSaveBytes(path + "/tex_occ.png", bo.getBytes().getData()); + if (isOcc) Krom.fileSaveBytes(path + "/tex_occ.png", bo.getBytes().getData()); #end for (i in 0...textureSize * textureSize) { @@ -520,7 +576,7 @@ class UITrait extends armory.Trait { var pngwriter = new iron.format.png.Writer(bo); pngwriter.write(iron.format.png.Tools.buildRGB(textureSize, textureSize, rgb)); #if kha_krom - Krom.fileSaveBytes(path + "/tex_rough.png", bo.getBytes().getData()); + if (isRough) Krom.fileSaveBytes(path + "/tex_rough.png", bo.getBytes().getData()); #end for (i in 0...textureSize * textureSize) { @@ -532,12 +588,12 @@ class UITrait extends armory.Trait { var pngwriter = new iron.format.png.Writer(bo); pngwriter.write(iron.format.png.Tools.buildRGB(textureSize, textureSize, rgb)); #if kha_krom - Krom.fileSaveBytes(path + "/tex_met.png", bo.getBytes().getData()); + if (isMet) Krom.fileSaveBytes(path + "/tex_met.png", bo.getBytes().getData()); #end } } - if (ui.panel(Id.handle({selected: false}), "Properties")) { + if (ui.panel(Id.handle({selected: false}), "Export")) { var hres = Id.handle({position: textureRes}); textureRes = ui.combo(hres, ["1K", "2K", "4K", "8K", "16K", "20K"], "Res", true); @@ -546,17 +602,19 @@ class UITrait extends armory.Trait { } ui.combo(Id.handle(), ["8bit"], "Color", true); ui.combo(Id.handle(), ["png"], "Format", true); - // ui.text("Channels"); + ui.text("Channels"); ui.row([1/2, 1/2]); isBase = ui.check(Id.handle({selected: isBase}), "Base Color"); - isOcc = ui.check(Id.handle({selected: isOcc}), "Occlusion"); + isOpac = ui.check(Id.handle({selected: isOpac}), "Opacity"); ui.row([1/2, 1/2]); + isOcc = ui.check(Id.handle({selected: isOcc}), "Occlusion"); isRough = ui.check(Id.handle({selected: isRough}), "Roughness"); + ui.row([1/2, 1/2]); isMet = ui.check(Id.handle({selected: isMet}), "Metallic"); isNor = ui.check(Id.handle({selected: isNor}), "Normal Map"); } - if (ui.panel(Id.handle({selected: true}), "Camera")) { + if (ui.panel(Id.handle({selected: false}), "Camera")) { ui.row([1/2,1/2]); cameraType = ui.combo(Id.handle({position: cameraType}), ["Orbit", "Fly"], "Camera"); @@ -600,7 +658,7 @@ class UITrait extends armory.Trait { // } // ui.separator(); - if (ui.panel(Id.handle({selected: true}), "Environment")) { + if (ui.panel(Id.handle({selected: false}), "Environment")) { ui.image(envThumbCay); var p = iron.Scene.active.world.getGlobalProbe(); ui.row([1/2, 1/2]); @@ -618,12 +676,15 @@ class UITrait extends armory.Trait { var paintHandle = Id.handle(); brushPaint = ui.combo(paintHandle, ["UV", "Project"], "Paint"); if (paintHandle.changed) { - UINodes.changed = true; + UINodes.inst.parseMaterial(); } brushBias = ui.slider(Id.handle({value: brushBias}), "Bias", 0.0, 4.0, true); ui.row([1/2, 1/2]); - // ui.combo(Id.handle(), ["Draw", "Fill"], "Type"); - ui.combo(Id.handle(), ["Draw"], "Type"); + var typeHandle = Id.handle(); + brushType = ui.combo(typeHandle, ["Draw", "Fill"], "Type"); + if (typeHandle.changed) { + UINodes.inst.parseMaterial(); + } ui.combo(Id.handle(), ["Add"], "Blending"); ui.row([1/2, 1/2]); brushRadius = ui.slider(Id.handle({value: brushRadius}), "Radius", 0.0, 2.0, true); @@ -641,13 +702,48 @@ class UITrait extends armory.Trait { 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"); + + var baseHandle = Id.handle({selected: paintBase}); + paintBase = ui.check(baseHandle, "Base Color"); + if (baseHandle.changed) { + UINodes.inst.parseMaterial(); + } + + var norHandle = Id.handle({selected: paintNor}); + paintNor = ui.check(norHandle, "Normal Map"); + if (norHandle.changed) { + UINodes.inst.parseMaterial(); + } + + var roughHandle = Id.handle({selected: paintRough}); + paintRough = ui.check(roughHandle, "Rough Met Occ"); + if (roughHandle.changed) { + UINodes.inst.parseMaterial(); + } } + + ui.text("v0.1", zui.Zui.Align.Right); } if (ui.tab(htab, "Assets")) { + if (messageTimer > 0) { + ui.text(message); + } + if (ui.button("Import")) { showFiles = true; + foldersOnly = false; filesDone = function(path:String) { importAsset(path); } @@ -731,7 +827,7 @@ class UITrait extends armory.Trait { if (uimodal.window(Id.handle(), leftRect, topRect, modalRectW, modalRectH - 100)) { var pathHandle = Id.handle(); pathHandle.text = uimodal.textInput(pathHandle); - path = zui.Ext.fileBrowser(uimodal, pathHandle); + path = zui.Ext.fileBrowser(uimodal, pathHandle, foldersOnly); } uimodal.end(false); g.begin(false); @@ -753,10 +849,20 @@ class UITrait extends armory.Trait { } function importMesh(path:String) { + if (!StringTools.endsWith(path, ".obj")) { + showMessage("Error: Unknown mesh format"); + return; + } iron.data.Data.getBlob(path, function(b:kha.Blob) { var obj = new iron.format.obj.Loader(b.toString()); + + if (obj.indexedVertices == null) { + showMessage("Error: Invalid mesh - no UVs found"); + return; + } + 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); diff --git a/armorpaint.blend b/armorpaint.blend index 3160c7f1..8f2748e9 100644 Binary files a/armorpaint.blend and b/armorpaint.blend differ