Files
armorpaint/base/Sources/ImportBlendMaterial.ts
T
luboslenco 10d57f0058 Cleanup
2024-01-23 14:51:21 +01:00

292 lines
9.3 KiB
TypeScript

class ImportBlendMaterial {
static run = (path: string) => {
Data.getBlob(path, (b: ArrayBuffer) => {
let bl = ParserBlend.init(b);
if (bl.dna == null) {
Console.error(Strings.error3());
return;
}
let mats = ParserBlend.get(bl, "Material");
if (mats.length == 0) {
Console.error("Error: No materials found");
return;
}
let imported: SlotMaterial[] = [];
for (let mat of mats) {
// Material slot
Context.raw.material = new SlotMaterial(Project.materials[0].data);
Project.materials.push(Context.raw.material);
imported.push(Context.raw.material);
let nodes = Context.raw.material.nodes;
let canvas = Context.raw.material.canvas;
canvas.name = BlHandle.get(BlHandle.get(mat, "id"), "name").substr(2); // MAWood
let nout: TNode = null;
for (let n of canvas.nodes) {
if (n.type == "OUTPUT_MATERIAL_PBR") {
nout = n;
break;
}
}
for (let n of canvas.nodes) {
if (n.name == "RGB") {
nodes.removeNode(n, canvas);
break;
}
}
// Parse nodetree
let nodetree = BlHandle.get(mat, "nodetree"); // bNodeTree
let blnodes = BlHandle.get(nodetree, "nodes"); // ListBase
let bllinks = BlHandle.get(nodetree, "links"); // bNodeLink
// Look for Principled BSDF node
let node: any = BlHandle.get(blnodes, "first", 0, "bNode");
let last = BlHandle.get(blnodes, "last", 0, "bNode");
while (true) {
if (BlHandle.get(node, "idname") == "ShaderNodeBsdfPrincipled") break;
if (BlHandle.get(node, "name") == BlHandle.get(last, "name")) break;
node = BlHandle.get(node, "next");
}
if (BlHandle.get(node, "idname") != "ShaderNodeBsdfPrincipled") {
Console.error("Error: No Principled BSDF node found");
continue;
}
// Use Principled BSDF as material output
nout.name = BlHandle.get(node, "name");
nout.x = BlHandle.get(node, "locx") + 400;
nout.y = -BlHandle.get(node, "locy") + 400;
// Place nodes
node = BlHandle.get(blnodes, "first", 0, "bNode");
while (true) {
// Search for node in list
let search = BlHandle.get(node, "idname").substr(10).toLowerCase();
let base: TNode = null;
for (let list of NodesMaterial.list) {
let found = false;
for (let n of list) {
let s = n.type.replace("_", "").toLowerCase();
if (search == s) {
base = n;
found = true;
break;
}
}
if (found) break;
}
if (base != null) {
let n = UINodes.makeNode(base, nodes, canvas);
n.x = BlHandle.get(node, "locx") + 400;
n.y = -BlHandle.get(node, "locy") + 400;
n.name = BlHandle.get(node, "name");
// Fill input socket values
let inputs = BlHandle.get(node, "inputs");
let sock: any = BlHandle.get(inputs, "first", 0, "bNodeSocket");
let pos = 0;
while (true) {
if (pos >= n.inputs.length) break;
n.inputs[pos].default_value = ImportBlendMaterial.readBlendSocket(sock);
let last = sock;
sock = BlHandle.get(sock, "next");
if (last.block == sock.block) break;
pos++;
}
// Fill button values
if (search == "teximage") {
let img = BlHandle.get(node, "id", 0, "Image");
let file: string = BlHandle.get(img, "name").substr(2); // '//desktop\logo.png'
file = Path.baseDir(path) + file;
ImportTexture.run(file);
let ar = file.split(Path.sep);
let filename = ar[ar.length - 1];
n.buttons[0].default_value = Base.getAssetIndex(filename);
}
else if (search == "valtorgb") {
let ramp: any = BlHandle.get(node, "storage", 0, "ColorBand");
n.buttons[0].data = BlHandle.get(ramp, "ipotype") == 0 ? 0 : 1; // Linear / Constant
let elems: f32[][] = n.buttons[0].default_value;
for (let i = 0; i < BlHandle.get(ramp, "tot"); ++i) {
if (i >= elems.length) elems.push([1.0, 1.0, 1.0, 1.0, 0.0]);
let cbdata: any = BlHandle.get(ramp, "data", i, "CBData");
elems[i][0] = Math.floor(BlHandle.get(cbdata, "r") * 100) / 100;
elems[i][1] = Math.floor(BlHandle.get(cbdata, "g") * 100) / 100;
elems[i][2] = Math.floor(BlHandle.get(cbdata, "b") * 100) / 100;
elems[i][3] = Math.floor(BlHandle.get(cbdata, "a") * 100) / 100;
elems[i][4] = Math.floor(BlHandle.get(cbdata, "pos") * 100) / 100;
}
}
else if (search == "mixrgb" || search == "math") {
n.buttons[0].default_value = BlHandle.get(node, "custom1");
n.buttons[1].default_value = BlHandle.get(node, "custom2") & 2;
}
else if (search == "mapping") {
let storage = BlHandle.get(node, "storage", 0, "TexMapping");
n.buttons[0].default_value = BlHandle.get(storage, "loc");
n.buttons[1].default_value = BlHandle.get(storage, "rot");
n.buttons[2].default_value = BlHandle.get(storage, "size");
// let mat = BlHandle.get(storage, "mat"); float[4][4]
// storage.flag & 1 // use_min
// storage.flag & 2 // use_max
// storage.min[0]
// storage.min[1]
// storage.min[2]
// storage.max[0]
// storage.max[1]
// storage.max[2]
}
// Fill output socket values
let outputs = BlHandle.get(node, "outputs");
sock = BlHandle.get(outputs, "first", 0, "bNodeSocket");
pos = 0;
while (true) {
if (pos >= n.outputs.length) break;
n.outputs[pos].default_value = ImportBlendMaterial.readBlendSocket(sock);
let last = sock;
sock = BlHandle.get(sock, "next");
if (last.block == sock.block) break;
pos++;
}
canvas.nodes.push(n);
}
if (BlHandle.get(node, "name") == BlHandle.get(last, "name")) break;
node = BlHandle.get(node, "next");
}
// Place links
let link: any = BlHandle.get(bllinks, "first", 0, "bNodeLink");
while (true) {
let fromnode = BlHandle.get(BlHandle.get(link, "fromnode"), "name");
let tonode = BlHandle.get(BlHandle.get(link, "tonode"), "name");
let fromsock = BlHandle.get(link, "fromsock");
let tosock = BlHandle.get(link, "tosock");
let from_id = -1;
let to_id = -1;
for (let n of canvas.nodes) {
if (n.name == fromnode) {
from_id = n.id;
break;
}
}
for (let n of canvas.nodes) {
if (n.name == tonode) {
to_id = n.id;
break;
}
}
if (from_id >= 0 && to_id >= 0) {
let from_socket = 0;
let sock: any = fromsock;
while (true) {
let last = sock;
sock = BlHandle.get(sock, "prev");
if (last.block == sock.block) break;
from_socket++;
}
let to_socket = 0;
sock = tosock;
while (true) {
let last = sock;
sock = BlHandle.get(sock, "prev");
if (last.block == sock.block) break;
to_socket++;
}
let valid = true;
// Remap principled
if (tonode == nout.name) {
if (to_socket == 0) to_socket = 0; // Base
else if (to_socket == 18) to_socket = 1; // Opac
else if (to_socket == 7) to_socket = 3; // Rough
else if (to_socket == 4) to_socket = 4; // Met
else if (to_socket == 19) to_socket = 5; // TODO: auto-remove normal_map node
else if (to_socket == 17) to_socket = 6; // Emis
else if (to_socket == 1) to_socket = 8; // Subs
else valid = false;
}
if (valid) {
let raw: TNodeLink = {
id: nodes.getLinkId(canvas.links),
from_id: from_id,
from_socket: from_socket,
to_id: to_id,
to_socket: to_socket
};
canvas.links.push(raw);
}
}
let last = link;
link = BlHandle.get(link, "next");
if (last.block == link.block) break;
}
History.newMaterial();
}
let _init = () => {
for (let m of imported) {
Context.setMaterial(m);
MakeMaterial.parsePaintMaterial();
UtilRender.makeMaterialPreview();
}
}
App.notifyOnInit(_init);
UIBase.hwnds[TabArea.TabSidebar1].redraws = 2;
Data.deleteBlob(path);
});
}
static readBlendSocket = (sock: any): any => {
let idname = BlHandle.get(sock, "idname");
if (idname.startsWith("NodeSocketVector")) {
let v: any = BlHandle.get(BlHandle.get(sock, "default_value", 0, "bNodeSocketValueVector"), "value");
v[0] = Math.floor(v[0] * 100) / 100;
v[1] = Math.floor(v[1] * 100) / 100;
v[2] = Math.floor(v[2] * 100) / 100;
return v;
}
else if (idname.startsWith("NodeSocketColor")) {
let v: any = BlHandle.get(BlHandle.get(sock, "default_value", 0, "bNodeSocketValueRGBA"), "value");
v[0] = Math.floor(v[0] * 100) / 100;
v[1] = Math.floor(v[1] * 100) / 100;
v[2] = Math.floor(v[2] * 100) / 100;
v[3] = Math.floor(v[3] * 100) / 100;
return v;
}
else if (idname.startsWith("NodeSocketFloat")) {
let v: any = BlHandle.get(BlHandle.get(sock, "default_value", 0, "bNodeSocketValueFloat"), "value");
v = Math.floor(v * 100) / 100;
return v;
}
else if (idname.startsWith("NodeSocketInt")) {
return BlHandle.get(BlHandle.get(sock, "default_value", 0, "bNodeSocketValueInt"), "value");
}
else if (idname.startsWith("NodeSocketBoolean")) {
return BlHandle.get(BlHandle.get(sock, "default_value", 0, "bNodeSocketValueBoolean"), "value");
}
else if (idname.startsWith("NodeSocketString")) {
return BlHandle.get(BlHandle.get(sock, "default_value", 0, "bNodeSocketValueString"), "value");
}
return null;
}
}