366 lines
12 KiB
TypeScript
366 lines
12 KiB
TypeScript
|
|
function import_blend_material_run(path: string) {
|
|
let b: buffer_t = data_get_blob(path);
|
|
let bl: blend_t = parser_blend_init(b);
|
|
if (bl.dna == null) {
|
|
console_error(strings_error3());
|
|
return;
|
|
}
|
|
|
|
let mats: bl_handle_t[] = parser_blend_get(bl, "Material");
|
|
if (mats.length == 0) {
|
|
console_error("Error: No materials found");
|
|
return;
|
|
}
|
|
|
|
let imported: slot_material_t[] = [];
|
|
|
|
for (let i: i32 = 0; i < mats.length; ++i) {
|
|
let mat: bl_handle_t = mats[i];
|
|
// Material slot
|
|
context_raw.material = slot_material_create(project_materials[0].data);
|
|
array_push(project_materials, context_raw.material);
|
|
array_push(imported, context_raw.material);
|
|
let nodes: ui_nodes_t = context_raw.material.nodes;
|
|
let canvas: ui_node_canvas_t = context_raw.material.canvas;
|
|
let id: bl_handle_t = bl_handle_get(mat, "id");
|
|
canvas.name = bl_handle_get(id, "name"); // MAWood
|
|
canvas.name = substring(canvas.name, 2, canvas.name.length);
|
|
let nout: ui_node_t = null;
|
|
for (let i: i32 = 0; i < canvas.nodes.length; ++i) {
|
|
let n: ui_node_t = canvas.nodes[i];
|
|
if (n.type == "OUTPUT_MATERIAL_PBR") {
|
|
nout = n;
|
|
break;
|
|
}
|
|
}
|
|
for (let i: i32 = 0; i < canvas.nodes.length; ++i) {
|
|
let n: ui_node_t = canvas.nodes[i];
|
|
if (n.name == "RGB") {
|
|
ui_remove_node(n, canvas);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Parse nodetree
|
|
let nodetree: bl_handle_t = bl_handle_get(mat, "nodetree"); // bNodeTree
|
|
let blnodes: bl_handle_t = bl_handle_get(nodetree, "nodes"); // ListBase
|
|
let bllinks: bl_handle_t = bl_handle_get(nodetree, "links"); // bNodeLink
|
|
|
|
// Look for Principled BSDF node
|
|
let node: bl_handle_t = bl_handle_get(blnodes, "first", 0, "bNode");
|
|
let last: bl_handle_t = bl_handle_get(blnodes, "last", 0, "bNode");
|
|
while (true) {
|
|
if (bl_handle_get(node, "idname") == "ShaderNodeBsdfPrincipled") {
|
|
break;
|
|
}
|
|
if (bl_handle_get(node, "name") == bl_handle_get(last, "name")) {
|
|
break;
|
|
}
|
|
node = bl_handle_get(node, "next");
|
|
}
|
|
if (bl_handle_get(node, "idname") != "ShaderNodeBsdfPrincipled") {
|
|
console_error("Error: No Principled BSDF node found");
|
|
continue;
|
|
}
|
|
|
|
// Use Principled BSDF as material output
|
|
nout.name = bl_handle_get(node, "name");
|
|
let nx: i32 = bl_handle_get_i(node, "locx");
|
|
let ny: i32 = bl_handle_get_i(node, "locy");
|
|
nout.x = nx + 400;
|
|
nout.y = -ny + 400;
|
|
|
|
// Place nodes
|
|
node = bl_handle_get(blnodes, "first", 0, "bNode");
|
|
while (true) {
|
|
// Search for node in list
|
|
let search: string = bl_handle_get(node, "idname");
|
|
search = to_lower_case(substring(search, 10, search.length));
|
|
let base: ui_node_t = null;
|
|
for (let i: i32 = 0; i < nodes_material_list.length; ++i) {
|
|
let list: ui_node_t[] = nodes_material_list[i];
|
|
let found: bool = false;
|
|
for (let i: i32 = 0; i < list.length; ++i) {
|
|
let n: ui_node_t = list[i];
|
|
let s: string = to_lower_case(string_replace_all(n.type, "_", ""));
|
|
if (search == s) {
|
|
base = n;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (base != null) {
|
|
let n: ui_node_t = ui_nodes_make_node(base, nodes, canvas);
|
|
n.x = bl_handle_get_i(node, "locx") + 400;
|
|
n.y = -bl_handle_get_i(node, "locy") + 400;
|
|
n.name = bl_handle_get(node, "name");
|
|
|
|
// Fill input socket values
|
|
let inputs: bl_handle_t = bl_handle_get(node, "inputs");
|
|
let sock: bl_handle_t = bl_handle_get(inputs, "first", 0, "bNodeSocket");
|
|
let pos: i32 = 0;
|
|
while (true) {
|
|
if (pos >= n.inputs.length) {
|
|
break;
|
|
}
|
|
n.inputs[pos].default_value = import_blend_material_read_blend_socket(sock);
|
|
|
|
let last: bl_handle_t = sock;
|
|
sock = bl_handle_get(sock, "next");
|
|
if (last.block == sock.block) {
|
|
break;
|
|
}
|
|
pos++;
|
|
}
|
|
|
|
// Fill button values
|
|
if (search == "teximage") {
|
|
let img: bl_handle_t = bl_handle_get(node, "id", 0, "Image");
|
|
let file: string = bl_handle_get(img, "name"); // "//desktop\logo.png"
|
|
file = substring(file, 2, file.length);
|
|
file = path_base_dir(path) + file;
|
|
import_texture_run(file);
|
|
let ar: string[] = string_split(file, path_sep);
|
|
let filename: string = ar[ar.length - 1];
|
|
n.buttons[0].default_value = f32_array_create_x(base_get_asset_index(filename));
|
|
}
|
|
else if (search == "valtorgb") {
|
|
// let ramp: bl_handle_t = bl_handle_get(node, "storage", 0, "ColorBand");
|
|
// n.buttons[0].data = bl_handle_get(ramp, "ipotype") == 0 ? 0 : 1; // Linear / Constant
|
|
// let elems: f32[][] = n.buttons[0].default_value;
|
|
// for (let i: i32 = 0; i < bl_handle_get(ramp, "tot"); ++i) {
|
|
// if (i >= elems.length) {
|
|
// array_push(elems, [1.0, 1.0, 1.0, 1.0, 0.0]);
|
|
// }
|
|
// let cbdata: bl_handle_t = bl_handle_get(ramp, "data", i, "CBData");
|
|
// elems[i][0] = math_floor(bl_handle_get(cbdata, "r") * 100) / 100;
|
|
// elems[i][1] = math_floor(bl_handle_get(cbdata, "g") * 100) / 100;
|
|
// elems[i][2] = math_floor(bl_handle_get(cbdata, "b") * 100) / 100;
|
|
// elems[i][3] = math_floor(bl_handle_get(cbdata, "a") * 100) / 100;
|
|
// elems[i][4] = math_floor(bl_handle_get(cbdata, "pos") * 100) / 100;
|
|
// }
|
|
}
|
|
else if (search == "mixrgb" || search == "math") {
|
|
n.buttons[0].default_value = f32_array_create_x(bl_handle_get_i(node, "custom1"));
|
|
n.buttons[1].default_value = f32_array_create_x(bl_handle_get_i(node, "custom2") & 2);
|
|
}
|
|
else if (search == "mapping") {
|
|
let storage: bl_handle_t = bl_handle_get(node, "storage", 0, "TexMapping");
|
|
let v: f32_ptr = bl_handle_get(storage, "loc");
|
|
n.buttons[0].default_value = f32_array_create(3);
|
|
n.buttons[0].default_value[0] = ARRAY_ACCESS(v, 0);
|
|
n.buttons[0].default_value[1] = ARRAY_ACCESS(v, 1);
|
|
n.buttons[0].default_value[2] = ARRAY_ACCESS(v, 2);
|
|
|
|
v = bl_handle_get(storage, "rot");
|
|
n.buttons[1].default_value = f32_array_create(3);
|
|
n.buttons[1].default_value[0] = ARRAY_ACCESS(v, 0);
|
|
n.buttons[1].default_value[1] = ARRAY_ACCESS(v, 1);
|
|
n.buttons[1].default_value[2] = ARRAY_ACCESS(v, 2);
|
|
|
|
v = bl_handle_get(storage, "size");
|
|
n.buttons[2].default_value = f32_array_create(3);
|
|
n.buttons[2].default_value[0] = ARRAY_ACCESS(v, 0);
|
|
n.buttons[2].default_value[1] = ARRAY_ACCESS(v, 1);
|
|
n.buttons[2].default_value[2] = ARRAY_ACCESS(v, 2);
|
|
|
|
// let mat: any = 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: bl_handle_t = bl_handle_get(node, "outputs");
|
|
sock = bl_handle_get(outputs, "first", 0, "bNodeSocket");
|
|
pos = 0;
|
|
while (true) {
|
|
if (pos >= n.outputs.length) {
|
|
break;
|
|
}
|
|
n.outputs[pos].default_value = import_blend_material_read_blend_socket(sock);
|
|
|
|
let last: bl_handle_t = sock;
|
|
sock = bl_handle_get(sock, "next");
|
|
if (last.block == sock.block) {
|
|
break;
|
|
}
|
|
pos++;
|
|
}
|
|
|
|
array_push(canvas.nodes, n);
|
|
}
|
|
|
|
if (bl_handle_get(node, "name") == bl_handle_get(last, "name")) {
|
|
break;
|
|
}
|
|
node = bl_handle_get(node, "next");
|
|
}
|
|
|
|
// Place links
|
|
let link: bl_handle_t = bl_handle_get(bllinks, "first", 0, "bNodeLink");
|
|
while (true) {
|
|
let fromnode: bl_handle_t = bl_handle_get(bl_handle_get(link, "fromnode"), "name");
|
|
let tonode: string = bl_handle_get(bl_handle_get(link, "tonode"), "name");
|
|
let fromsock: bl_handle_t = bl_handle_get(link, "fromsock");
|
|
let tosock: bl_handle_t = bl_handle_get(link, "tosock");
|
|
|
|
let from_id: i32 = -1;
|
|
let to_id: i32 = -1;
|
|
for (let i: i32 = 0; i < canvas.nodes.length; ++i) {
|
|
let n: ui_node_t = canvas.nodes[i];
|
|
if (n.name == fromnode) {
|
|
from_id = n.id;
|
|
break;
|
|
}
|
|
}
|
|
for (let i: i32 = 0; i < canvas.nodes.length; ++i) {
|
|
let n: ui_node_t = canvas.nodes[i];
|
|
if (n.name == tonode) {
|
|
to_id = n.id;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (from_id >= 0 && to_id >= 0) {
|
|
let from_socket: i32 = 0;
|
|
let sock: bl_handle_t = fromsock;
|
|
while (true) {
|
|
let last: bl_handle_t = sock;
|
|
sock = bl_handle_get(sock, "prev");
|
|
if (last.block == sock.block) {
|
|
break;
|
|
}
|
|
from_socket++;
|
|
}
|
|
|
|
let to_socket: i32 = 0;
|
|
sock = tosock;
|
|
while (true) {
|
|
let last: bl_handle_t = sock;
|
|
sock = bl_handle_get(sock, "prev");
|
|
if (last.block == sock.block) {
|
|
break;
|
|
}
|
|
to_socket++;
|
|
}
|
|
|
|
let valid: bool = 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: ui_node_link_t = {
|
|
id: ui_next_link_id(canvas.links),
|
|
from_id: from_id,
|
|
from_socket: from_socket,
|
|
to_id: to_id,
|
|
to_socket: to_socket
|
|
};
|
|
array_push(canvas.links, raw);
|
|
}
|
|
}
|
|
|
|
let last: bl_handle_t = link;
|
|
link = bl_handle_get(link, "next");
|
|
if (last.block == link.block) {
|
|
break;
|
|
}
|
|
}
|
|
history_new_material();
|
|
}
|
|
|
|
app_notify_on_init(function (imported: slot_material_t[]) {
|
|
for (let i: i32 = 0; i < imported.length; ++i) {
|
|
let m: slot_material_t = imported[i];
|
|
context_set_material(m);
|
|
make_material_parse_paint_material();
|
|
util_render_make_material_preview();
|
|
}
|
|
}, imported);
|
|
|
|
ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
|
|
data_delete_blob(path);
|
|
}
|
|
|
|
function import_blend_material_read_blend_socket(sock: bl_handle_t): f32_array_t {
|
|
let idname: string = bl_handle_get(sock, "idname");
|
|
if (starts_with(idname, "NodeSocketVector")) {
|
|
let v: f32_ptr = bl_handle_get(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueVector"), "value");
|
|
let a: f32_array_t = f32_array_create(3);
|
|
a[0] = math_floor(ARRAY_ACCESS(v, 0) * 100) / 100;
|
|
a[1] = math_floor(ARRAY_ACCESS(v, 1) * 100) / 100;
|
|
a[2] = math_floor(ARRAY_ACCESS(v, 2) * 100) / 100;
|
|
return a;
|
|
}
|
|
else if (starts_with(idname, "NodeSocketColor")) {
|
|
let v: f32_ptr = bl_handle_get(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueRGBA"), "value");
|
|
let a: f32_array_t = f32_array_create(4);
|
|
a[0] = math_floor(ARRAY_ACCESS(v, 0) * 100) / 100;
|
|
a[1] = math_floor(ARRAY_ACCESS(v, 1) * 100) / 100;
|
|
a[2] = math_floor(ARRAY_ACCESS(v, 2) * 100) / 100;
|
|
a[3] = math_floor(ARRAY_ACCESS(v, 3) * 100) / 100;
|
|
return a;
|
|
}
|
|
else if (starts_with(idname, "NodeSocketFloat")) {
|
|
let v: f32 = bl_handle_get_f(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueFloat"), "value");
|
|
let a: f32_array_t = f32_array_create(1);
|
|
a[0] = math_floor(v * 100) / 100;
|
|
return a;
|
|
}
|
|
else if (starts_with(idname, "NodeSocketInt")) {
|
|
let v: i32 = bl_handle_get_i(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueInt"), "value");
|
|
let a: f32_array_t = f32_array_create(1);
|
|
a[0] = v;
|
|
return a;
|
|
}
|
|
else if (starts_with(idname, "NodeSocketBoolean")) {
|
|
let v: bool = bl_handle_get_i(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueBoolean"), "value") > 0;
|
|
let a: f32_array_t = f32_array_create(1);
|
|
a[0] = v;
|
|
return a;
|
|
}
|
|
else if (starts_with(idname, "NodeSocketString")) {
|
|
let v: string = bl_handle_get(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueString"), "value");
|
|
return null;
|
|
}
|
|
return null;
|
|
}
|