503 lines
14 KiB
TypeScript
503 lines
14 KiB
TypeScript
|
|
let nodes_material_categories: string[] = [
|
|
_tr("Input"),
|
|
_tr("Texture"),
|
|
_tr("Color"),
|
|
_tr("Vector"),
|
|
_tr("Converter"),
|
|
// _tr("Neural"),
|
|
_tr("Group")
|
|
];
|
|
|
|
let nodes_material_input: ui_node_t[];
|
|
// let nodes_material_output: ui_node_t[];
|
|
let nodes_material_texture: ui_node_t[];
|
|
let nodes_material_color: ui_node_t[];
|
|
let nodes_material_vector: ui_node_t[];
|
|
let nodes_material_converter: ui_node_t[];
|
|
// let nodes_material_neural: ui_node_t[];
|
|
let nodes_material_group: ui_node_t[];
|
|
|
|
type node_list_t = ui_node_t[];
|
|
let nodes_material_list: node_list_t[];
|
|
let _nodes_material_nodes: ui_nodes_t;
|
|
let _nodes_material_node: ui_node_t;
|
|
let _nodes_material_sockets: ui_node_socket_t[];
|
|
|
|
function nodes_material_init() {
|
|
map_set(ui_nodes_custom_buttons, "nodes_material_vector_curves_button", nodes_material_vector_curves_button);
|
|
map_set(ui_nodes_custom_buttons, "nodes_material_color_ramp_button", nodes_material_color_ramp_button);
|
|
map_set(ui_nodes_custom_buttons, "nodes_material_new_group_button", nodes_material_new_group_button);
|
|
map_set(ui_nodes_custom_buttons, "nodes_material_group_input_button", nodes_material_group_input_button);
|
|
map_set(ui_nodes_custom_buttons, "nodes_material_group_output_button", nodes_material_group_output_button);
|
|
|
|
nodes_material_list_init();
|
|
}
|
|
|
|
function nodes_material_list_init() {
|
|
if (nodes_material_list != null) {
|
|
return;
|
|
}
|
|
|
|
nodes_material_input = [
|
|
attribute_node_def,
|
|
camera_data_node_def,
|
|
fresnel_node_def,
|
|
geometry_node_def,
|
|
layer_node_def,
|
|
layer_mask_node_def,
|
|
layer_weight_node_def,
|
|
material_node_def,
|
|
object_info_node_def,
|
|
picker_node_def,
|
|
rgb_node_def,
|
|
script_node_def,
|
|
shader_node_def,
|
|
tangent_node_def,
|
|
texture_coordinate_node_def,
|
|
uv_map_node_def,
|
|
value_node_def,
|
|
vertex_color_node_def,
|
|
wireframe_node_def,
|
|
];
|
|
|
|
// nodes_material_output = [
|
|
// material_output_node_def
|
|
// ];
|
|
|
|
nodes_material_texture = [
|
|
brick_texture_node_def,
|
|
checker_texture_node_def,
|
|
curvature_bake_node_def,
|
|
gradient_texture_node_def,
|
|
image_texture_node_def,
|
|
text_texture_node_def,
|
|
magic_texture_node_def,
|
|
musgrave_texture_node_def,
|
|
noise_texture_node_def,
|
|
voronoi_texture_node_def,
|
|
wave_texture_node_def
|
|
];
|
|
|
|
nodes_material_color = [
|
|
blur_node_def,
|
|
brightness_contrast_node_def,
|
|
gamma_node_def,
|
|
hue_saturation_value_node_def,
|
|
invert_node_def,
|
|
mix_color_node_def,
|
|
quantize_node_def,
|
|
replace_color_node_def,
|
|
warp_node_def
|
|
];
|
|
|
|
nodes_material_vector = [
|
|
bump_node_def,
|
|
mapping_node_def,
|
|
mix_normal_map_node_def,
|
|
normal_node_def,
|
|
normal_map_node_def,
|
|
vector_curves_node_def
|
|
];
|
|
|
|
nodes_material_converter = [
|
|
clamp_node_def,
|
|
color_ramp_node_def,
|
|
color_mask_node_def,
|
|
combine_hsv_node_def,
|
|
combine_rgb_node_def,
|
|
combine_xyz_node_def,
|
|
map_range_node_def,
|
|
math2_node_def,
|
|
rgb_to_bw_node_def,
|
|
separate_hsv_node_def,
|
|
separate_rgb_node_def,
|
|
separate_xyz_node_def,
|
|
vector_math2_node_def
|
|
];
|
|
|
|
// nodes_material_neural = [
|
|
// text_to_photo_node_def,
|
|
// inpaint_node_def,
|
|
// photo_to_pbr_node_def,
|
|
// tiling_node_def,
|
|
// upscale_node_def,
|
|
// variance_node_def
|
|
// ];
|
|
|
|
nodes_material_group = [
|
|
group_node_def
|
|
];
|
|
|
|
nodes_material_list = [
|
|
nodes_material_input,
|
|
nodes_material_texture,
|
|
nodes_material_color,
|
|
nodes_material_vector,
|
|
nodes_material_converter,
|
|
// nodes_material_neural,
|
|
nodes_material_group
|
|
];
|
|
}
|
|
|
|
function nodes_material_vector_curves_button(node_id: i32) {
|
|
let node: ui_node_t = ui_get_node(ui_nodes_get_canvas(true).nodes, node_id);
|
|
|
|
let but: ui_node_button_t = node.buttons[0];
|
|
let nhandle: ui_handle_t = ui_nest(ui_handle(__ID__), node.id);
|
|
ui_row3();
|
|
ui_radio(ui_nest(ui_nest(nhandle, 0), 1), 0, "X");
|
|
ui_radio(ui_nest(ui_nest(nhandle, 0), 1), 1, "Y");
|
|
ui_radio(ui_nest(ui_nest(nhandle, 0), 1), 2, "Z");
|
|
|
|
// Preview
|
|
let axis: i32 = ui_nest(ui_nest(nhandle, 0), 1).i;
|
|
let val: f32[] = but.default_value;
|
|
ui._y += UI_LINE_H() * 5;
|
|
|
|
let num: i32 = val[96 + axis];
|
|
|
|
if (num == 0) {
|
|
// Init
|
|
val[96 + 0] = 1;
|
|
val[96 + 1] = 1;
|
|
val[96 + 2] = 1;
|
|
}
|
|
|
|
// Edit
|
|
let row: f32[] = [1 / 5, 1 / 5, 3 / 5];
|
|
ui_row(row);
|
|
if (ui_button("+")) {
|
|
// TODO:
|
|
// val[axis * 32 + num * 2 + 0] = 0.0;
|
|
// val[axis * 32 + num * 2 + 1] = 0.0;
|
|
// num++;
|
|
// val[96 + axis] = num;
|
|
}
|
|
if (ui_button("-")) {
|
|
if (num > 1) {
|
|
num--;
|
|
val[96 + axis] = num;
|
|
}
|
|
}
|
|
|
|
let ihandle: ui_handle_t = ui_nest(ui_nest(ui_nest(nhandle, 0), 2), axis);
|
|
if (ihandle.init) {
|
|
ihandle.i = 0;
|
|
}
|
|
|
|
let i: i32 = math_floor(ui_slider(ihandle, "Index", 0, num - 1, false, 1, true, ui_align_t.LEFT));
|
|
if (i >= num || i < 0) {
|
|
ihandle.f = i = num - 1; // Stay in bounds
|
|
}
|
|
|
|
ui_row2();
|
|
ui_nest(ui_nest(nhandle, 0), 3).f = val[axis * 32 + i * 2 + 0];
|
|
ui_nest(ui_nest(nhandle, 0), 4).f = val[axis * 32 + i * 2 + 1];
|
|
|
|
let h1: ui_handle_t = ui_nest(ui_nest(nhandle, 0), 3);
|
|
if (h1.init) {
|
|
h1.f = 0.0;
|
|
}
|
|
let h2: ui_handle_t = ui_nest(ui_nest(nhandle, 0), 4);
|
|
if (h2.init) {
|
|
h2.f = 0.0;
|
|
}
|
|
val[axis * 32 + i * 2 + 0] = ui_slider(h1, "X", -1, 1, true, 100, true, ui_align_t.LEFT);
|
|
val[axis * 32 + i * 2 + 1] = ui_slider(h2, "Y", -1, 1, true, 100, true, ui_align_t.LEFT);
|
|
}
|
|
|
|
function nodes_material_color_ramp_button(node_id: i32) {
|
|
let nodes: ui_nodes_t = ui_nodes_get_nodes();
|
|
let node: ui_node_t = ui_get_node(ui_nodes_get_canvas(true).nodes, node_id);
|
|
|
|
let but: ui_node_button_t = node.buttons[0];
|
|
let nhandle: ui_handle_t = ui_nest(ui_handle(__ID__), node.id);
|
|
let nx: f32 = ui._x;
|
|
let ny: f32 = ui._y;
|
|
|
|
// Preview
|
|
let vals: f32[] = but.default_value; // [r, g, b, a, pos, r, g, b, a, pos, ..]
|
|
let sw: f32 = ui._w / UI_NODES_SCALE();
|
|
for (let i: i32 = 0; i < vals.length / 5; ++i) {
|
|
let pos: f32 = vals[i * 5 + 4];
|
|
let col: i32 = color_from_floats(vals[i * 5 + 0], vals[i * 5 + 1], vals[i * 5 + 2], 1.0);
|
|
ui_fill(pos * sw, 0, (1.0 - pos) * sw, UI_LINE_H() - 2 * UI_NODES_SCALE(), col);
|
|
}
|
|
ui._y += UI_LINE_H();
|
|
// Edit
|
|
let ihandle: ui_handle_t = ui_nest(ui_nest(nhandle, 0), 2);
|
|
let row: f32[] = [1 / 4, 1 / 4, 2 / 4];
|
|
ui_row(row);
|
|
if (ui_button("+")) {
|
|
// TODO:
|
|
// array_push(vals, vals[vals.length - 5]); // r
|
|
// array_push(vals, vals[vals.length - 5]); // g
|
|
// array_push(vals, vals[vals.length - 5]); // b
|
|
// array_push(vals, vals[vals.length - 5]); // a
|
|
// array_push(vals, 1.0); // pos
|
|
// ihandle.f += 1;
|
|
}
|
|
if (ui_button("-") && vals.length > 5) {
|
|
array_pop(vals);
|
|
array_pop(vals);
|
|
array_pop(vals);
|
|
array_pop(vals);
|
|
array_pop(vals);
|
|
ihandle.f -= 1;
|
|
}
|
|
|
|
let h: ui_handle_t = ui_nest(ui_nest(nhandle, 0), 1);
|
|
if (h.init) {
|
|
h.i = but.data[0];
|
|
}
|
|
let interpolate_combo: string[] = [tr("Linear"), tr("Constant")];
|
|
but.data[0] = ui_combo(h, interpolate_combo, tr("Interpolate"));
|
|
|
|
ui_row2();
|
|
let i: i32 = math_floor(ui_slider(ihandle, "Index", 0, (vals.length / 5) - 1, false, 1, true, ui_align_t.LEFT));
|
|
if (i >= (vals.length * 5) || i < 0) {
|
|
ihandle.f = i = (vals.length / 5) - 1; // Stay in bounds
|
|
}
|
|
|
|
ui_nest(ui_nest(nhandle, 0), 3).f = vals[i * 5 + 4];
|
|
vals[i * 5 + 4] = ui_slider(ui_nest(ui_nest(nhandle, 0), 3), "Pos", 0, 1, true, 100, true, ui_align_t.LEFT);
|
|
if (vals[i * 5 + 4] > 1.0) {
|
|
vals[i * 5 + 4] = 1.0; // Stay in bounds
|
|
}
|
|
else if (vals[i * 5 + 4] < 0.0) {
|
|
vals[i * 5 + 4] = 0.0;
|
|
}
|
|
|
|
let chandle: ui_handle_t = ui_nest(ui_nest(nhandle, 0), 4);
|
|
chandle.color = color_from_floats(vals[i * 5 + 0], vals[i * 5 + 1], vals[i * 5 + 2], 1.0);
|
|
if (ui_text("", ui_align_t.RIGHT, chandle.color) == ui_state_t.STARTED) {
|
|
let rx: f32 = nx + ui._w - ui_p(37);
|
|
let ry: f32 = ny - ui_p(5);
|
|
nodes._input_started = ui.input_started = false;
|
|
ui_nodes_rgba_popup(chandle, vals.buffer + i * 5, math_floor(rx), math_floor(ry + UI_ELEMENT_H()));
|
|
}
|
|
vals[i * 5 + 0] = color_get_rb(chandle.color) / 255;
|
|
vals[i * 5 + 1] = color_get_gb(chandle.color) / 255;
|
|
vals[i * 5 + 2] = color_get_bb(chandle.color) / 255;
|
|
}
|
|
|
|
function nodes_material_new_group_button(node_id: i32) {
|
|
let node: ui_node_t = ui_get_node(ui_nodes_get_canvas(true).nodes, node_id);
|
|
|
|
if (node.name == "New Group") {
|
|
for (let i: i32 = 1; i < 999; ++i) {
|
|
node.name = tr("Group") + " " + i;
|
|
|
|
let found: bool = false;
|
|
for (let i: i32 = 0; i < project_material_groups.length; ++i) {
|
|
let g: node_group_t = project_material_groups[i];
|
|
let cname: string = g.canvas.name;
|
|
if (cname == node.name) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
let canvas: ui_node_canvas_t = {
|
|
name: node.name,
|
|
nodes: [
|
|
{
|
|
id: 0,
|
|
name: _tr("Group Input"),
|
|
type: "GROUP_INPUT",
|
|
x: 50,
|
|
y: 200,
|
|
color: 0xff448c6d,
|
|
inputs: [],
|
|
outputs: [],
|
|
buttons: [
|
|
{
|
|
name: "nodes_material_group_input_button",
|
|
type: "CUSTOM",
|
|
height: 1
|
|
}
|
|
],
|
|
width: 0,
|
|
flags: 0
|
|
},
|
|
{
|
|
id: 1,
|
|
name: _tr("Group Output"),
|
|
type: "GROUP_OUTPUT",
|
|
x: 450,
|
|
y: 200,
|
|
color: 0xff448c6d,
|
|
inputs: [],
|
|
outputs: [],
|
|
buttons: [
|
|
{
|
|
name: "nodes_material_group_output_button",
|
|
type: "CUSTOM",
|
|
height: 1
|
|
}
|
|
],
|
|
width: 0,
|
|
flags: 0
|
|
}
|
|
],
|
|
links: []
|
|
};
|
|
let ng: node_group_t = {
|
|
canvas: canvas,
|
|
nodes: ui_nodes_create()
|
|
};
|
|
array_push(project_material_groups, ng);
|
|
}
|
|
|
|
let group: node_group_t = null;
|
|
for (let i: i32 = 0; i < project_material_groups.length; ++i) {
|
|
let g: node_group_t = project_material_groups[i];
|
|
let cname: string = g.canvas.name;
|
|
if (cname == node.name) {
|
|
group = g;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ui_button(tr("Nodes"))) {
|
|
array_push(ui_nodes_group_stack, group);
|
|
}
|
|
}
|
|
|
|
function nodes_material_group_input_button(node_id: i32) {
|
|
let nodes: ui_nodes_t = ui_nodes_get_nodes();
|
|
let node: ui_node_t = ui_get_node(ui_nodes_get_canvas(true).nodes, node_id);
|
|
nodes_material_add_socket_button(nodes, node, node.outputs);
|
|
}
|
|
|
|
function nodes_material_group_output_button(node_id: i32) {
|
|
let nodes: ui_nodes_t = ui_nodes_get_nodes();
|
|
let node: ui_node_t = ui_get_node(ui_nodes_get_canvas(true).nodes, node_id);
|
|
nodes_material_add_socket_button(nodes, node, node.inputs);
|
|
}
|
|
|
|
function nodes_material_add_socket_button(nodes: ui_nodes_t, node: ui_node_t, sockets: ui_node_socket_t[]) {
|
|
if (ui_button(tr("Add"))) {
|
|
_nodes_material_nodes = nodes;
|
|
_nodes_material_node = node;
|
|
_nodes_material_sockets = sockets;
|
|
ui_menu_draw(function () {
|
|
let nodes: ui_nodes_t = _nodes_material_nodes;
|
|
let node: ui_node_t = _nodes_material_node;
|
|
let sockets: ui_node_socket_t[] = _nodes_material_sockets;
|
|
|
|
let group_stack: node_group_t[] = ui_nodes_group_stack;
|
|
let c: ui_node_canvas_t = group_stack[group_stack.length - 1].canvas;
|
|
if (ui_menu_button(tr("RGBA"))) {
|
|
array_push(sockets, nodes_material_create_socket(nodes, node, null, "RGBA", c));
|
|
nodes_material_sync_sockets(node);
|
|
}
|
|
if (ui_menu_button(tr("Vector"))) {
|
|
array_push(sockets, nodes_material_create_socket(nodes, node, null, "VECTOR", c));
|
|
nodes_material_sync_sockets(node);
|
|
}
|
|
if (ui_menu_button(tr("Value"))) {
|
|
array_push(sockets, nodes_material_create_socket(nodes, node, null, "VALUE", c));
|
|
nodes_material_sync_sockets(node);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function nodes_material_sync_sockets(node: ui_node_t) {
|
|
let group_stack: node_group_t[] = ui_nodes_group_stack;
|
|
let c: ui_node_canvas_t = group_stack[group_stack.length - 1].canvas;
|
|
for (let i: i32 = 0; i < project_materials.length; ++i) {
|
|
let m: slot_material_t = project_materials[i];
|
|
nodes_material_sync_group_sockets(m.canvas, c.name, node);
|
|
}
|
|
for (let i: i32 = 0; i < project_material_groups.length; ++i) {
|
|
let g: node_group_t = project_material_groups[i];
|
|
nodes_material_sync_group_sockets(g.canvas, c.name, node);
|
|
}
|
|
}
|
|
|
|
function nodes_material_sync_group_sockets(canvas: ui_node_canvas_t, group_name: string, node: ui_node_t) {
|
|
for (let i: i32 = 0; i < canvas.nodes.length; ++i) {
|
|
let n: ui_node_t = canvas.nodes[i];
|
|
if (n.type == "GROUP" && n.name == group_name) {
|
|
let is_inputs: bool = node.name == "Group Input";
|
|
let old_sockets: ui_node_socket_t[] = is_inputs ? n.inputs : n.outputs;
|
|
let sockets: ui_node_socket_t[] = util_clone_canvas_sockets(is_inputs ? node.outputs : node.inputs);
|
|
if (is_inputs) {
|
|
n.inputs = sockets;
|
|
}
|
|
else {
|
|
n.outputs = sockets;
|
|
}
|
|
for (let i: i32 = 0; i < sockets.length; ++i) {
|
|
let s: ui_node_socket_t = sockets[i];
|
|
s.node_id = n.id;
|
|
}
|
|
let num_sockets: i32 = sockets.length < old_sockets.length ? sockets.length : old_sockets.length;
|
|
for (let i: i32 = 0; i < num_sockets; ++i) {
|
|
if (sockets[i].type == old_sockets[i].type) {
|
|
sockets[i].default_value = old_sockets[i].default_value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function nodes_material_get_socket_color(type: string): i32 {
|
|
return type == "RGBA" ? 0xffc7c729 : type == "VECTOR" ? 0xff6363c7 : 0xffa1a1a1;
|
|
}
|
|
|
|
function nodes_material_get_socket_default_value(type: string): f32_array_t {
|
|
return type == "RGBA" ? f32_array_create_xyzw(0.8, 0.8, 0.8, 1.0) : type == "VECTOR" ? f32_array_create_xyz(0.0, 0.0, 0.0) : f32_array_create_x(0.0);
|
|
}
|
|
|
|
function nodes_material_get_socket_name(type: string): string {
|
|
return type == "RGBA" ? _tr("Color") : type == "VECTOR" ? _tr("Vector") : _tr("Value");
|
|
}
|
|
|
|
function nodes_material_create_socket(nodes: ui_nodes_t, node: ui_node_t, name: string, type: string, canvas: ui_node_canvas_t, min: f32 = 0.0, max: f32 = 1.0, default_value: any = null): ui_node_socket_t {
|
|
let soc: ui_node_socket_t = {
|
|
id: ui_get_socket_id(canvas.nodes),
|
|
node_id: node.id,
|
|
name: name == null ? nodes_material_get_socket_name(type) : name,
|
|
type: type,
|
|
color: nodes_material_get_socket_color(type),
|
|
default_value: default_value == null ? nodes_material_get_socket_default_value(type) : default_value,
|
|
min: min,
|
|
max: max,
|
|
precision: 100
|
|
};
|
|
return soc;
|
|
}
|
|
|
|
function nodes_material_get_node_t(node_type: string): ui_node_t {
|
|
for (let i: i32 = 0; i < nodes_material_list.length; ++i) {
|
|
let c: ui_node_t[] = nodes_material_list[i];
|
|
for (let i: i32 = 0; i < c.length; ++i) {
|
|
let n: ui_node_t = c[i];
|
|
if (n.type == node_type) {
|
|
return n;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function nodes_material_create_node(node_type: string, group: node_group_t = null): ui_node_t {
|
|
let n: ui_node_t = nodes_material_get_node_t(node_type);
|
|
if (n == null) {
|
|
return null;
|
|
}
|
|
let canvas: ui_node_canvas_t = group != null ? group.canvas : ui_nodes_get_canvas();
|
|
let nodes: ui_nodes_t = group != null ? group.nodes : context_raw.material.nodes;
|
|
let node: ui_node_t = ui_nodes_make_node(n, nodes, canvas);
|
|
array_push(canvas.nodes, node);
|
|
return node;
|
|
}
|