diff --git a/paint/sources/make_blur.ts b/paint/sources/make_blur.ts index 0e1c4127..2b59bdc7 100644 --- a/paint/sources/make_blur.ts +++ b/paint/sources/make_blur.ts @@ -80,3 +80,35 @@ function make_blur_run(kong: node_shader_t) { } node_shader_write_frag(kong, "opacity *= constants.brush_opacity;"); } + +let str_get_smudge_tool_weight: string = "\ +fun get_smudge_tool_weight(i: int): float { \ + if (i == 0) { return 1.0 / 28.0; } \ + if (i == 1) { return 2.0 / 28.0; } \ + if (i == 2) { return 3.0 / 28.0; } \ + if (i == 3) { return 4.0 / 28.0; } \ + if (i == 4) { return 5.0 / 28.0; } \ + if (i == 5) { return 6.0 / 28.0; } \ + return 7.0 / 28.0; \ +} \ +"; + +let str_get_blur_tool_weight: string = "\ +fun get_blur_tool_weight(i: int): float { \ + if (i == 0) { return 0.034619 / 2.0; } \ + if (i == 1) { return 0.044859 / 2.0; } \ + if (i == 2) { return 0.055857 / 2.0; } \ + if (i == 3) { return 0.066833 / 2.0; } \ + if (i == 4) { return 0.076841 / 2.0; } \ + if (i == 5) { return 0.084894 / 2.0; } \ + if (i == 6) { return 0.090126 / 2.0; } \ + if (i == 7) { return 0.09194 / 2.0; } \ + if (i == 8) { return 0.090126 / 2.0; } \ + if (i == 9) { return 0.084894 / 2.0; } \ + if (i == 10) { return 0.076841 / 2.0; } \ + if (i == 11) { return 0.066833 / 2.0; } \ + if (i == 12) { return 0.055857 / 2.0; } \ + if (i == 13) { return 0.044859 / 2.0; } \ + return 0.034619 / 2.0; \ +} \ +"; diff --git a/paint/sources/make_colorid_picker.ts b/paint/sources/make_colorid_picker.ts index 0a851866..bc6bde45 100644 --- a/paint/sources/make_colorid_picker.ts +++ b/paint/sources/make_colorid_picker.ts @@ -40,3 +40,17 @@ function make_colorid_picker_run(kong: node_shader_t) { } } } + +let str_get_pos_nor_from_depth: string = "\ +fun get_pos_from_depth(uv: float2, invVP: float4x4): float3 { \ + var depth: float = sample_lod(gbufferD, sampler_linear, float2(uv.x, 1.0 - uv.y), 0.0).r; \ + var wpos: float4 = float4(uv * 2.0 - 1.0, depth, 1.0); \ + wpos = invVP * wpos; \ + return wpos.xyz / wpos.w; \ +} \ +fun get_nor_from_depth(p0: float3, uv: float2, invVP: float4x4, tex_step: float2): float3 { \ + var p1: float3 = get_pos_from_depth(uv + float2(tex_step.x * 4.0, 0.0), invVP); \ + var p2: float3 = get_pos_from_depth(uv + float2(0.0, tex_step.y * 4.0), invVP); \ + return normalize(cross(p2 - p0, p1 - p0)); \ +} \ +"; diff --git a/paint/sources/make_mesh.ts b/paint/sources/make_mesh.ts index 65cd9d1d..99ad730b 100644 --- a/paint/sources/make_mesh.ts +++ b/paint/sources/make_mesh.ts @@ -528,3 +528,117 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): node_shader_conte return con_mesh; } + +let str_cotangent_frame: string = "\ +fun cotangent_frame(n: float3, p: float3, tex_coord: float2): float3x3 { \ + var duv1: float2 = ddx2(tex_coord); \ + var duv2: float2 = ddy2(tex_coord); \ + var dp1: float3 = ddx3(p); \ + var dp2: float3 = ddy3(p); \ + var dp2perp: float3 = cross(dp2, n); \ + var dp1perp: float3 = cross(n, dp1); \ + var t: float3 = dp2perp * duv1.x + dp1perp * duv2.x; \ + var b: float3 = dp2perp * duv1.y + dp1perp * duv2.y; \ + var invmax: float = rsqrt(max(dot(t, t), dot(b, b))); \ + return float3x3(t * invmax, b * invmax, n); \ +} \ +"; + +let str_octahedron_wrap: string = "\ +fun octahedron_wrap(v: float2): float2 { \ + var a: float2; \ + if (v.x >= 0.0) { a.x = 1.0; } else { a.x = -1.0; } \ + if (v.y >= 0.0) { a.y = 1.0; } else { a.y = -1.0; } \ + var r: float2; \ + r.x = abs(v.y); \ + r.y = abs(v.x); \ + r.x = 1.0 - r.x; \ + r.y = 1.0 - r.y; \ + return r * a; \ +} \ +"; + +// let str_octahedron_wrap: string = "\ +// fun octahedron_wrap(v: float2): float2 { \ +// return (1.0 - abs(v.yx)) * (float2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0)); \ +// } \ +// "; + +let str_pack_float_int16: string = "\ +fun pack_f32_i16(f: float, i: uint): float { \ + return 0.062504762 * min(f, 0.9999) + 0.062519999 * float(i); \ +} \ +"; + +// let str_pack_float_int16: string = "\ +// fun pack_f32_i16(f: float, i: uint): float { \ +// var prec: float = float(1 << 16); \ +// var maxi: float = float(1 << 4); \ +// var prec_minus_one: float = prec - 1.0; \ +// var t1: float = ((prec / maxi) - 1.0) / prec_minus_one; \ +// var t2: float = (prec / maxi) / prec_minus_one; \ +// return t1 * f + t2 * float(i); \ +// } \ +// "; + +let str_sh_irradiance: string = "\ +fun sh_irradiance(nor: float3): float3 { \ + var c1: float = 0.429043; \ + var c2: float = 0.511664; \ + var c3: float = 0.743125; \ + var c4: float = 0.886227; \ + var c5: float = 0.247708; \ + var cl00: float3 = float3(constants.shirr0.x, constants.shirr0.y, constants.shirr0.z); \ + var cl1m1: float3 = float3(constants.shirr0.w, constants.shirr1.x, constants.shirr1.y); \ + var cl10: float3 = float3(constants.shirr1.z, constants.shirr1.w, constants.shirr2.x); \ + var cl11: float3 = float3(constants.shirr2.y, constants.shirr2.z, constants.shirr2.w); \ + var cl2m2: float3 = float3(constants.shirr3.x, constants.shirr3.y, constants.shirr3.z); \ + var cl2m1: float3 = float3(constants.shirr3.w, constants.shirr4.x, constants.shirr4.y); \ + var cl20: float3 = float3(constants.shirr4.z, constants.shirr4.w, constants.shirr5.x); \ + var cl21: float3 = float3(constants.shirr5.y, constants.shirr5.z, constants.shirr5.w); \ + var cl22: float3 = float3(constants.shirr6.x, constants.shirr6.y, constants.shirr6.z); \ + return ( \ + cl22 * c1 * (nor.y * nor.y - (-nor.z) * (-nor.z)) + \ + cl20 * c3 * nor.x * nor.x + \ + cl00 * c4 - \ + cl20 * c5 + \ + cl2m2 * 2.0 * c1 * nor.y * (-nor.z) + \ + cl21 * 2.0 * c1 * nor.y * nor.x + \ + cl2m1 * 2.0 * c1 * (-nor.z) * nor.x + \ + cl11 * 2.0 * c2 * nor.y + \ + cl1m1 * 2.0 * c2 * (-nor.z) + \ + cl10 * 2.0 * c2 * nor.x \ + ); \ +} \ +"; + +let str_envmap_equirect: string = "\ +fun envmap_equirect(normal: float3, angle: float): float2 { \ + var PI: float = 3.1415926535; \ + var PI2: float = PI * 2.0; \ + var phi: float = acos(normal.z); \ + var theta: float = atan2(-normal.y, normal.x) + PI + angle; \ + return float2(theta / PI2, phi / PI); \ +} \ +"; + +let str_envmap_sample: string = "\ +fun envmap_sample(lod: float, coord: float2): float3 { \ + if (lod == 0.0) { \ + return sample_lod(senvmap_radiance, sampler_linear, coord, 0.0).rgb; \ + } \ + if (lod == 1.0) { \ + return sample_lod(senvmap_radiance0, sampler_linear, coord, 0.0).rgb; \ + } \ + if (lod == 2.0) { \ + return sample_lod(senvmap_radiance1, sampler_linear, coord, 0.0).rgb; \ + } \ + if (lod == 3.0) { \ + return sample_lod(senvmap_radiance2, sampler_linear, coord, 0.0).rgb; \ + } \ + if (lod == 4.0) { \ + return sample_lod(senvmap_radiance3, sampler_linear, coord, 0.0).rgb; \ + } \ + return sample_lod(senvmap_radiance4, sampler_linear, coord, 0.0).rgb; \ +} \ +"; diff --git a/paint/sources/material_nodes/attribute_node.ts b/paint/sources/material_nodes/attribute_node.ts index ff6474f1..324c0f72 100644 --- a/paint/sources/material_nodes/attribute_node.ts +++ b/paint/sources/material_nodes/attribute_node.ts @@ -1,4 +1,25 @@ +function attribute_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + if (socket == node.outputs[0]) { // Color + if (parser_material_kong.context.allow_vcols) { + node_shader_context_add_elem(parser_material_kong.context, "col", "short4norm"); // Vcols only for now + return "input.vcolor"; + } + else { + return("float3(0.0, 0.0, 0.0)"); + } + } + else { // Vector + node_shader_context_add_elem(parser_material_kong.context, "tex", "short2norm"); // UVMaps only for now + return "float3(tex_coord.x, tex_coord.y, 0.0)"; + } +} + +function attribute_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_constant(parser_material_kong, "time: float", "_time"); + return "constants.time"; +} + let attribute_node_def: ui_node_t = { id: 0, name: _tr("Attribute"), diff --git a/paint/sources/material_nodes/blur_node.ts b/paint/sources/material_nodes/blur_node.ts index efe29017..1fa0f415 100644 --- a/paint/sources/material_nodes/blur_node.ts +++ b/paint/sources/material_nodes/blur_node.ts @@ -1,4 +1,27 @@ +function blur_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + if (parser_material_blur_passthrough) { + return parser_material_parse_vector_input(node.inputs[0]); + } + let strength: string = parser_material_parse_value_input(node.inputs[1]); + if (strength == "0.0") { + return "float3(0.0, 0.0, 0.0)"; + } + let steps: string = "(" + strength + " * 10.0 + 1.0)"; + let tex_name: string = "texblur_" + parser_material_node_name(node); + node_shader_add_texture(parser_material_kong, "" + tex_name, "_" + tex_name); + node_shader_add_constant(parser_material_kong, "" + tex_name + "_size: float2", "_size(_" + tex_name + ")"); + let store: string = parser_material_store_var_name(node); + parser_material_write(parser_material_kong, "var " + store + "_res: float3 = float3(0.0, 0.0, 0.0);"); + parser_material_write(parser_material_kong, "for (var i: int = 0; i <= int(" + steps + " * 2.0); i += 1) {"); + parser_material_write(parser_material_kong, "for (var j: int = 0; j <= int(" + steps + " * 2.0); j += 1) {"); + parser_material_write(parser_material_kong, store + "_res += sample(" + tex_name + ", sampler_linear, tex_coord + float2(float(i) - " + steps + ", float(j) - " + steps + ") / constants." + tex_name + "_size).rgb;"); + parser_material_write(parser_material_kong, "}"); + parser_material_write(parser_material_kong, "}"); + parser_material_write(parser_material_kong, store + "_res = " + store + "_res / (" + steps + " * 2.0 + 1.0) * (" + steps + " * 2.0 + 1.0);"); + return store + "_res"; +} + let blur_node_def: ui_node_t = { id: 0, name: _tr("Blur"), diff --git a/paint/sources/material_nodes/brick_texture_node.ts b/paint/sources/material_nodes/brick_texture_node.ts index 112e7268..3a3c9785 100644 --- a/paint/sources/material_nodes/brick_texture_node.ts +++ b/paint/sources/material_nodes/brick_texture_node.ts @@ -1,4 +1,53 @@ +let str_tex_brick: string = "\ +fun tex_brick_noise(n: int): float { \ + var nn: int; \ + n = (n >> 13) ^ n; \ + /*nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;*/ \ + nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 2147483647; \ + return 0.5 * float(nn) / 1073741824.0; \ +} \ +fun tex_brick(p: float3, c1: float3, c2: float3, c3: float3): float3 { \ + var brick_size: float3 = float3(0.9, 0.49, 0.49); \ + var mortar_size: float3 = float3(0.05, 0.1, 0.1); \ + p /= brick_size / 2.0; \ + if (frac(p.y * 0.5) > 0.5) { p.x += 0.5; } \ + var col: float = floor(p.x / (brick_size.x + (mortar_size.x * 2.0))); \ + var row: float = p.y; \ + p = frac3(p); \ + var b: float3 = step3(p, 1.0 - mortar_size); \ + /*var tint: float = min(max(tex_brick_noise((int(col) << 16) + (int(row) & 0xffff)), 0.0), 1.0);*/ \ + var tint: float = min(max(tex_brick_noise((int(col) << 16) + (int(row) & 65535)), 0.0), 1.0); \ + return lerp3(c3, lerp3(c1, c2, tint), b.x * b.y * b.z); \ +} \ +fun tex_brick_f(p: float3): float { \ + p /= float3(0.9, 0.49, 0.49) / 2.0; \ + if (frac(p.y * 0.5) > 0.5) { p.x += 0.5; } \ + p = frac3(p); \ + var b: float3 = step3(p, float3(0.95, 0.9, 0.9)); \ + return lerp(1.0, 0.0, b.x * b.y * b.z); \ +} \ +"; + +function brick_texture_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_brick); + let co: string = parser_material_get_coord(node); + let col1: string = parser_material_parse_vector_input(node.inputs[1]); + let col2: string = parser_material_parse_vector_input(node.inputs[2]); + let col3: string = parser_material_parse_vector_input(node.inputs[3]); + let scale: string = parser_material_parse_value_input(node.inputs[4]); + let res: string = "tex_brick(" + co + " * " + scale + ", " + col1 + ", " + col2 + ", " + col3 + ")"; + return res; +} + +function brick_texture_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_brick); + let co: string = parser_material_get_coord(node); + let scale: string = parser_material_parse_value_input(node.inputs[4]); + let res: string = "tex_brick_f(" + co + " * " + scale + ")"; + return res; +} + let brick_texture_node_def: ui_node_t = { id: 0, name: _tr("Brick Texture"), diff --git a/paint/sources/material_nodes/brightness_contrast_node.ts b/paint/sources/material_nodes/brightness_contrast_node.ts index a45e57e1..cf4506e8 100644 --- a/paint/sources/material_nodes/brightness_contrast_node.ts +++ b/paint/sources/material_nodes/brightness_contrast_node.ts @@ -1,4 +1,20 @@ +let str_brightcontrast: string = "\ +fun brightcontrast(col: float3, bright: float, contr: float): float3 { \ + var a: float = 1.0 + contr; \ + var b: float = bright - contr * 0.5; \ + return max3(a * col + b, float3(0.0, 0.0, 0.0)); \ +} \ +"; + +function brightness_contrast_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let out_col: string = parser_material_parse_vector_input(node.inputs[0]); + let bright: string = parser_material_parse_value_input(node.inputs[1]); + let contr: string = parser_material_parse_value_input(node.inputs[2]); + node_shader_add_function(parser_material_kong, str_brightcontrast); + return "brightcontrast(" + out_col + ", " + bright + ", " + contr + ")"; +} + let brightness_contrast_node_def: ui_node_t = { id: 0, name: _tr("Brightness/Contrast"), diff --git a/paint/sources/material_nodes/bump_node.ts b/paint/sources/material_nodes/bump_node.ts index 699b62b8..525b3a82 100644 --- a/paint/sources/material_nodes/bump_node.ts +++ b/paint/sources/material_nodes/bump_node.ts @@ -1,4 +1,15 @@ +function bump_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let strength: string = parser_material_parse_value_input(node.inputs[0]); + // let distance: string = parse_value_input(node.inputs[1]); + let height: string = parser_material_parse_value_input(node.inputs[2]); + let nor: string = parser_material_parse_vector_input(node.inputs[3]); + let sample_bump_res: string = parser_material_store_var_name(node) + "_bump"; + parser_material_write(parser_material_kong, "var " + sample_bump_res + "_x: float = ddx(float(" + height + ")) * (" + strength + ") * 16.0;"); + parser_material_write(parser_material_kong, "var " + sample_bump_res + "_y: float = ddy(float(" + height + ")) * (" + strength + ") * 16.0;"); + return "(normalize(float3(" + sample_bump_res + "_x, " + sample_bump_res + "_y, 1.0) + " + nor + ") * float3(0.5, 0.5, 0.5) + float3(0.5, 0.5, 0.5))"; +} + let bump_node_def: ui_node_t = { id: 0, name: _tr("Bump"), diff --git a/paint/sources/material_nodes/camera_data_node.ts b/paint/sources/material_nodes/camera_data_node.ts index cd1b05db..5e59b50c 100644 --- a/paint/sources/material_nodes/camera_data_node.ts +++ b/paint/sources/material_nodes/camera_data_node.ts @@ -1,4 +1,22 @@ +function camera_data_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + parser_material_kong.frag_vvec_cam = true; + return "vvec_cam"; +} + +function camera_data_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + if (socket == node.outputs[1]) { // View Z Depth + node_shader_add_constant(parser_material_kong, "camera_proj: float2", "_camera_plane_proj"); + parser_material_kong.frag_wvpposition = true; + return "(constants.camera_proj.y / ((input.wvpposition.z / input.wvpposition.w) - constants.camera_proj.x))"; + } + else { // View Distance + node_shader_add_constant(parser_material_kong, "eye: float3", "_camera_pos"); + parser_material_kong.frag_wposition = true; + return "distance(constants.eye, input.wposition)"; + } +} + let camera_data_node_def: ui_node_t = { id: 0, name: _tr("Camera Data"), diff --git a/paint/sources/material_nodes/checker_texture_node.ts b/paint/sources/material_nodes/checker_texture_node.ts index 980e36cf..d3eb6c4b 100644 --- a/paint/sources/material_nodes/checker_texture_node.ts +++ b/paint/sources/material_nodes/checker_texture_node.ts @@ -1,4 +1,51 @@ +let str_tex_checker: string = "\ +fun tex_checker(co: float3, col1: float3, col2: float3, scale: float): float3 { \ + /* Prevent precision issues on unit coordinates */ \ + var p: float3 = (co + 0.000001 * 0.999999) * scale; \ + var xi: float = abs(floor(p.x)); \ + var yi: float = abs(floor(p.y)); \ + var zi: float = abs(floor(p.z)); \ + /* var check: bool = (xi % 2.0 == yi % 2.0) == zi % 2.0;*/ \ + var checka: int = 0; \ + var checkb: int = 0; \ + if (xi % 2.0 == yi % 2.0) { checka = 1; } \ + if (zi % 2.0 != 0.0) { checkb = 1; } \ + if (checka == checkb) { return col1; } return col2; \ +} \ +fun tex_checker_f(co: float3, scale: float): float { \ + var p: float3 = (co + 0.000001 * 0.999999) * scale; \ + var xi: float = abs(floor(p.x)); \ + var yi: float = abs(floor(p.y)); \ + var zi: float = abs(floor(p.z)); \ + /*return float((xi % 2.0 == yi % 2.0) == zi % 2.0);*/ \ + var checka: int = 0; \ + var checkb: int = 0; \ + if (xi % 2.0 == yi % 2.0) { checka = 1; } \ + if (zi % 2.0 != 0.0) { checkb = 1; } \ + if (checka == checkb) { return 1.0; } return 0.0; \ + \ +} \ +"; + +function checker_texture_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_checker); + let co: string = parser_material_get_coord(node); + let col1: string = parser_material_parse_vector_input(node.inputs[1]); + let col2: string = parser_material_parse_vector_input(node.inputs[2]); + let scale: string = parser_material_parse_value_input(node.inputs[3]); + let res: string = "tex_checker(" + co + ", " + col1 + ", " + col2 + ", " + scale + ")"; + return res; +} + +function checker_texture_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_checker); + let co: string = parser_material_get_coord(node); + let scale: string = parser_material_parse_value_input(node.inputs[3]); + let res: string = "tex_checker_f(" + co + ", " + scale + ")"; + return res; +} + let checker_texture_node_def: ui_node_t = { id: 0, name: _tr("Checker Texture"), diff --git a/paint/sources/material_nodes/clamp_node.ts b/paint/sources/material_nodes/clamp_node.ts index ce442e33..74076aff 100644 --- a/paint/sources/material_nodes/clamp_node.ts +++ b/paint/sources/material_nodes/clamp_node.ts @@ -1,4 +1,19 @@ +function clamp_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let val: string = parser_material_parse_value_input(node.inputs[0]); + let min: string = parser_material_parse_value_input(node.inputs[1]); + let max: string = parser_material_parse_value_input(node.inputs[2]); + let but: ui_node_button_t = node.buttons[0]; //operation; + let op: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); + op = string_replace_all(op, " ", "_"); + if (op == "MIN_MAX") { + return "(clamp(" + val + ", " + min + ", " + max + "))"; + } + else if (op == "RANGE") { + return "(clamp(" + val + ", min(" + min + ", " + max + "), max(" + min + ", " + max + ")))"; + } +} + let clamp_node_def: ui_node_t = { id: 0, name: _tr("Clamp"), diff --git a/paint/sources/material_nodes/color_mask_node.ts b/paint/sources/material_nodes/color_mask_node.ts index 3354e8fa..dddd5235 100644 --- a/paint/sources/material_nodes/color_mask_node.ts +++ b/paint/sources/material_nodes/color_mask_node.ts @@ -1,4 +1,12 @@ +function color_mask_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let input_color: string = parser_material_parse_vector_input(node.inputs[0]); + let mask_color: string = parser_material_parse_vector_input(node.inputs[1]); + let radius: string = parser_material_parse_value_input(node.inputs[2]); + let fuzziness: string = parser_material_parse_value_input(node.inputs[3]); + return "clamp(1.0 - (distance(" + input_color + ", " + mask_color + ") - " + radius + ") / max(" + fuzziness + ", " + parser_material_eps + "), 0.0, 1.0)"; +} + let color_mask_node_def: ui_node_t = { id: 0, name: _tr("Color Mask"), diff --git a/paint/sources/material_nodes/color_ramp_node.ts b/paint/sources/material_nodes/color_ramp_node.ts index 0dc70e21..fe250345 100644 --- a/paint/sources/material_nodes/color_ramp_node.ts +++ b/paint/sources/material_nodes/color_ramp_node.ts @@ -1,4 +1,54 @@ +function color_ramp_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let fac: string = parser_material_parse_value_input(node.inputs[0]); + let data0: i32 = node.buttons[0].data[0]; + let interp: string = data0 == 0 ? "LINEAR" : "CONSTANT"; + let elems: f32[] = node.buttons[0].default_value; + let len: i32 = elems.length / 5; + if (len == 1) { + return parser_material_vec3(elems); + } + // Write cols array + let cols_var: string = parser_material_node_name(node) + "_cols"; + parser_material_write(parser_material_kong, "var " + cols_var + ": float3[" + len + "];"); // TODO: Make const + for (let i: i32 = 0; i < len; ++i) { + let tmp: f32[] = []; + array_push(tmp, elems[i * 5]); + array_push(tmp, elems[i * 5 + 1]); + array_push(tmp, elems[i * 5 + 2]); + parser_material_write(parser_material_kong, cols_var + "[" + i + "] = " + parser_material_vec3(tmp) + ";"); + } + // Get index + let fac_var: string = parser_material_node_name(node) + "_fac"; + parser_material_write(parser_material_kong, "var " + fac_var + ": float = " + fac + ";"); + let index: string = "0"; + for (let i: i32 = 1; i < len; ++i) { + let e: f32 = elems[i * 5 + 4]; + index += " + (" + fac_var + " > " + e + " ? 1 : 0)"; + } + // Write index + let index_var: string = parser_material_node_name(node) + "_i"; + parser_material_write(parser_material_kong, "var " + index_var + ": int = " + index + ";"); + if (interp == "CONSTANT") { + return cols_var + "[" + index_var + "]"; + } + else { // Linear + // Write facs array + let facs_var: string = parser_material_node_name(node) + "_facs"; + parser_material_write(parser_material_kong, "var " + facs_var + ": float[" + len + "];"); // TODO: Make const + for (let i: i32 = 0; i < len; ++i) { + let e: f32 = elems[i * 5 + 4]; + parser_material_write(parser_material_kong, facs_var + "[" + i + "] = " + e + ";"); + } + // Mix color + // float f = (pos - start) * (1.0 / (finish - start)) + // TODO: index_var + 1 out of bounds + return "lerp3(" + cols_var + "[" + index_var + "], " + cols_var + "[" + index_var + " + 1], (" + + fac_var + " - " + facs_var + "[" + index_var + "]) * (1.0 / (" + facs_var + "[" + index_var + " + 1] - " + + facs_var + "[" + index_var + "]) ))"; + } +} + let color_ramp_node_def: ui_node_t = { id: 0, name: _tr("Color Ramp"), diff --git a/paint/sources/material_nodes/combine_hsv_node.ts b/paint/sources/material_nodes/combine_hsv_node.ts index 7b1f2dd6..85033456 100644 --- a/paint/sources/material_nodes/combine_hsv_node.ts +++ b/paint/sources/material_nodes/combine_hsv_node.ts @@ -1,4 +1,12 @@ +function combine_hsv_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_hue_sat); + let h: string = parser_material_parse_value_input(node.inputs[0]); + let s: string = parser_material_parse_value_input(node.inputs[1]); + let v: string = parser_material_parse_value_input(node.inputs[2]); + return "hsv_to_rgb(float3(" + h + ", " + s + ", " + v + "))"; +} + let combine_hsv_node_def: ui_node_t = { id: 0, name: _tr("Combine HSV"), diff --git a/paint/sources/material_nodes/combine_rgb_node.ts b/paint/sources/material_nodes/combine_rgb_node.ts index c39bfde5..b2fe812f 100644 --- a/paint/sources/material_nodes/combine_rgb_node.ts +++ b/paint/sources/material_nodes/combine_rgb_node.ts @@ -1,4 +1,11 @@ +function combine_rgb_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let r: string = parser_material_parse_value_input(node.inputs[0]); + let g: string = parser_material_parse_value_input(node.inputs[1]); + let b: string = parser_material_parse_value_input(node.inputs[2]); + return "float3(" + r + ", " + g + ", " + b + ")"; +} + let combine_rgb_node_def: ui_node_t = { id: 0, name: _tr("Combine RGB"), diff --git a/paint/sources/material_nodes/combine_xyz_node.ts b/paint/sources/material_nodes/combine_xyz_node.ts index f27f7a55..572aa736 100644 --- a/paint/sources/material_nodes/combine_xyz_node.ts +++ b/paint/sources/material_nodes/combine_xyz_node.ts @@ -1,4 +1,11 @@ +function combine_xyz_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let x: string = parser_material_parse_value_input(node.inputs[0]); + let y: string = parser_material_parse_value_input(node.inputs[1]); + let z: string = parser_material_parse_value_input(node.inputs[2]); + return "float3(" + x + ", " + y + ", " + z + ")"; +} + let combine_xyz_node_def: ui_node_t = { id: 0, name: _tr("Combine XYZ"), diff --git a/paint/sources/material_nodes/curvature_bake_node.ts b/paint/sources/material_nodes/curvature_bake_node.ts index 3a22032b..d27583ad 100644 --- a/paint/sources/material_nodes/curvature_bake_node.ts +++ b/paint/sources/material_nodes/curvature_bake_node.ts @@ -1,4 +1,22 @@ +let parser_material_bake_passthrough_strength: string = "0.0"; +let parser_material_bake_passthrough_radius: string = "0.0"; +let parser_material_bake_passthrough_offset: string = "0.0"; + +function curvature_bake_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + if (parser_material_bake_passthrough) { + parser_material_bake_passthrough_strength = parser_material_parse_value_input(node.inputs[0]); + parser_material_bake_passthrough_radius = parser_material_parse_value_input(node.inputs[1]); + parser_material_bake_passthrough_offset = parser_material_parse_value_input(node.inputs[2]); + return "0.0"; + } + let tex_name: string = "texbake_" + parser_material_node_name(node); + node_shader_add_texture(parser_material_kong, "" + tex_name, "_" + tex_name); + let store: string = parser_material_store_var_name(node); + parser_material_write(parser_material_kong, "var " + store + "_res: float = sample(" + tex_name + ", sampler_linear, tex_coord).r;"); + return store + "_res"; +} + let curvature_bake_node_def: ui_node_t = { id: 0, name: _tr("Curvature Bake"), diff --git a/paint/sources/material_nodes/fresnel_node_def.ts b/paint/sources/material_nodes/fresnel_node.ts similarity index 81% rename from paint/sources/material_nodes/fresnel_node_def.ts rename to paint/sources/material_nodes/fresnel_node.ts index 7ed8225c..699f89e8 100644 --- a/paint/sources/material_nodes/fresnel_node_def.ts +++ b/paint/sources/material_nodes/fresnel_node.ts @@ -1,4 +1,10 @@ +function fresnel_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let ior: string = parser_material_parse_value_input(node.inputs[0]); + parser_material_kong.frag_dotnv = true; + return "pow(1.0 - dotnv, 7.25 / " + ior + ")"; +} + let fresnel_node_def: ui_node_t = { id: 0, name: _tr("Fresnel"), @@ -49,4 +55,4 @@ let fresnel_node_def: ui_node_t = { buttons: [], width: 0, flags: 0 -}; \ No newline at end of file +}; diff --git a/paint/sources/material_nodes/gamma_node.ts b/paint/sources/material_nodes/gamma_node.ts index 92bb67e4..f8c5dfd0 100644 --- a/paint/sources/material_nodes/gamma_node.ts +++ b/paint/sources/material_nodes/gamma_node.ts @@ -1,4 +1,10 @@ +function gamma_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let out_col: string = parser_material_parse_vector_input(node.inputs[0]); + let gamma: string = parser_material_parse_value_input(node.inputs[1]); + return "pow3(" + out_col + ", " + parser_material_to_vec3(gamma) + ")"; +} + let gamma_node_def: ui_node_t = { id: 0, name: _tr("Gamma"), diff --git a/paint/sources/material_nodes/geometry_node.ts b/paint/sources/material_nodes/geometry_node.ts index 53958f72..24b5726f 100644 --- a/paint/sources/material_nodes/geometry_node.ts +++ b/paint/sources/material_nodes/geometry_node.ts @@ -1,4 +1,53 @@ +function geometry_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + if (socket == node.outputs[0]) { // Position + parser_material_kong.frag_wposition = true; + return "input.wposition"; + } + else if (socket == node.outputs[1]) { // Normal + parser_material_kong.frag_n = true; + return "n"; + } + else if (socket == node.outputs[2]) { // Tangent + parser_material_kong.frag_wtangent = true; + return "input.wtangent"; + } + else if (socket == node.outputs[3]) { // True Normal + parser_material_kong.frag_n = true; + return "n"; + } + else if (socket == node.outputs[4]) { // Incoming + parser_material_kong.frag_vvec = true; + return "vvec"; + } + else if (socket == node.outputs[5]) { // Parametric + parser_material_kong.frag_mposition = true; + return "input.mposition"; + } +} + +function geometry_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + if (socket == node.outputs[6]) { // Backfacing + return "0.0"; // SV_IsFrontFace + // return "(1.0 - float(gl_FrontFacing))"; + } + else if (socket == node.outputs[7]) { // Pointiness + let strength: f32 = 1.0; + let radius: f32 = 1.0; + let offset: f32 = 0.0; + let store: string = parser_material_store_var_name(node); + parser_material_kong.frag_n = true; + parser_material_write(parser_material_kong, "var " + store + "_dx: float3 = ddx3(n);"); + parser_material_write(parser_material_kong, "var " + store + "_dy: float3 = ddy3(n);"); + parser_material_write(parser_material_kong, "var " + store + "_curvature: float = max(dot(" + store + "_dx, " + store + "_dx), dot(" + store + "_dy, " + store + "_dy));"); + parser_material_write(parser_material_kong, store + "_curvature = clamp(pow(" + store + "_curvature, (1.0 / " + radius + ") * 0.25) * " + strength + " * 2.0 + " + offset + " / 10.0, 0.0, 1.0);"); + return store + "_curvature"; + } + else if (socket == node.outputs[8]) { // Random Per Island + return "0.0"; + } +} + let geometry_node_def: ui_node_t = { id: 0, name: _tr("Geometry"), @@ -120,4 +169,4 @@ let geometry_node_def: ui_node_t = { buttons: [], width: 0, flags: 0 -}; \ No newline at end of file +}; diff --git a/paint/sources/material_nodes/gradient_texture_node.ts b/paint/sources/material_nodes/gradient_texture_node.ts index f80e5fc5..164de640 100644 --- a/paint/sources/material_nodes/gradient_texture_node.ts +++ b/paint/sources/material_nodes/gradient_texture_node.ts @@ -1,4 +1,48 @@ +function parser_material_get_gradient(grad: string, co: string): string { + if (grad == "LINEAR") { + return co + ".x"; + } + else if (grad == "QUADRATIC") { + return "0.0"; + } + else if (grad == "EASING") { + return "0.0"; + } + else if (grad == "DIAGONAL") { + return "(" + co + ".x + " + co + ".y) * 0.5"; + } + else if (grad == "RADIAL") { + return "atan2(" + co + ".x, " + co + ".y) / (3.141592 * 2.0) + 0.5"; + } + else if (grad == "QUADRATIC_SPHERE") { + return "0.0"; + } + else { // "SPHERICAL" + return "max(1.0 - sqrt(" + co + ".x * " + co + ".x + " + co + ".y * " + co + ".y + " + co + ".z * " + co + ".z), 0.0)"; + } +} + +function gradient_texture_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let co: string = parser_material_get_coord(node); + let but: ui_node_button_t = node.buttons[0]; //gradient_type; + let grad: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); + grad = string_replace_all(grad, " ", "_"); + let f: string = parser_material_get_gradient(grad, co); + let res: string = parser_material_to_vec3("clamp(" + f + ", 0.0, 1.0)"); + return res; +} + +function gradient_texture_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let co: string = parser_material_get_coord(node); + let but: ui_node_button_t = node.buttons[0]; //gradient_type; + let grad: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); + grad = string_replace_all(grad, " ", "_"); + let f: string = parser_material_get_gradient(grad, co); + let res: string = "(clamp(" + f + ", 0.0, 1.0))"; + return res; +} + let gradient_texture_node_def: ui_node_t = { id: 0, name: _tr("Gradient Texture"), diff --git a/paint/sources/material_nodes/group_node.ts b/paint/sources/material_nodes/group_node.ts index f4eaf686..13b74f8f 100644 --- a/paint/sources/material_nodes/group_node.ts +++ b/paint/sources/material_nodes/group_node.ts @@ -1,4 +1,12 @@ +function group_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + return parser_material_parse_group(node, socket); +} + +function group_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + return parser_material_parse_group(node, socket); +} + let group_node_def: ui_node_t = { id: 0, name: _tr("New Group"), diff --git a/paint/sources/material_nodes/hue_saturation_value_node.ts b/paint/sources/material_nodes/hue_saturation_value_node.ts index 076cbf4a..735be94f 100644 --- a/paint/sources/material_nodes/hue_saturation_value_node.ts +++ b/paint/sources/material_nodes/hue_saturation_value_node.ts @@ -1,4 +1,37 @@ +let str_hue_sat: string = "\ +fun hsv_to_rgb(c: float3): float3 { \ + var K: float4 = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); \ + var p: float3 = abs3(frac3(c.xxx + K.xyz) * 6.0 - K.www); \ + return lerp3(K.xxx, clamp3(p - K.xxx, float3(0.0, 0.0, 0.0), float3(1.0, 1.0, 1.0)), c.y) * c.z; \ +} \ +fun rgb_to_hsv(c: float3): float3 { \ + var K: float4 = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); \ + var p: float4 = lerp4(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g)); \ + var q: float4 = lerp4(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r)); \ + var d: float = q.x - min(q.w, q.y); \ + var e: float = 0.0000000001; \ + return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); \ +} \ +fun hue_sat(col: float3, shift: float4): float3 { \ + var hsv: float3 = rgb_to_hsv(col); \ + hsv.x += shift.x; \ + hsv.y *= shift.y; \ + hsv.z *= shift.z; \ + return lerp3(hsv_to_rgb(hsv), col, shift.w); \ +} \ +"; + +function hue_saturation_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_hue_sat); + let hue: string = parser_material_parse_value_input(node.inputs[0]); + let sat: string = parser_material_parse_value_input(node.inputs[1]); + let val: string = parser_material_parse_value_input(node.inputs[2]); + let fac: string = parser_material_parse_value_input(node.inputs[3]); + let col: string = parser_material_parse_vector_input(node.inputs[4]); + return "hue_sat(" + col + ", float4(" + hue + " - 0.5, " + sat + ", " + val + ", 1.0 - " + fac + "))"; +} + let hue_saturation_value_node_def: ui_node_t = { id: 0, name: _tr("Hue/Saturation/Value"), diff --git a/paint/sources/material_nodes/image_texture_node.ts b/paint/sources/material_nodes/image_texture_node.ts index b1b115aa..c844b30c 100644 --- a/paint/sources/material_nodes/image_texture_node.ts +++ b/paint/sources/material_nodes/image_texture_node.ts @@ -1,4 +1,118 @@ +enum color_space_t { + AUTO, // sRGB for base color, otherwise linear + LINEAR, + SRGB, + DIRECTX_NORMAL_MAP, +} + +function parser_material_texture_store(node: ui_node_t, tex: bind_tex_t, tex_name: string, color_space: i32): string { + array_push(parser_material_matcon.bind_textures, tex); + node_shader_context_add_elem(parser_material_kong.context, "tex", "short2norm"); + node_shader_add_texture(parser_material_kong, "" + tex_name); + let uv_name: string = ""; + if (parser_material_get_input_link(node.inputs[0]) != null) { + uv_name = parser_material_parse_vector_input(node.inputs[0]); + } + else { + uv_name = parser_material_tex_coord; + } + let tex_store: string = parser_material_store_var_name(node); + + if (parser_material_sample_keep_aspect) { + node_shader_add_constant(parser_material_kong, tex_name + "_size: float2", "_size(" + tex_name + ")"); + parser_material_write(parser_material_kong, "var " + tex_store + "_size: float2 = constants." + tex_name + "_size;"); + parser_material_write(parser_material_kong, "var " + tex_store + "_ax: float = " + tex_store + "_size.x / " + tex_store + "_size.y;"); + parser_material_write(parser_material_kong, "var " + tex_store + "_ay: float = " + tex_store + "_size.y / " + tex_store + "_size.x;"); + parser_material_write(parser_material_kong, "var " + tex_store + "_uv: float2 = ((" + uv_name + ".xy / float(" + parser_material_sample_uv_scale + ") - float2(0.5, 0.5)) * float2(max(" + tex_store + "_ay, 1.0), max(" + tex_store + "_ax, 1.0))) + float2(0.5, 0.5);"); + parser_material_write(parser_material_kong, "if (" + tex_store + "_uv.x < 0.0 || " + tex_store + "_uv.y < 0.0 || " + tex_store + "_uv.x > 1.0 || " + tex_store + "_uv.y > 1.0) { discard; }"); + parser_material_write(parser_material_kong, tex_store + "_uv = " + tex_store + "_uv * float(" + parser_material_sample_uv_scale + ");"); + uv_name = tex_store + "_uv"; + } + + if (parser_material_triplanar) { + parser_material_write(parser_material_kong, "var " + tex_store + ": float4 = float4(0.0, 0.0, 0.0, 0.0);"); + parser_material_write(parser_material_kong, "if (tex_coord_blend.x > 0.0) {" + tex_store + " += sample(" + tex_name + ", sampler_linear, " + uv_name + ".xy) * tex_coord_blend.x; }"); + parser_material_write(parser_material_kong, "if (tex_coord_blend.y > 0.0) {" + tex_store + " += sample(" + tex_name + ", sampler_linear, " + uv_name + "1.xy) * tex_coord_blend.y; }"); + parser_material_write(parser_material_kong, "if (tex_coord_blend.z > 0.0) {" + tex_store + " += sample(" + tex_name + ", sampler_linear, " + uv_name + "2.xy) * tex_coord_blend.z; }"); + } + else { + if (parser_material_is_frag) { + map_set(parser_material_texture_map, tex_store, "sample(" + tex_name + ", sampler_linear, " + uv_name + ".xy)"); + parser_material_write(parser_material_kong, "var " + tex_store + ": float4 = sample(" + tex_name + ", sampler_linear, " + uv_name + ".xy);"); + } + else { + map_set(parser_material_texture_map, tex_store, "sample_lod(" + tex_name + ", sampler_linear, " + uv_name + ".xy, 0.0)"); + parser_material_write(parser_material_kong, "var " + tex_store + ": float4 = sample_lod(" + tex_name + ", sampler_linear, " + uv_name + ".xy, 0.0);"); + } + if (!ends_with(tex.file, ".jpg")) { // Pre-mult alpha + parser_material_write(parser_material_kong, tex_store + ".rgb = " + tex_store + ".rgb * " + tex_store + ".a;"); + } + } + + if (parser_material_transform_color_space) { + // Base color socket auto-converts from sRGB to linear + if (color_space == color_space_t.LINEAR && parser_material_parsing_basecolor) { // Linear to sRGB + parser_material_write(parser_material_kong, tex_store + ".rgb = pow3(" + tex_store + ".rgb, float3(2.2, 2.2, 2.2));"); + } + else if (color_space == color_space_t.SRGB && !parser_material_parsing_basecolor) { // sRGB to linear + parser_material_write(parser_material_kong, tex_store + ".rgb = pow3(" + tex_store + ".rgb, float3(1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2));"); + } + else if (color_space == color_space_t.DIRECTX_NORMAL_MAP) { // DirectX normal map to OpenGL normal map + parser_material_write(parser_material_kong, tex_store + ".y = 1.0 - " + tex_store + ".y;"); + } + } + return tex_store; +} + +function parser_material_make_texture(image_node: ui_node_t, tex_name: string): bind_tex_t { + let i: i32 = image_node.buttons[0].default_value[0]; + if (i > 9000) { // 9999 - Texture deleted, use pink now + return null; + } + let filepath: string = parser_material_enum_data(base_enum_texts(image_node.type)[i]); + if (filepath == "" || string_index_of(filepath, ".") == -1) { + return null; + } + + return parser_material_make_bind_tex(tex_name, filepath); +} + +function image_texture_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + // Already fetched + if (array_index_of(parser_material_parsed, parser_material_res_var_name(node, node.outputs[1])) >= 0) { // TODO: node.outputs[0] + let varname: string = parser_material_store_var_name(node); + return varname + ".rgb"; + } + let tex_name: string = parser_material_node_name(node); + let tex: bind_tex_t = parser_material_make_texture(node, tex_name); + if (tex != null) { + let color_space: i32 = node.buttons[1].default_value[0]; + let texstore: string = parser_material_texture_store(node, tex, tex_name, color_space); + return texstore + ".rgb"; + } + else { + let tex_store: string = parser_material_store_var_name(node); // Pink color for missing texture + parser_material_write(parser_material_kong, "var " + tex_store + ": float4 = float4(1.0, 0.0, 1.0, 1.0);"); + return tex_store + ".rgb"; + } +} + +function image_texture_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + // Already fetched + if (array_index_of(parser_material_parsed, parser_material_res_var_name(node, node.outputs[0])) >= 0) { // TODO: node.outputs[1] + let varname: string = parser_material_store_var_name(node); + return varname + ".a"; + } + let tex_name: string = parser_material_node_name(node); + let tex: bind_tex_t = parser_material_make_texture(node, tex_name); + if (tex != null) { + let color_space: i32 = node.buttons[1].default_value[0]; + let texstore: string = parser_material_texture_store(node, tex, tex_name, color_space); + return texstore + ".a"; + } +} + let image_texture_node_def: ui_node_t = { id: 0, name: _tr("Image Texture"), diff --git a/paint/sources/material_nodes/invert_node.ts b/paint/sources/material_nodes/invert_node.ts index 56ea206d..66d32fb3 100644 --- a/paint/sources/material_nodes/invert_node.ts +++ b/paint/sources/material_nodes/invert_node.ts @@ -1,4 +1,10 @@ +function invert_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let fac: string = parser_material_parse_value_input(node.inputs[0]); + let out_col: string = parser_material_parse_vector_input(node.inputs[1]); + return "lerp3(" + out_col + ", float3(1.0, 1.0, 1.0) - (" + out_col + "), " + fac + ")"; +} + let invert_node_def: ui_node_t = { id: 0, name: _tr("Invert"), diff --git a/paint/sources/material_nodes/layer_mask_node.ts b/paint/sources/material_nodes/layer_mask_node.ts index 8f6ae5eb..75d81513 100644 --- a/paint/sources/material_nodes/layer_mask_node.ts +++ b/paint/sources/material_nodes/layer_mask_node.ts @@ -1,4 +1,12 @@ +function layer_mask_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + if (socket == node.outputs[0]) { + let l: i32 = node.buttons[0].default_value[0]; + node_shader_add_texture(parser_material_kong, "texpaint" + l, "_texpaint" + l); + return "sample(texpaint" + l + ", sampler_linear, tex_coord).r"; + } +} + let layer_mask_node_def: ui_node_t = { id: 0, name: _tr("Layer Mask"), diff --git a/paint/sources/material_nodes/layer_node.ts b/paint/sources/material_nodes/layer_node.ts index 0a8f03b8..14a9116c 100644 --- a/paint/sources/material_nodes/layer_node.ts +++ b/paint/sources/material_nodes/layer_node.ts @@ -1,4 +1,40 @@ +function layer_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let l: i32 = node.buttons[0].default_value[0]; + if (socket == node.outputs[0]) { // Base + node_shader_add_texture(parser_material_kong, "texpaint" + l, "_texpaint" + l); + return "sample(texpaint" + l + ", sampler_linear, tex_coord).rgb"; + } + else if (socket == node.outputs[5]) { // Normal + node_shader_add_texture(parser_material_kong, "texpaint_nor" + l, "_texpaint_nor" + l); + return "sample(texpaint_nor" + l + ", sampler_linear, tex_coord).rgb"; + } +} + +function layer_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let l: i32 = node.buttons[0].default_value[0]; + if (socket == node.outputs[1]) { // Opac + node_shader_add_texture(parser_material_kong, "texpaint" + l, "_texpaint" + l); + return "sample(texpaint" + l + ", sampler_linear, tex_coord).a"; + } + else if (socket == node.outputs[2]) { // Occ + node_shader_add_texture(parser_material_kong, "texpaint_pack" + l, "_texpaint_pack" + l); + return "sample(texpaint_pack" + l + ", sampler_linear, tex_coord).r"; + } + else if (socket == node.outputs[3]) { // Rough + node_shader_add_texture(parser_material_kong, "texpaint_pack" + l, "_texpaint_pack" + l); + return "sample(texpaint_pack" + l + ", sampler_linear, tex_coord).g"; + } + else if (socket == node.outputs[4]) { // Metal + node_shader_add_texture(parser_material_kong, "texpaint_pack" + l, "_texpaint_pack" + l); + return "sample(texpaint_pack" + l + ", sampler_linear, tex_coord).b"; + } + else if (socket == node.outputs[7]) { // Height + node_shader_add_texture(parser_material_kong, "texpaint_pack" + l, "_texpaint_pack" + l); + return "sample(texpaint_pack" + l + ", sampler_linear, tex_coord).a"; + } +} + let layer_node_def: ui_node_t = { id: 0, name: _tr("Layer"), @@ -132,4 +168,4 @@ let layer_node_def: ui_node_t = { ], width: 0, flags: 0 -}; \ No newline at end of file +}; diff --git a/paint/sources/material_nodes/layer_weight_node.ts b/paint/sources/material_nodes/layer_weight_node.ts index 478fb713..a2869d33 100644 --- a/paint/sources/material_nodes/layer_weight_node.ts +++ b/paint/sources/material_nodes/layer_weight_node.ts @@ -1,4 +1,16 @@ +function layer_weight_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let blend: string = parser_material_parse_value_input(node.inputs[0]); + if (socket == node.outputs[0]) { // Fresnel + parser_material_kong.frag_dotnv = true; + return "clamp(pow(1.0 - dotnv, (1.0 - " + blend + ") * 10.0), 0.0, 1.0)"; + } + else if (socket == node.outputs[1]) { // Facing + parser_material_kong.frag_dotnv = true; + return "((1.0 - dotnv) * " + blend + ")"; + } +} + let layer_weight_node_def: ui_node_t = { id: 0, name: _tr("Layer Weight"), diff --git a/paint/sources/material_nodes/magic_texture_node.ts b/paint/sources/material_nodes/magic_texture_node.ts index c6007745..844a4528 100644 --- a/paint/sources/material_nodes/magic_texture_node.ts +++ b/paint/sources/material_nodes/magic_texture_node.ts @@ -1,4 +1,33 @@ +let str_tex_magic: string = "\ +fun tex_magic(p: float3): float3 { \ + var a: float = 1.0 - (sin(p.x) + sin(p.y)); \ + var b: float = 1.0 - sin(p.x - p.y); \ + var c: float = 1.0 - sin(p.x + p.y); \ + return float3(a, b, c); \ +} \ +fun tex_magic_f(p: float3): float { \ + var c: float3 = tex_magic(p); \ + return (c.x + c.y + c.z) / 3.0; \ +} \ +"; + +function magic_texture_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_magic); + let co: string = parser_material_get_coord(node); + let scale: string = parser_material_parse_value_input(node.inputs[1]); + let res: string = "tex_magic(" + co + " * " + scale + " * 4.0)"; + return res; +} + +function magic_texture_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_magic); + let co: string = parser_material_get_coord(node); + let scale: string = parser_material_parse_value_input(node.inputs[1]); + let res: string = "tex_magic_f(" + co + " * " + scale + " * 4.0)"; + return res; +} + let magic_texture_node_def: ui_node_t = { id: 0, name: _tr("Magic Texture"), diff --git a/paint/sources/material_nodes/map_range_node.ts b/paint/sources/material_nodes/map_range_node.ts index 3cc087cd..5cabb874 100644 --- a/paint/sources/material_nodes/map_range_node.ts +++ b/paint/sources/material_nodes/map_range_node.ts @@ -1,4 +1,23 @@ +function map_range_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let val: string = parser_material_parse_value_input(node.inputs[0]); + let fmin: string = parser_material_parse_value_input(node.inputs[1]); + let fmax: string = parser_material_parse_value_input(node.inputs[2]); + let tmin: string = parser_material_parse_value_input(node.inputs[3]); + let tmax: string = parser_material_parse_value_input(node.inputs[4]); + + let use_clamp: bool = node.buttons[0].default_value[0] > 0; + + let a: string = "((" + tmin + " - " + tmax + ") / (" + fmin + " - " + fmax + "))"; + let out_val: string = "(" + a + " * " + val + " + " + tmin + " - " + a + " * " + fmin + ")"; + if (use_clamp) { + return "(clamp(" + out_val + ", " + tmin + ", " + tmax + "))"; + } + else { + return out_val; + } +} + let map_range_node_def: ui_node_t = { id: 0, name: _tr("Map Range"), diff --git a/paint/sources/material_nodes/mapping_node.ts b/paint/sources/material_nodes/mapping_node.ts index 1ece6716..f2ad6a07 100644 --- a/paint/sources/material_nodes/mapping_node.ts +++ b/paint/sources/material_nodes/mapping_node.ts @@ -1,4 +1,35 @@ +function mapping_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let out: string = parser_material_parse_vector_input(node.inputs[0]); + let node_translation: string = parser_material_parse_vector_input(node.inputs[1]); + let node_rotation: string = parser_material_parse_vector_input(node.inputs[2]); + let node_scale: string = parser_material_parse_vector_input(node.inputs[3]); + if (node_scale != "float3(1, 1, 1)") { + out = "(" + out + " * " + node_scale + ")"; + } + if (node_rotation != "float3(0, 0, 0)") { + // ZYX rotation, Z axis for now.. + let a: string = node_rotation + ".z * (3.1415926535 / 180)"; + // x * cos(theta) - y * sin(theta) + // x * sin(theta) + y * cos(theta) + out = "float3(" + out + ".x * cos(" + a + ") - " + out + ".y * sin(" + a + "), " + out + ".x * sin(" + a + ") + " + out + ".y * cos(" + a + "), 0.0)"; + } + // if node.rotation[1] != 0.0: + // a = node.rotation[1] + // out = "float3({0}.x * {1} - {0}.z * {2}, {0}.x * {2} + {0}.z * {1}, 0.0)".format(out, math_cos(a), math_sin(a)) + // if node.rotation[0] != 0.0: + // a = node.rotation[0] + // out = "float3({0}.y * {1} - {0}.z * {2}, {0}.y * {2} + {0}.z * {1}, 0.0)".format(out, math_cos(a), math_sin(a)) + if (node_translation != "float3(0, 0, 0)") { + out = "(" + out + " + " + node_translation + ")"; + } + // if node.use_min: + // out = "max({0}, float3({1}, {2}, {3}))".format(out, node.min[0], node.min[1]) + // if node.use_max: + // out = "min({0}, float3({1}, {2}, {3}))".format(out, node.max[0], node.max[1]) + return out; +} + let mapping_node_def: ui_node_t = { id: 0, name: _tr("Mapping"), diff --git a/paint/sources/material_nodes/material_node.ts b/paint/sources/material_nodes/material_node.ts index b3044967..cdee7750 100644 --- a/paint/sources/material_nodes/material_node.ts +++ b/paint/sources/material_nodes/material_node.ts @@ -1,4 +1,61 @@ +function material_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let result: string = "float3(0.0, 0.0, 0.0)"; + let mi: i32 = node.buttons[0].default_value[0]; + if (mi >= project_materials.length) { + return result; + } + let m: slot_material_t = project_materials[mi]; + let _nodes: ui_node_t[] = parser_material_nodes; + let _links: ui_node_link_t[] = parser_material_links; + parser_material_nodes = m.canvas.nodes; + parser_material_links = m.canvas.links; + array_push(parser_material_parents, node); + let output_node: ui_node_t = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL_PBR"); + if (socket == node.outputs[0]) { // Base + result = parser_material_parse_vector_input(output_node.inputs[0]); + } + else if (socket == node.outputs[5]) { // Normal + result = parser_material_parse_vector_input(output_node.inputs[5]); + } + parser_material_nodes = _nodes; + parser_material_links = _links; + array_pop(parser_material_parents); + return result; +} + +function material_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let result: string = "0.0"; + let mi: i32 = node.buttons[0].default_value[0]; + if (mi >= project_materials.length) return result; + let m: slot_material_t = project_materials[mi]; + let _nodes: ui_node_t[] = parser_material_nodes; + let _links: ui_node_link_t[] = parser_material_links; + parser_material_nodes = m.canvas.nodes; + parser_material_links = m.canvas.links; + array_push(parser_material_parents, node); + let output_node: ui_node_t = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL_PBR"); + if (socket == node.outputs[1]) { // Opac + result = parser_material_parse_value_input(output_node.inputs[1]); + } + else if (socket == node.outputs[2]) { // Occ + result = parser_material_parse_value_input(output_node.inputs[2]); + } + else if (socket == node.outputs[3]) { // Rough + result = parser_material_parse_value_input(output_node.inputs[3]); + } + else if (socket == node.outputs[4]) { // Metal + result = parser_material_parse_value_input(output_node.inputs[4]); + } + else if (socket == node.outputs[7]) { // Height + result = parser_material_parse_value_input(output_node.inputs[7]); + } + parser_material_nodes = _nodes; + parser_material_links = _links; + array_pop(parser_material_parents); + return result; +} + let material_node_def: ui_node_t = { id: 0, name: _tr("Material"), diff --git a/paint/sources/material_nodes/math2_node.ts b/paint/sources/material_nodes/math2_node.ts index e73d00f9..468459b9 100644 --- a/paint/sources/material_nodes/math2_node.ts +++ b/paint/sources/material_nodes/math2_node.ts @@ -1,4 +1,139 @@ +function math2_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let val1: string = parser_material_parse_value_input(node.inputs[0]); + let val2: string = parser_material_parse_value_input(node.inputs[1]); + let but: ui_node_button_t = node.buttons[0]; // operation + let op: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); + op = string_replace_all(op, " ", "_"); + let use_clamp: bool = node.buttons[1].default_value[0] > 0; + let out_val: string = ""; + if (op == "ADD") { + out_val = "(" + val1 + " + " + val2 + ")"; + } + else if (op == "SUBTRACT") { + out_val = "(" + val1 + " - " + val2 + ")"; + } + else if (op == "MULTIPLY") { + out_val = "(" + val1 + " * " + val2 + ")"; + } + else if (op == "DIVIDE") { + let store: string = parser_material_store_var_name(node) + "_divide"; + parser_material_write(parser_material_kong, "var " + store + ": float = " + val2 + ";"); + parser_material_write(parser_material_kong, "if (" + store + " == 0.0) { " + store + " = " + parser_material_eps + "; }"); + out_val = "(" + val1 + " / " + store + ")"; + } + else if (op == "POWER") { + out_val = "pow(" + val1 + ", " + val2 + ")"; + } + else if (op == "LOGARITHM") { + out_val = "log(" + val1 + ")"; + } + else if (op == "SQUARE_ROOT") { + out_val = "sqrt(" + val1 + ")"; + } + else if(op == "INVERSE_SQUARE_ROOT") { + out_val = "rsqrt(" + val1 + ")"; + } + else if (op == "EXPONENT") { + out_val = "exp(" + val1 + ")"; + } + else if (op == "ABSOLUTE") { + out_val = "abs(" + val1 + ")"; + } + else if (op == "MINIMUM") { + out_val = "min(" + val1 + ", " + val2 + ")"; + } + else if (op == "MAXIMUM") { + out_val = "max(" + val1 + ", " + val2 + ")"; + } + else if (op == "LESS_THAN") { + // out_val = "float(" + val1 + " < " + val2 + ")"; + let store: string = parser_material_store_var_name(node) + "_lessthan"; + parser_material_write(parser_material_kong, "var " + store + ": float = 0.0;"); + parser_material_write(parser_material_kong, "if (" + val1 + " < " + val2 + ") { " + store + " = 1.0; }"); + out_val = store; + } + else if (op == "GREATER_THAN") { + // out_val = "float(" + val1 + " > " + val2 + ")"; + let store: string = parser_material_store_var_name(node) + "_greaterthan"; + parser_material_write(parser_material_kong, "var " + store + ": float = 0.0;"); + parser_material_write(parser_material_kong, "if (" + val1 + " > " + val2 + ") { " + store + " = 1.0; }"); + out_val = store; + } + else if (op == "SIGN") { + out_val = "sign(" + val1 + ")"; + } + else if (op == "ROUND") { + out_val = "floor(" + val1 + " + 0.5)"; + } + else if (op == "FLOOR") { + out_val = "floor(" + val1 + ")"; + } + else if (op == "CEIL") { + out_val = "ceil(" + val1 + ")"; + } + else if(op == "SNAP") { + out_val = "(floor(" + val1 + " / " + val2 + ") * " + val2 + ")"; + } + else if (op == "TRUNCATE") { + out_val = "trunc(" + val1 + ")"; + } + else if (op == "FRACTION") { + out_val = "frac(" + val1 + ")"; + } + else if (op == "MODULO") { + out_val = "(" + val1 + " % " + val2 + ")"; + } + else if (op == "PING-PONG") { + let store: string = parser_material_store_var_name(node) + "_pingpong"; + parser_material_write(parser_material_kong, "var " + store + ": float = 0.0;"); + parser_material_write(parser_material_kong, "if (" + val2 + " != 0.0) { " + store + " = abs(frac((" + val1 + " - " + val2 + ") / (" + val2 + " * 2.0)) * " + val2 + " * 2.0 - " + val2 + "); }"); + out_val = store; + } + else if (op == "SINE") { + out_val = "sin(" + val1 + ")"; + } + else if (op == "COSINE") { + out_val = "cos(" + val1 + ")"; + } + else if (op == "TANGENT") { + out_val = "tan(" + val1 + ")"; + } + else if (op == "ARCSINE") { + out_val = "asin(" + val1 + ")"; + } + else if (op == "ARCCOSINE") { + out_val = "acos(" + val1 + ")"; + } + else if (op == "ARCTANGENT") { + out_val = "atan(" + val1 + ")"; + } + else if (op == "ARCTAN2") { + out_val = "atan2(" + val1 + ", " + val2 + ")"; + } + else if (op == "HYPERBOLIC_SINE") { + out_val = "sinh(" + val1 + ")"; + } + else if (op == "HYPERBOLIC_COSINE") { + out_val = "cosh(" + val1 + ")"; + } + else if (op == "HYPERBOLIC_TANGENT") { + out_val = "tanh(" + val1 + ")"; + } + else if (op == "TO_RADIANS") { + out_val = "radians(" + val1 + ")"; + } + else if (op == "TO_DEGREES") { + out_val = "degrees(" + val1 + ")"; + } + if (use_clamp) { + return "clamp(" + out_val + ", 0.0, 1.0)"; + } + else { + return out_val; + } +} + let math2_node_def: ui_node_t = { id: 0, name: _tr("Math"), diff --git a/paint/sources/material_nodes/mix_color_node.ts b/paint/sources/material_nodes/mix_color_node.ts index d21a7aed..fbd7ea1c 100644 --- a/paint/sources/material_nodes/mix_color_node.ts +++ b/paint/sources/material_nodes/mix_color_node.ts @@ -1,4 +1,99 @@ +function mix_color_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let fac: string = parser_material_parse_value_input(node.inputs[0]); + let fac_var: string = parser_material_node_name(node) + "_fac"; + parser_material_write(parser_material_kong, "var " + fac_var + ": float = " + fac + ";"); + let col1: string = parser_material_parse_vector_input(node.inputs[1]); + let col2: string = parser_material_parse_vector_input(node.inputs[2]); + let but: ui_node_button_t = node.buttons[0]; // blend_type + let blend: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); + blend = string_replace_all(blend, " ", "_"); + let use_clamp: bool = node.buttons[1].default_value[0] > 0; + let out_col: string = ""; + if (blend == "MIX") { + out_col = "lerp3(" + col1 + ", " + col2 + ", " + fac_var + ")"; + } + else if (blend == "DARKEN") { + out_col = "min3(" + col1 + ", " + col2 + " * " + fac_var + ")"; + } + else if (blend == "MULTIPLY") { + out_col = "lerp3(" + col1 + ", " + col1 + " * " + col2 + ", " + fac_var + ")"; + } + else if (blend == "BURN") { + out_col = "lerp3(" + col1 + ", float3(1.0, 1.0, 1.0) - (float3(1.0, 1.0, 1.0) - " + col1 + ") / " + col2 + ", " + fac_var + ")"; + } + else if (blend == "LIGHTEN") { + out_col = "max3(" + col1 + ", " + col2 + " * " + fac_var + ")"; + } + else if (blend == "SCREEN") { + let v3: string = parser_material_to_vec3("1.0 - " + fac_var); + out_col = "(float3(1.0, 1.0, 1.0) - (" + v3 + " + " + fac_var + " * (float3(1.0, 1.0, 1.0) - " + col2 + ")) * (float3(1.0, 1.0, 1.0) - " + col1 + "))"; + } + else if (blend == "DODGE") { + out_col = "lerp3(" + col1 + ", " + col1 + " / (float3(1.0, 1.0, 1.0) - " + col2 + "), " + fac_var + ")"; + } + else if (blend == "ADD") { + out_col = "lerp3(" + col1 + ", " + col1 + " + " + col2 + ", " + fac_var + ")"; + } + else if (blend == "OVERLAY") { + // out_col = "lerp3(" + col1 + ", float3( \ + // " + col1 + ".r < 0.5 ? 2.0 * " + col1 + ".r * " + col2 + ".r : 1.0 - 2.0 * (1.0 - " + col1 + ".r) * (1.0 - " + col2 + ".r), \ + // " + col1 + ".g < 0.5 ? 2.0 * " + col1 + ".g * " + col2 + ".g : 1.0 - 2.0 * (1.0 - " + col1 + ".g) * (1.0 - " + col2 + ".g), \ + // " + col1 + ".b < 0.5 ? 2.0 * " + col1 + ".b * " + col2 + ".b : 1.0 - 2.0 * (1.0 - " + col1 + ".b) * (1.0 - " + col2 + ".b) \ + // ), " + fac_var + ")"; + let res_r: string = parser_material_node_name(node) + "_res_r"; + let res_g: string = parser_material_node_name(node) + "_res_g"; + let res_b: string = parser_material_node_name(node) + "_res_b"; + parser_material_write(parser_material_kong, "var " + res_r + ": float;"); + parser_material_write(parser_material_kong, "var " + res_g + ": float;"); + parser_material_write(parser_material_kong, "var " + res_b + ": float;"); + parser_material_write(parser_material_kong, "if (" + col1 + ".r < 0.5) { " + res_r + " = 2.0 * " + col1 + ".r * " + col2 + ".r; } else { " + res_r + " = 1.0 - 2.0 * (1.0 - " + col1 + ".r) * (1.0 - " + col2 + ".r); }"); + parser_material_write(parser_material_kong, "if (" + col1 + ".g < 0.5) { " + res_g + " = 2.0 * " + col1 + ".g * " + col2 + ".g; } else { " + res_g + " = 1.0 - 2.0 * (1.0 - " + col1 + ".g) * (1.0 - " + col2 + ".g); }"); + parser_material_write(parser_material_kong, "if (" + col1 + ".b < 0.5) { " + res_b + " = 2.0 * " + col1 + ".b * " + col2 + ".b; } else { " + res_b + " = 1.0 - 2.0 * (1.0 - " + col1 + ".b) * (1.0 - " + col2 + ".b); }"); + out_col = "lerp3(" + col1 + ", float3(" + res_r + ", " + res_g + ", " + res_b + "), " + fac_var + ")"; + } + else if (blend == "SOFT_LIGHT") { + out_col = "((1.0 - " + fac_var + ") * " + col1 + " + " + fac_var + " * ((float3(1.0, 1.0, 1.0) - " + col1 + ") * " + col2 + " * " + col1 + " + " + col1 + " * (float3(1.0, 1.0, 1.0) - (float3(1.0, 1.0, 1.0) - " + col2 + ") * (float3(1.0, 1.0, 1.0) - " + col1 + "))))"; + } + else if (blend == "LINEAR_LIGHT") { + out_col = "(" + col1 + " + " + fac_var + " * (float3(2.0, 2.0, 2.0) * (" + col2 + " - float3(0.5, 0.5, 0.5))))"; + } + else if (blend == "DIFFERENCE") { + out_col = "lerp3(" + col1 + ", abs3(" + col1 + " - " + col2 + "), " + fac_var + ")"; + } + else if (blend == "SUBTRACT") { + out_col = "lerp3(" + col1 + ", " + col1 + " - " + col2 + ", " + fac_var + ")"; + } + else if (blend == "DIVIDE") { + let eps: f32 = 0.000001; + col2 = "max3(" + col2 + ", float3(" + eps + ", " + eps + ", " + eps + "))"; + let v3: string = "(float3(1.0, 1.0, 1.0) - float3(" + fac_var + ", " + fac_var + ", " + fac_var + ")) * " + col1 + " + float3(" + fac_var + ", " + fac_var + ", " + fac_var + ") * " + col1 + " / " + col2; + out_col = "(" + v3 + ")"; + } + else if (blend == "HUE") { + node_shader_add_function(parser_material_kong, str_hue_sat); + out_col = "lerp3(" + col1 + ", hsv_to_rgb(float3(rgb_to_hsv(" + col2 + ").r, rgb_to_hsv(" + col1 + ").g, rgb_to_hsv(" + col1 + ").b)), " + fac_var + ")"; + } + else if (blend == "SATURATION") { + node_shader_add_function(parser_material_kong, str_hue_sat); + out_col = "lerp3(" + col1 + ", hsv_to_rgb(float3(rgb_to_hsv(" + col1 + ").r, rgb_to_hsv(" + col2 + ").g, rgb_to_hsv(" + col1 + ").b)), " + fac_var + ")"; + } + else if (blend == "COLOR") { + node_shader_add_function(parser_material_kong, str_hue_sat); + out_col = "lerp3(" + col1 + ", hsv_to_rgb(float3(rgb_to_hsv(" + col2 + ").r, rgb_to_hsv(" + col2 + ").g, rgb_to_hsv(" + col1 + ").b)), " + fac_var + ")"; + } + else if (blend == "VALUE") { + node_shader_add_function(parser_material_kong, str_hue_sat); + out_col = "lerp3(" + col1 + ", hsv_to_rgb(float3(rgb_to_hsv(" + col1 + ").r, rgb_to_hsv(" + col1 + ").g, rgb_to_hsv(" + col2 + ").b)), " + fac_var + ")"; + } + if (use_clamp) { + return "clamp3(" + out_col + ", float3(0.0, 0.0, 0.0), float3(1.0, 1.0, 1.0))"; + } + else { + return out_col; + } +} + let mix_color_node_def: ui_node_t = { id: 0, name: _tr("Mix Color"), diff --git a/paint/sources/material_nodes/mix_normal_map_node.ts b/paint/sources/material_nodes/mix_normal_map_node.ts index 55209576..cdbdada3 100644 --- a/paint/sources/material_nodes/mix_normal_map_node.ts +++ b/paint/sources/material_nodes/mix_normal_map_node.ts @@ -1,4 +1,31 @@ +function mix_normal_map_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let nm1: string = parser_material_parse_vector_input(node.inputs[0]); + let nm2: string = parser_material_parse_vector_input(node.inputs[1]); + let but: ui_node_button_t = node.buttons[0]; + let blend: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); // blend_type + blend = string_replace_all(blend, " ", "_"); + let store: string = parser_material_store_var_name(node); + + // The blending algorithms are based on the paper "Blending in Detail" by Colin Barré-Brisebois and Stephen Hill 2012 + // https://blog.selfshadow.com/publications/blending-in-detail/ + if (blend == "PARTIAL_DERIVATIVE") { //partial derivate blending + parser_material_write(parser_material_kong, "var " + store + "_n1: float3 = " + nm1 + " * 2.0 - 1.0;"); + parser_material_write(parser_material_kong, "var " + store + "_n2: float3 = " + nm2 + " * 2.0 - 1.0;"); + return "0.5 * normalize(float3(" + store + "_n1.xy * " + store + "_n2.z + " + store + "_n2.xy * " + store + "_n1.z, " + store + "_n1.z * " + store + "_n2.z)) + 0.5"; + } + else if (blend == "WHITEOUT") { //whiteout blending + parser_material_write(parser_material_kong, "var " + store + "_n1: float3 = " + nm1 + " * 2.0 - 1.0;"); + parser_material_write(parser_material_kong, "var " + store + "_n2: float3 = " + nm2 + " * 2.0 - 1.0;"); + return "0.5 * normalize(float3(" + store + "_n1.xy + " + store + "_n2.xy, " + store + "_n1.z * " + store + "_n2.z)) + 0.5"; + } + else if (blend == "REORIENTED") { //reoriented normal mapping + parser_material_write(parser_material_kong, "var " + store + "_n1: float3 = " + nm1 + " * 2.0 - float3(1.0, 1.0, 0.0);"); + parser_material_write(parser_material_kong, "var " + store + "_n2: float3 = " + nm2 + " * float3(-2.0, -2.0, 2.0) - float3(-1.0, -1.0, 1.0);"); + return "0.5 * normalize(" + store + "_n1 * dot(" + store + "_n1, " + store + "_n2) - " + store + "_n2 * " + store + "_n1.z) + 0.5"; + } +} + let mix_normal_map_node_def: ui_node_t = { id: 0, name: _tr("Mix Normal Map"), diff --git a/paint/sources/material_nodes/musgrave_texture_node.ts b/paint/sources/material_nodes/musgrave_texture_node.ts index 35e83df4..adf6d402 100644 --- a/paint/sources/material_nodes/musgrave_texture_node.ts +++ b/paint/sources/material_nodes/musgrave_texture_node.ts @@ -1,4 +1,52 @@ +let str_tex_musgrave: string = "\ +fun random3(c: float3): float3 { \ + var j: float = 4096.0 * sin(dot(c, float3(17.0, 59.4, 15.0))); \ + var r: float3; \ + r.z = frac(512.0 * j); \ + j *= 0.125; \ + r.x = frac(512.0 * j); \ + j *= 0.125; \ + r.y = frac(512.0 * j); \ + return r - 0.5; \ +} \ +fun tex_musgrave_f(p: float3): float { \ + var F3: float = 0.3333333; \ + var G3: float = 0.1666667; \ + var s: float3 = floor3(p + dot(p, float3(F3, F3, F3))); \ + var x: float3 = p - s + dot(s, float3(G3, G3, G3)); \ + var e: float3 = step3(float3(0.0, 0.0, 0.0), x - x.yzx); \ + var i1: float3 = e * (1.0 - e.zxy); \ + var i2: float3 = 1.0 - e.zxy * (1.0 - e); \ + var x1: float3 = x - i1 + G3; \ + var x2: float3 = x - i2 + 2.0 * G3; \ + var x3: float3 = x - 1.0 + 3.0 * G3; \ + var w: float4; \ + var d: float4; \ + w.x = dot(x, x); \ + w.y = dot(x1, x1); \ + w.z = dot(x2, x2); \ + w.w = dot(x3, x3); \ + w = max4(float4(0.6, 0.6, 0.6, 0.6) - w, float4(0.0, 0.0, 0.0, 0.0)); \ + d.x = dot(random3(s), x); \ + d.y = dot(random3(s + i1), x1); \ + d.z = dot(random3(s + i2), x2); \ + d.w = dot(random3(s + 1.0), x3); \ + w *= w; \ + w *= w; \ + d *= w; \ + return clamp(dot(d, float4(52.0, 52.0, 52.0, 52.0)), 0.0, 1.0); \ +} \ +"; + +function musgrave_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_musgrave); + let co: string = parser_material_get_coord(node); + let scale: string = parser_material_parse_value_input(node.inputs[1]); + let res: string = "tex_musgrave_f(" + co + " * " + scale + " * 0.5)"; + return res; +} + let musgrave_texture_node_def: ui_node_t = { id: 0, name: _tr("Musgrave Texture"), diff --git a/paint/sources/material_nodes/noise_texture_node.ts b/paint/sources/material_nodes/noise_texture_node.ts index 813f67bb..92b4a916 100644 --- a/paint/sources/material_nodes/noise_texture_node.ts +++ b/paint/sources/material_nodes/noise_texture_node.ts @@ -1,4 +1,43 @@ +let str_tex_noise: string = "\ +fun hash(n: float): float { return frac(sin(n) * 10000.0); } \ +fun tex_noise_f(x: float3): float { \ + var step: float3 = float3(110.0, 241.0, 171.0); \ + var i: float3 = floor3(x); \ + var f: float3 = frac3(x); \ + var n: float = dot(i, step); \ + var u: float3 = f * f * (3.0 - 2.0 * f); \ + return lerp(lerp(lerp(hash(n + dot(step, float3(0.0, 0.0, 0.0))), hash(n + dot(step, float3(1.0, 0.0, 0.0))), u.x), \ + lerp(hash(n + dot(step, float3(0.0, 1.0, 0.0))), hash(n + dot(step, float3(1.0, 1.0, 0.0))), u.x), u.y), \ + lerp(lerp(hash(n + dot(step, float3(0.0, 0.0, 1.0))), hash(n + dot(step, float3(1.0, 0.0, 1.0))), u.x), \ + lerp(hash(n + dot(step, float3(0.0, 1.0, 1.0))), hash(n + dot(step, float3(1.0, 1.0, 1.0))), u.x), u.y), u.z); \ +} \ +fun tex_noise(p: float3): float { \ + p = p * 1.25; \ + var f: float = 0.5 * tex_noise_f(p); p = p * 2.01; \ + f += 0.25 * tex_noise_f(p); p = p * 2.02; \ + f += 0.125 * tex_noise_f(p); p = p * 2.03; \ + f += 0.0625 * tex_noise_f(p); \ + return 1.0 - f; \ +} \ +"; + +function noise_texture_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_noise); + let co: string = parser_material_get_coord(node); + let scale: string = parser_material_parse_value_input(node.inputs[1]); + let res: string = "float3(tex_noise(" + co + " * " + scale + "), tex_noise(" + co + " * " + scale + " + 0.33), tex_noise(" + co + " * " + scale + " + 0.66))"; + return res; +} + +function noise_texture_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_noise); + let co: string = parser_material_get_coord(node); + let scale: string = parser_material_parse_value_input(node.inputs[1]); + let res: string = "tex_noise(" + co + " * " + scale + ")"; + return res; +} + let noise_texture_node_def: ui_node_t = { id: 0, name: _tr("Noise Texture"), diff --git a/paint/sources/material_nodes/normal_map_node.ts b/paint/sources/material_nodes/normal_map_node.ts index 4b17a8de..179133f1 100644 --- a/paint/sources/material_nodes/normal_map_node.ts +++ b/paint/sources/material_nodes/normal_map_node.ts @@ -1,4 +1,16 @@ +function normal_map_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let strength: string = parser_material_parse_value_input(node.inputs[0]); + let norm: string = parser_material_parse_vector_input(node.inputs[1]); + + let store: string = parser_material_store_var_name(node); + parser_material_write(parser_material_kong, "var " + store + "_texn: float3 = " + norm + " * 2.0 - 1.0;"); + parser_material_write(parser_material_kong, "" + store + "_texn.xy = " + strength + " * " + store + "_texn.xy;"); + parser_material_write(parser_material_kong, "" + store + "_texn = normalize(" + store + "_texn);"); + + return "(0.5 * " + store + "_texn + 0.5)"; +} + let normal_map_node_def: ui_node_t = { id: 0, name: _tr("Normal Map"), diff --git a/paint/sources/material_nodes/normal_node.ts b/paint/sources/material_nodes/normal_node.ts index d2b01733..e38a4f0c 100644 --- a/paint/sources/material_nodes/normal_node.ts +++ b/paint/sources/material_nodes/normal_node.ts @@ -1,4 +1,21 @@ +function normal_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + if (socket == node.outputs[0]) { + return parser_material_vec3(node.outputs[0].default_value); + } + else if (socket == node.outputs[1]) { + let nor: string = parser_material_parse_vector_input(node.inputs[0]); + let norout: string = parser_material_vec3(node.outputs[0].default_value); + return parser_material_to_vec3("dot(" + norout + ", " + nor + ")"); + } +} + +function normal_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let nor: string = parser_material_parse_vector_input(node.inputs[0]); + let norout: string = parser_material_vec3(node.outputs[0].default_value); + return "dot(" + norout + ", " + nor + ")"; +} + let normal_node_def: ui_node_t = { id: 0, name: _tr("Normal"), diff --git a/paint/sources/material_nodes/object_info_node.ts b/paint/sources/material_nodes/object_info_node.ts index 9006505d..6a3b05a1 100644 --- a/paint/sources/material_nodes/object_info_node.ts +++ b/paint/sources/material_nodes/object_info_node.ts @@ -1,4 +1,29 @@ +function object_info_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + if (socket == node.outputs[0]) { // Location + parser_material_kong.frag_wposition = true; + return "input.wposition"; + } + else if (socket == node.outputs[1]) { // Color + return "float3(0.0, 0.0, 0.0)"; + } +} + +function object_info_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + if (socket == node.outputs[1]) { // Object Index + node_shader_add_constant(parser_material_kong, "object_info_index: float", "_object_info_index"); + return "constants.object_info_index"; + } + else if (socket == node.outputs[2]) { // Material Index + node_shader_add_constant(parser_material_kong, "object_info_material_index: float", "_object_info_material_index"); + return "constants.object_info_material_index"; + } + else if (socket == node.outputs[3]) { // Random + node_shader_add_constant(parser_material_kong, "object_info_random: float", "_object_info_random"); + return "constants.object_info_random"; + } +} + let object_info_node_def: ui_node_t = { id: 0, name: _tr("Object Info"), diff --git a/paint/sources/material_nodes/picker_node.ts b/paint/sources/material_nodes/picker_node.ts index 447e6da2..bb1c4fa6 100644 --- a/paint/sources/material_nodes/picker_node.ts +++ b/paint/sources/material_nodes/picker_node.ts @@ -1,4 +1,38 @@ +function picker_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + if (socket == node.outputs[0]) { // Base + node_shader_add_constant(parser_material_kong, "picker_base: float3", "_picker_base"); + return "constants.picker_base"; + } + else if (socket == node.outputs[5]) { // Normal + node_shader_add_constant(parser_material_kong, "picker_normal: float3", "_picker_normal"); + return "constants.picker_normal"; + } +} + +function picker_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + if (socket == node.outputs[1]) { + node_shader_add_constant(parser_material_kong, "picker_opacity: float", "_picker_opacity"); + return "constants.picker_opacity"; + } + else if (socket == node.outputs[2]) { + node_shader_add_constant(parser_material_kong, "picker_occlusion: float", "_picker_occlusion"); + return "constants.picker_occlusion"; + } + else if (socket == node.outputs[3]) { + node_shader_add_constant(parser_material_kong, "picker_roughness: float", "_picker_roughness"); + return "constants.picker_roughness"; + } + else if (socket == node.outputs[4]) { + node_shader_add_constant(parser_material_kong, "picker_metallic: float", "_picker_metallic"); + return "constants.picker_metallic"; + } + else if (socket == node.outputs[7]) { + node_shader_add_constant(parser_material_kong, "picker_height: float", "_picker_height"); + return "constants.picker_height"; + } +} + let picker_node_def: ui_node_t = { id: 0, name: _tr("Picker"), diff --git a/paint/sources/material_nodes/quantize_node.ts b/paint/sources/material_nodes/quantize_node.ts index b16cd4af..2b615428 100644 --- a/paint/sources/material_nodes/quantize_node.ts +++ b/paint/sources/material_nodes/quantize_node.ts @@ -1,4 +1,10 @@ +function quantize_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let strength: string = parser_material_parse_value_input(node.inputs[0]); + let col: string = parser_material_parse_vector_input(node.inputs[1]); + return "(floor3(100.0 * " + strength + " * " + col + ") / (100.0 * " + strength + "))"; +} + let quantize_node_def: ui_node_t = { id: 0, name: _tr("Quantize"), diff --git a/paint/sources/material_nodes/replace_color_node.ts b/paint/sources/material_nodes/replace_color_node.ts index 26fbe1e4..949a1a56 100644 --- a/paint/sources/material_nodes/replace_color_node.ts +++ b/paint/sources/material_nodes/replace_color_node.ts @@ -1,4 +1,13 @@ +function replace_color_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let input_color: string = parser_material_parse_vector_input(node.inputs[0]); + let old_color: string = parser_material_parse_vector_input(node.inputs[1]); + let new_color: string = parser_material_parse_vector_input(node.inputs[2]); + let radius: string = parser_material_parse_value_input(node.inputs[3]); + let fuzziness: string = parser_material_parse_value_input(node.inputs[4]); + return "lerp3(" + new_color + ", " + input_color + ", clamp((distance(" + old_color + ", " + input_color + ") - " + radius + ") / max(" + fuzziness + ", " + parser_material_eps + "), 0.0, 1.0))"; +} + let replace_color_node_def: ui_node_t = { id: 0, name: _tr("Replace Color"), diff --git a/paint/sources/material_nodes/rgb_curves_node.ts b/paint/sources/material_nodes/rgb_curves_node.ts new file mode 100644 index 00000000..b879b9f3 --- /dev/null +++ b/paint/sources/material_nodes/rgb_curves_node.ts @@ -0,0 +1,15 @@ + +// else if (node.type == "CURVE_RGB") { // RGB Curves +// let fac: string = parser_material_parse_value_input(node.inputs[0]); +// let vec: string = parser_material_parse_vector_input(node.inputs[1]); +// let curves: f32_array_t = node.buttons[0].default_value; +// let name: string = parser_material_node_name(node); +// // mapping.curves[0].points[0].handle_type +// let vc0: string = parser_material_vector_curve(name + "0", vec + ".x", curves[0]); +// let vc1: string = parser_material_vector_curve(name + "1", vec + ".y", curves[1]); +// let vc2: string = parser_material_vector_curve(name + "2", vec + ".z", curves[2]); +// let vc3a: string = parser_material_vector_curve(name + "3a", vec + ".x", curves[3]); +// let vc3b: string = parser_material_vector_curve(name + "3b", vec + ".y", curves[3]); +// let vc3c: string = parser_material_vector_curve(name + "3c", vec + ".z", curves[3]); +// return "(sqrt(float3(" + vc0 + ", " + vc1 + ", " + vc2 + ") * float3(" + vc3a + ", " + vc3b + ", " + vc3c + ")) * " + fac + ")"; +// } diff --git a/paint/sources/material_nodes/rgb_node.ts b/paint/sources/material_nodes/rgb_node.ts index 772aa1ab..ea054406 100644 --- a/paint/sources/material_nodes/rgb_node.ts +++ b/paint/sources/material_nodes/rgb_node.ts @@ -1,4 +1,8 @@ +function rgb_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + return parser_material_vec3(socket.default_value); +} + let rgb_node_def: ui_node_t = { id: 0, name: _tr("RGB"), diff --git a/paint/sources/material_nodes/rgb_to_bw_node.ts b/paint/sources/material_nodes/rgb_to_bw_node.ts index 7619e53a..81154097 100644 --- a/paint/sources/material_nodes/rgb_to_bw_node.ts +++ b/paint/sources/material_nodes/rgb_to_bw_node.ts @@ -1,4 +1,9 @@ +function rgb_to_bw_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let col: string = parser_material_parse_vector_input(node.inputs[0]); + return "(((" + col + ".r * 0.3 + " + col + ".g * 0.59 + " + col + ".b * 0.11) / 3.0) * 2.5)"; +} + let rgb_to_bw_node_def: ui_node_t = { id: 0, name: _tr("RGB to BW"), diff --git a/paint/sources/material_nodes/script_node.ts b/paint/sources/material_nodes/script_node.ts index 1e145d28..8da08b64 100644 --- a/paint/sources/material_nodes/script_node.ts +++ b/paint/sources/material_nodes/script_node.ts @@ -1,4 +1,16 @@ +function script_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + if (parser_material_script_links == null) { + parser_material_script_links = map_create(); + } + let script: buffer_t = node.buttons[0].default_value; + let str: string = sys_buffer_to_string(script); + let link: string = parser_material_node_name(node); + map_set(parser_material_script_links, link, str); + node_shader_add_constant(parser_material_kong, "" + link + ": float", "_" + link); + return "constants." + link; +} + let script_node_def: ui_node_t = { id: 0, name: _tr("Script"), diff --git a/paint/sources/material_nodes/separate_hsv_node.ts b/paint/sources/material_nodes/separate_hsv_node.ts index dce40dd6..da489eae 100644 --- a/paint/sources/material_nodes/separate_hsv_node.ts +++ b/paint/sources/material_nodes/separate_hsv_node.ts @@ -1,4 +1,18 @@ +function separate_hsv_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_hue_sat); + let col: string = parser_material_parse_vector_input(node.inputs[0]); + if (socket == node.outputs[0]) { + return "rgb_to_hsv(" + col + ").r"; + } + else if (socket == node.outputs[1]) { + return "rgb_to_hsv(" + col + ").g"; + } + else if (socket == node.outputs[2]) { + return "rgb_to_hsv(" + col + ").b"; + } +} + let separate_hsv_node_def: ui_node_t = { id: 0, name: _tr("Separate HSV"), diff --git a/paint/sources/material_nodes/separate_rgb_node.ts b/paint/sources/material_nodes/separate_rgb_node.ts index ca8c9fd3..950b485d 100644 --- a/paint/sources/material_nodes/separate_rgb_node.ts +++ b/paint/sources/material_nodes/separate_rgb_node.ts @@ -1,4 +1,17 @@ +function separate_rgb_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let col: string = parser_material_parse_vector_input(node.inputs[0]); + if (socket == node.outputs[0]) { + return col + ".r"; + } + else if (socket == node.outputs[1]) { + return col + ".g"; + } + else if (socket == node.outputs[2]) { + return col + ".b"; + } +} + let separate_rgb_node_def: ui_node_t = { id: 0, name: _tr("Separate RGB"), diff --git a/paint/sources/material_nodes/separate_xyz_node.ts b/paint/sources/material_nodes/separate_xyz_node.ts index 409478e6..43841619 100644 --- a/paint/sources/material_nodes/separate_xyz_node.ts +++ b/paint/sources/material_nodes/separate_xyz_node.ts @@ -1,4 +1,17 @@ +function separate_xyz_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let vec: string = parser_material_parse_vector_input(node.inputs[0]); + if (socket == node.outputs[0]) { + return vec + ".x"; + } + else if (socket == node.outputs[1]) { + return vec + ".y"; + } + else if (socket == node.outputs[2]) { + return vec + ".z"; + } +} + let separate_xyz_node_def: ui_node_t = { id: 0, name: _tr("Separate XYZ"), diff --git a/paint/sources/material_nodes/shader_node.ts b/paint/sources/material_nodes/shader_node.ts index b408fd56..ba0792f0 100644 --- a/paint/sources/material_nodes/shader_node.ts +++ b/paint/sources/material_nodes/shader_node.ts @@ -1,4 +1,10 @@ +function shader_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let shader: buffer_t = node.buttons[0].default_value; + let str: string = sys_buffer_to_string(shader); + return str == "" ? "0.0" : str; +} + let shader_node_def: ui_node_t = { id: 0, name: _tr("Shader"), @@ -37,4 +43,3 @@ let shader_node_def: ui_node_t = { width: 0, flags: 0 }; - diff --git a/paint/sources/material_nodes/tangent_node.ts b/paint/sources/material_nodes/tangent_node.ts index 59b27ef9..21ebabb2 100644 --- a/paint/sources/material_nodes/tangent_node.ts +++ b/paint/sources/material_nodes/tangent_node.ts @@ -1,4 +1,9 @@ +function tangent_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + parser_material_kong.frag_wtangent = true; + return "input.wtangent"; +} + let tangent_node_def: ui_node_t = { id: 0, name: _tr("Tangent"), diff --git a/paint/sources/material_nodes/text_texture_node.ts b/paint/sources/material_nodes/text_texture_node.ts index 16bbd5ba..47fa6bd3 100644 --- a/paint/sources/material_nodes/text_texture_node.ts +++ b/paint/sources/material_nodes/text_texture_node.ts @@ -1,4 +1,46 @@ +function _parser_material_cache_tex_text_node(file: string, text: string) { + if (map_get(data_cached_images, file) == null) { + sys_notify_on_next_frame(function(text: string) { + let _text_tool_text: string = context_raw.text_tool_text; + let _text_tool_image: gpu_texture_t = context_raw.text_tool_image; + context_raw.text_tool_text = text; + context_raw.text_tool_image = null; + + util_render_make_text_preview(); + let file: string = "tex_text_" + text; + + // TODO: remove old cache + map_set(data_cached_images, file, context_raw.text_tool_image); + + context_raw.text_tool_text = _text_tool_text; + context_raw.text_tool_image = _text_tool_image; + }, text); + } +} + +function text_texture_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let tex_name: string = parser_material_node_name(node); + let text_buffer: buffer_t = node.buttons[0].default_value; + let text: string = sys_buffer_to_string(text_buffer); + let file: string = "tex_text_" + text; + _parser_material_cache_tex_text_node(file, text); + let tex: bind_tex_t = parser_material_make_bind_tex(tex_name, file); + let texstore: string = parser_material_texture_store(node, tex, tex_name, color_space_t.AUTO); + return texstore + ".rrr"; +} + +function text_texture_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let tex_name: string = parser_material_node_name(node); + let text_buffer: buffer_t = node.buttons[0].default_value; + let text: string = sys_buffer_to_string(text_buffer); + let file: string = "tex_text_" + text; + _parser_material_cache_tex_text_node(file, text); + let tex: bind_tex_t = parser_material_make_bind_tex(tex_name, file); + let texstore: string = parser_material_texture_store(node, tex, tex_name, color_space_t.AUTO); + return texstore + ".r"; +} + let text_texture_node_def: ui_node_t = { id: 0, name: _tr("Text Texture"), diff --git a/paint/sources/material_nodes/texture_coordinate_node.ts b/paint/sources/material_nodes/texture_coordinate_node.ts index 4cbb28aa..028b6a4e 100644 --- a/paint/sources/material_nodes/texture_coordinate_node.ts +++ b/paint/sources/material_nodes/texture_coordinate_node.ts @@ -1,4 +1,34 @@ +function texture_coordinate_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + if (socket == node.outputs[0]) { // Generated - bounds + parser_material_kong.frag_bposition = true; + return "bposition"; + } + else if (socket == node.outputs[1]) { // Normal + parser_material_kong.frag_n = true; + return "n"; + } + else if (socket == node.outputs[2]) {// UV + node_shader_context_add_elem(parser_material_kong.context, "tex", "short2norm"); + return "float3(tex_coord.x, tex_coord.y, 0.0)"; + } + else if (socket == node.outputs[3]) { // Object + parser_material_kong.frag_mposition = true; + return "input.mposition"; + } + else if (socket == node.outputs[4]) { // Camera + parser_material_kong.frag_vposition = true; + return "input.vposition"; + } + else if (socket == node.outputs[5]) { // Window + parser_material_kong.frag_wvpposition = true; + return "input.wvpposition.xyz"; + } + else if (socket == node.outputs[6]) { // Reflection + return "float3(0.0, 0.0, 0.0)"; + } +} + let texture_coordinate_node_def: ui_node_t = { id: 0, name: _tr("Texture Coordinate"), diff --git a/paint/sources/material_nodes/uv_map_node.ts b/paint/sources/material_nodes/uv_map_node.ts index b93b8813..644734a6 100644 --- a/paint/sources/material_nodes/uv_map_node.ts +++ b/paint/sources/material_nodes/uv_map_node.ts @@ -1,4 +1,9 @@ +function uv_map_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_context_add_elem(parser_material_kong.context, "tex", "short2norm"); + return "float3(tex_coord.x, tex_coord.y, 0.0)"; +} + let uv_map_node_def: ui_node_t = { id: 0, name: _tr("UV Map"), diff --git a/paint/sources/material_nodes/value_node.ts b/paint/sources/material_nodes/value_node.ts index 4cfbd311..c5d3d145 100644 --- a/paint/sources/material_nodes/value_node.ts +++ b/paint/sources/material_nodes/value_node.ts @@ -1,4 +1,8 @@ +function value_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + return parser_material_vec1(node.outputs[0].default_value[0]); +} + let value_node_def: ui_node_t = { id: 0, name: _tr("Value"), diff --git a/paint/sources/material_nodes/vector_curves_node.ts b/paint/sources/material_nodes/vector_curves_node.ts index 137f8691..ee44ab46 100644 --- a/paint/sources/material_nodes/vector_curves_node.ts +++ b/paint/sources/material_nodes/vector_curves_node.ts @@ -1,4 +1,55 @@ +function parser_material_vector_curve(name: string, fac: string, points: f32_ptr, num: i32): string { + // Write Ys array + let ys_var: string = name + "_ys"; + parser_material_write(parser_material_kong, "var " + ys_var + ": float[" + num + "];"); // TODO: Make const + for (let i: i32 = 0; i < num; ++i) { + let p: f32 = ARRAY_ACCESS(points, i * 2 + 1); + parser_material_write(parser_material_kong, ys_var + "[" + i + "] = " + p + ";"); + } + // Get index + let fac_var: string = name + "_fac"; + parser_material_write(parser_material_kong, "var " + fac_var + ": float = " + fac + ";"); + let index: string = "0"; + for (let i: i32 = 1; i < num; ++i) { + let p: f32 = ARRAY_ACCESS(points, i * 2 + 0); + index += " + (" + fac_var + " > " + p + " ? 1 : 0)"; + } + // Write index + let index_var: string = name + "_i"; + parser_material_write(parser_material_kong, "var " + index_var + ": int = " + index + ";"); + // Linear + // Write Xs array + let facs_var: string = name + "_xs"; + parser_material_write(parser_material_kong, "var " + facs_var + ": float[" + num + "];"); // TODO: Make const + for (let i: i32 = 0; i < num; ++i) { + let p: f32 = ARRAY_ACCESS(points, i * 2 + 0); + parser_material_write(parser_material_kong, "" + facs_var + "[" + i + "] = " + p + ";"); + } + // Map vector + return "0.0"; //// + // return "lerp(" + + // ys_var + "[" + index_var + "], " + ys_var + "[" + index_var + " + 1], (" + fac_var + " - " + + // facs_var + "[" + index_var + "]) * (1.0 / (" + facs_var + "[" + index_var + " + 1] - " + facs_var + "[" + index_var + "])))"; +} + +function vector_curves_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let fac: string = parser_material_parse_value_input(node.inputs[0]); + let vec: string = parser_material_parse_vector_input(node.inputs[1]); + let curves: f32_array_t = node.buttons[0].default_value; + if (curves[96] == 0.0) { + curves[96] = 1.0; + curves[97] = 1.0; + curves[98] = 1.0; + } + let name: string = parser_material_node_name(node); + let vc0: string = parser_material_vector_curve(name + "0", vec + ".x", curves.buffer + 32 * 0, curves[96]); + let vc1: string = parser_material_vector_curve(name + "1", vec + ".y", curves.buffer + 32 * 1, curves[97]); + let vc2: string = parser_material_vector_curve(name + "2", vec + ".z", curves.buffer + 32 * 2, curves[98]); + // mapping.curves[0].points[0].handle_type // bezier curve + return "(float3(" + vc0 + ", " + vc1 + ", " + vc2 + ") * " + fac + ")"; +} + let vector_curves_node_def: ui_node_t = { id: 0, name: _tr("Vector Curves"), diff --git a/paint/sources/material_nodes/vector_math2_node.ts b/paint/sources/material_nodes/vector_math2_node.ts index 3e329110..d87e6b5f 100644 --- a/paint/sources/material_nodes/vector_math2_node.ts +++ b/paint/sources/material_nodes/vector_math2_node.ts @@ -1,4 +1,109 @@ +function vector_math2_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + let vec1: string = parser_material_parse_vector_input(node.inputs[0]); + let vec2: string = parser_material_parse_vector_input(node.inputs[1]); + let but: ui_node_button_t = node.buttons[0]; //operation; + let op: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); + op = string_replace_all(op, " ", "_"); + if (op == "ADD") { + return "(" + vec1 + " + " + vec2 + ")"; + } + else if (op == "SUBTRACT") { + return "(" + vec1 + " - " + vec2 + ")"; + } + else if (op == "AVERAGE") { + return "((" + vec1 + " + " + vec2 + ") / 2.0)"; + } + else if (op == "DOT_PRODUCT") { + return parser_material_to_vec3("dot(" + vec1 + ", " + vec2 + ")"); + } + else if (op == "LENGTH") { + return parser_material_to_vec3("length(" + vec1 + ")"); + } + else if (op == "DISTANCE") { + return parser_material_to_vec3("distance(" + vec1 + ", " + vec2 + ")"); + } + else if (op == "CROSS_PRODUCT") { + return "cross(" + vec1 + ", " + vec2 + ")"; + } + else if (op == "NORMALIZE") { + return "normalize(" + vec1 + ")"; + } + else if (op == "MULTIPLY") { + return "(" + vec1 + " * " + vec2 + ")"; + } + else if (op == "DIVIDE") { + let store: string = parser_material_store_var_name(node) + "_vec2"; + parser_material_write(parser_material_kong, "var " + store + ": float3 = " + vec2 + ";"); + parser_material_write(parser_material_kong, "if (" + store + ".x == 0.0) { " + store + ".x = 0.000001; }"); + parser_material_write(parser_material_kong, "if (" + store + ".y == 0.0) { " + store + ".y = 0.000001; }"); + parser_material_write(parser_material_kong, "if (" + store + ".z == 0.0) { " + store + ".z = 0.000001; }"); + return "(" + vec1 + " / " + vec2 + ")"; + } + else if (op == "PROJECT") { + return "(dot(" + vec1 + ", " + vec2 + ") / dot(" + vec2 + ", " + vec2 + ") * " + vec2 + ")"; + } + else if (op == "REFLECT") { + return "reflect(" + vec1 + ", normalize(" + vec2 + "))"; + } + else if (op == "SCALE") { + return "(" + vec2 + ".x * " + vec1 + ")"; + } + else if (op == "ABSOLUTE") { + return "abs3(" + vec1 + ")"; + } + else if (op == "MINIMUM") { + return "min3(" + vec1 + ", " + vec2 + ")"; + } + else if (op == "MAXIMUM") { + return "max3(" + vec1 + ", " + vec2 + ")"; + } + else if (op == "FLOOR") { + return "floor3(" + vec1 + ")"; + } + else if (op == "CEIL") { + return "ceil3(" + vec1 + ")"; + } + else if (op == "FRACTION") { + return "frac3(" + vec1 + ")"; + } + else if (op == "MODULO") { + return "(" + vec1 + " % " + vec2 + ")"; + } + else if(op == "SNAP") { + return "(floor3(" + vec1 + " / " + vec2 + ") * " + vec2 + ")"; + } + else if (op == "SINE") { + return "float3(sin(" + vec1 + ".x), sin(" + vec1 + ".y), sin(" + vec1 + ".z))"; + } + else if (op == "COSINE") { + return "float3(cos(" + vec1 + ".x), cos(" + vec1 + ".y), cos(" + vec1 + ".z))"; + } + else if (op == "TANGENT") { + return "float3(tan(" + vec1 + ".x), tan(" + vec1 + ".y), tan(" + vec1 + ".z))"; + } +} + +function vector_math2_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + let vec1: string = parser_material_parse_vector_input(node.inputs[0]); + let vec2: string = parser_material_parse_vector_input(node.inputs[1]); + let but: ui_node_button_t = node.buttons[0]; //operation; + let op: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); + op = string_replace_all(op, " ", "_"); + if (op == "DOT_PRODUCT") { + return "dot(" + vec1 + ", " + vec2 + ")"; + } + else if (op == "LENGTH") { + return "length(" + vec1 + ")"; + } + else if (op == "DISTANCE") { + return "distance(" + vec1 + ", " + vec2 + ")"; + } + else { + return "0.0"; + } +} + let vector_math2_node_def: ui_node_t = { id: 0, name: _tr("Vector Math"), diff --git a/paint/sources/material_nodes/vector_transform_node.ts b/paint/sources/material_nodes/vector_transform_node.ts new file mode 100644 index 00000000..119f6102 --- /dev/null +++ b/paint/sources/material_nodes/vector_transform_node.ts @@ -0,0 +1,9 @@ + + +// else if (node.type == "VECT_TRANSFORM") { +// type = node.vector_type +// conv_from = node.convert_from +// conv_to = node.convert_to +// // Pass throuh +// return parse_vector_input(node.inputs[0]) +// } diff --git a/paint/sources/material_nodes/vertex_color_node.ts b/paint/sources/material_nodes/vertex_color_node.ts index 1721764b..9132615c 100644 --- a/paint/sources/material_nodes/vertex_color_node.ts +++ b/paint/sources/material_nodes/vertex_color_node.ts @@ -1,4 +1,18 @@ +function vertex_color_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + if (parser_material_kong.context.allow_vcols) { + node_shader_context_add_elem(parser_material_kong.context, "col", "short4norm"); + return "input.vcolor"; + } + else { + return("float3(0.0, 0.0, 0.0)"); + } +} + +function vertex_color_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + return "1.0"; +} + let vertex_color_node_def: ui_node_t = { id: 0, name: _tr("Vertex Color"), diff --git a/paint/sources/material_nodes/voronoi_texture_node.ts b/paint/sources/material_nodes/voronoi_texture_node.ts index b1d083ef..b099f20a 100644 --- a/paint/sources/material_nodes/voronoi_texture_node.ts +++ b/paint/sources/material_nodes/voronoi_texture_node.ts @@ -1,4 +1,69 @@ +let str_tex_voronoi: string = "\ +fun tex_voronoi(x: float3): float4 { \ + var p: float3 = floor3(x); \ + var f: float3 = frac3(x); \ + var id: float = 0.0; \ + var res: float = 100.0; \ + for (var k: int = 0; k <= 2; k += 1) \ + for (var j: int = 0; j <= 2; j += 1) \ + for (var i: int = 0; i <= 2; i += 1) { \ + var b: float3 = float3(float(i - 1), float(j - 1), float(k - 1)); \ + var pb: float3 = p + b; \ + var snoise_sample: float3 = sample(snoise256, sampler_linear, (pb.xy + float2(3.0, 1.0) * pb.z + 0.5) / 256.0).xyz; \ + var r: float3 = b - f + snoise_sample; \ + var d: float = dot(r, r); \ + if (d < res) { \ + id = dot(p + b, float3(1.0, 57.0, 113.0)); \ + res = d; \ + } \ + } \ + /*var col: float3 = 0.5 + 0.5 * cos(id * 0.35 + float3(0.0, 1.0, 2.0));*/ \ + var col: float3; \ + col.x = 0.5 + 0.5 * cos(id * 0.35 + 0.0); \ + col.y = 0.5 + 0.5 * cos(id * 0.35 + 1.0); \ + col.z = 0.5 + 0.5 * cos(id * 0.35 + 2.0); \ + return float4(col, sqrt(res)); \ +} \ +"; + +function voronoi_texture_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_voronoi); + node_shader_add_texture(parser_material_kong, "snoise256", "$noise256.k"); + let co: string = parser_material_get_coord(node); + let scale: string = parser_material_parse_value_input(node.inputs[1]); + let but: ui_node_button_t = node.buttons[0]; //coloring; + let coloring: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); + coloring = string_replace_all(coloring, " ", "_"); + let res: string = ""; + if (coloring == "INTENSITY") { + let voronoi: string = "tex_voronoi(" + co + " * " + scale + ").a"; + res = parser_material_to_vec3(voronoi); + } + else { // Cells + res = "tex_voronoi(" + co + " * " + scale + ").rgb"; + } + return res; +} + +function voronoi_texture_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_voronoi); + node_shader_add_texture(parser_material_kong, "snoise256", "$noise256.k"); + let co: string = parser_material_get_coord(node); + let scale: string = parser_material_parse_value_input(node.inputs[1]); + let but: ui_node_button_t = node.buttons[0]; // coloring + let coloring: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); + coloring = string_replace_all(coloring, " ", "_"); + let res: string = ""; + if (coloring == "INTENSITY") { + res = "tex_voronoi(" + co + " * " + scale + ").a"; + } + else { // Cells + res = "tex_voronoi(" + co + " * " + scale + ").r"; + } + return res; +} + let voronoi_texture_node_def: ui_node_t = { id: 0, name: _tr("Voronoi Texture"), diff --git a/paint/sources/material_nodes/warp_node.ts b/paint/sources/material_nodes/warp_node.ts index 455628d0..957d9571 100644 --- a/paint/sources/material_nodes/warp_node.ts +++ b/paint/sources/material_nodes/warp_node.ts @@ -1,4 +1,20 @@ +function warp_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + if (parser_material_warp_passthrough) { + return parser_material_parse_vector_input(node.inputs[0]); + } + let angle: string = parser_material_parse_value_input(node.inputs[1], true); + let mask: string = parser_material_parse_value_input(node.inputs[2], true); + let tex_name: string = "texwarp_" + parser_material_node_name(node); + node_shader_add_texture(parser_material_kong, "" + tex_name, "_" + tex_name); + let store: string = parser_material_store_var_name(node); + let pi: f32 = math_pi(); + parser_material_write(parser_material_kong, "var " + store + "_rad: float = " + angle + " * (" + pi + " / 180.0);"); + parser_material_write(parser_material_kong, "var " + store + "_x: float = cos(" + store + "_rad);"); + parser_material_write(parser_material_kong, "var " + store + "_y: float = sin(" + store + "_rad);"); + return "sample(" + tex_name + ", sampler_linear, tex_coord + float2(" + store + "_x, " + store + "_y) * " + mask + ").rgb"; +} + let warp_node_def: ui_node_t = { id: 0, name: _tr("Warp"), diff --git a/paint/sources/material_nodes/wave_texture_node.ts b/paint/sources/material_nodes/wave_texture_node.ts index 21e7bda6..3a3f1821 100644 --- a/paint/sources/material_nodes/wave_texture_node.ts +++ b/paint/sources/material_nodes/wave_texture_node.ts @@ -1,4 +1,26 @@ +let str_tex_wave: string = "\ +fun tex_wave_f(p: float3): float { \ + return 1.0 - sin((p.x + p.y) * 10.0); \ +} \ +"; + +function wave_texture_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_wave); + let co: string = parser_material_get_coord(node); + let scale: string = parser_material_parse_value_input(node.inputs[1]); + let res: string = parser_material_to_vec3("tex_wave_f(" + co + " * " + scale + ")"); + return res; +} + +function wave_texture_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_function(parser_material_kong, str_tex_wave); + let co: string = parser_material_get_coord(node); + let scale: string = parser_material_parse_value_input(node.inputs[1]); + let res: string = "tex_wave_f(" + co + " * " + scale + ")"; + return res; +} + let wave_texture_node_def: ui_node_t = { id: 0, name: _tr("Wave Texture"), diff --git a/paint/sources/material_nodes/wavelength_node.ts b/paint/sources/material_nodes/wavelength_node.ts new file mode 100644 index 00000000..17a95067 --- /dev/null +++ b/paint/sources/material_nodes/wavelength_node.ts @@ -0,0 +1,14 @@ + +// let str_wavelength_to_rgb: string = "\ +// fun wavelength_to_rgb(t: float): float3 { \ +// var r: float3 = t * 2.1 - float3(1.8, 1.14, 0.3); \ +// return 1.0 - r * r; \ +// } \ +// "; + +// else if (node.type == "WAVELENGTH") { +// node_shader_add_function(parser_material_kong, str_wavelength_to_rgb); +// let wl: string = parser_material_parse_value_input(node.inputs[0]); +// node_shader_add_function(parser_material_kong, str_wavelength_to_rgb); +// return "wavelength_to_rgb((" + wl + " - 450.0) / 150.0)"; +// } diff --git a/paint/sources/material_nodes/wireframe_node.ts b/paint/sources/material_nodes/wireframe_node.ts index 9bf12847..8204e7c8 100644 --- a/paint/sources/material_nodes/wireframe_node.ts +++ b/paint/sources/material_nodes/wireframe_node.ts @@ -1,4 +1,11 @@ +function wireframe_node_value(node: ui_node_t, socket: ui_node_socket_t): string { + node_shader_add_texture(parser_material_kong, "texuvmap", "_texuvmap"); + // let use_pixel_size: bool = node.buttons[0].default_value[0] > 0.0; + // let pixel_size: f32 = parse_value_input(node.inputs[0]); + return "sample_lod(texuvmap, sampler_linear, tex_coord, 0.0).r"; +} + let wireframe_node_def: ui_node_t = { id: 0, name: _tr("Wireframe"), diff --git a/paint/sources/nodes_material.ts b/paint/sources/nodes_material.ts index 12083594..c6f03f37 100644 --- a/paint/sources/nodes_material.ts +++ b/paint/sources/nodes_material.ts @@ -138,6 +138,86 @@ function nodes_material_list_init() { // nodes_material_neural, nodes_material_group ]; + + map_set(parser_material_node_vectors, "ATTRIBUTE", attribute_node_vector); + map_set(parser_material_node_values, "ATTRIBUTE", attribute_node_value); + map_set(parser_material_node_vectors, "BLUR", blur_node_vector); + map_set(parser_material_node_vectors, "TEX_BRICK", brick_texture_node_vector); + map_set(parser_material_node_values, "TEX_BRICK", brick_texture_node_value); + map_set(parser_material_node_values, "BRIGHTCONTRAST", brightness_contrast_node_value); + map_set(parser_material_node_vectors, "BUMP", bump_node_vector); + map_set(parser_material_node_vectors, "CAMERA", camera_data_node_vector); + map_set(parser_material_node_values, "CAMERA", camera_data_node_value); + map_set(parser_material_node_vectors, "TEX_CHECKER", checker_texture_node_vector); + map_set(parser_material_node_values, "TEX_CHECKER", checker_texture_node_value); + map_set(parser_material_node_values, "CLAMP", clamp_node_value); + map_set(parser_material_node_values, "COLMASK", color_mask_node_value); + map_set(parser_material_node_vectors, "VALTORGB", color_ramp_node_vector); + map_set(parser_material_node_vectors, "COMBHSV", combine_hsv_node_vector); + map_set(parser_material_node_vectors, "COMBRGB", combine_rgb_node_vector); + map_set(parser_material_node_vectors, "COMBXYZ", combine_xyz_node_vector); + map_set(parser_material_node_values, "BAKE_CURVATURE", curvature_bake_node_value); + map_set(parser_material_node_values, "FRESNEL", fresnel_node_value); + map_set(parser_material_node_vectors, "GAMMA", gamma_node_vector); + map_set(parser_material_node_vectors, "NEW_GEOMETRY", geometry_node_vector); + map_set(parser_material_node_values, "NEW_GEOMETRY", geometry_node_value); + map_set(parser_material_node_vectors, "TEX_GRADIENT", gradient_texture_node_vector); + map_set(parser_material_node_values, "TEX_GRADIENT", gradient_texture_node_value); + map_set(parser_material_node_vectors, "GROUP", group_node_vector); + map_set(parser_material_node_values, "GROUP", group_node_value); + map_set(parser_material_node_vectors, "HUE_SAT", hue_saturation_node_vector); + map_set(parser_material_node_vectors, "TEX_IMAGE", image_texture_node_vector); + map_set(parser_material_node_values, "TEX_IMAGE", image_texture_node_value); + map_set(parser_material_node_vectors, "INVERT", invert_node_vector); + map_set(parser_material_node_values, "LAYER_MASK", layer_mask_node_value); + map_set(parser_material_node_vectors, "LAYER", layer_node_vector); + map_set(parser_material_node_values, "LAYER", layer_node_value); + map_set(parser_material_node_values, "LAYER_WEIGHT", layer_weight_node_value); + map_set(parser_material_node_vectors, "TEX_MAGIC", magic_texture_node_vector); + map_set(parser_material_node_values, "TEX_MAGIC", magic_texture_node_value); + map_set(parser_material_node_values, "MAPRANGE", map_range_node_value); + map_set(parser_material_node_vectors, "MAPPING", mapping_node_vector); + map_set(parser_material_node_vectors, "MATERIAL", material_node_vector); + map_set(parser_material_node_values, "MATERIAL", material_node_value); + map_set(parser_material_node_values, "MATH", math2_node_value); + map_set(parser_material_node_vectors, "MIX_RGB", mix_color_node_vector); + map_set(parser_material_node_vectors, "MIX_NORMAL_MAP", mix_normal_map_node_vector); + map_set(parser_material_node_values, "TEX_MUSGRAVE", musgrave_node_value); + map_set(parser_material_node_vectors, "TEX_NOISE", noise_texture_node_vector); + map_set(parser_material_node_values, "TEX_NOISE", noise_texture_node_value); + map_set(parser_material_node_vectors, "NORMAL_MAP", normal_map_node_vector); + map_set(parser_material_node_vectors, "NORMAL", normal_node_vector); + map_set(parser_material_node_values, "NORMAL", normal_node_value); + map_set(parser_material_node_vectors, "OBJECT_INFO", object_info_node_vector); + map_set(parser_material_node_values, "OBJECT_INFO", object_info_node_value); + map_set(parser_material_node_vectors, "PICKER", picker_node_vector); + map_set(parser_material_node_values, "PICKER", picker_node_value); + map_set(parser_material_node_vectors, "QUANTIZE", quantize_node_vector); + map_set(parser_material_node_vectors, "REPLACECOL", replace_color_node_vector); + map_set(parser_material_node_vectors, "RGB", rgb_node_vector); + map_set(parser_material_node_values, "RGBTOBW", rgb_to_bw_node_value); + map_set(parser_material_node_values, "SCRIPT_CPU", script_node_value); + map_set(parser_material_node_values, "SEPHSV", separate_hsv_node_value); + map_set(parser_material_node_values, "SEPRGB", separate_rgb_node_value); + map_set(parser_material_node_values, "SEPXYZ", separate_xyz_node_value); + map_set(parser_material_node_values, "SHADER_GPU", shader_node_value); + map_set(parser_material_node_vectors, "TANGENT", tangent_node_vector); + map_set(parser_material_node_vectors, "TEX_TEXT", text_texture_node_vector); + map_set(parser_material_node_values, "TEX_TEXT", text_texture_node_value); + map_set(parser_material_node_vectors, "TEX_COORD", texture_coordinate_node_vector); + map_set(parser_material_node_vectors, "UVMAP", uv_map_node_vector); + map_set(parser_material_node_values, "VALUE", value_node_value); + map_set(parser_material_node_vectors, "CURVE_VEC", vector_curves_node_vector); + map_set(parser_material_node_vectors, "VECT_MATH", vector_math2_node_vector); + map_set(parser_material_node_values, "VECT_MATH", vector_math2_node_value); + map_set(parser_material_node_vectors, "VERTEX_COLOR", vertex_color_node_vector); + map_set(parser_material_node_values, "VERTEX_COLOR", vertex_color_node_value); + map_set(parser_material_node_vectors, "TEX_VORONOI", voronoi_texture_node_vector); + map_set(parser_material_node_values, "TEX_VORONOI", voronoi_texture_node_value); + map_set(parser_material_node_vectors, "DIRECT_WARP", warp_node_vector); + map_set(parser_material_node_vectors, "TEX_WAVE", wave_texture_node_vector); + map_set(parser_material_node_values, "TEX_WAVE", wave_texture_node_value); + map_set(parser_material_node_values, "WIREFRAME", wireframe_node_value); } function nodes_material_vector_curves_button(node_id: i32) { diff --git a/paint/sources/parser_material.ts b/paint/sources/parser_material.ts index c06ec222..92b635d1 100644 --- a/paint/sources/parser_material.ts +++ b/paint/sources/parser_material.ts @@ -1,35 +1,28 @@ -// // This module builds upon Cycles nodes work licensed as // Copyright 2011-2013 Blender Foundation -// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// // http://www.apache.org/licenses/LICENSE-2.0 -// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -// let parser_material_con: node_shader_context_t; let parser_material_kong: node_shader_t; -let parser_material_kong: node_shader_t; let parser_material_matcon: material_context_t; let parser_material_parsed: string[]; let parser_material_parents: ui_node_t[]; - let parser_material_canvases: ui_node_canvas_t[]; let parser_material_nodes: ui_node_t[]; let parser_material_links: ui_node_link_t[]; - let parser_material_cotangent_frame_written: bool; let parser_material_tex_coord: string = "tex_coord"; let parser_material_eps: f32 = 0.000001; - +let parser_material_node_values: map_t = map_create(); +let parser_material_node_vectors: map_t = map_create(); let parser_material_custom_nodes: map_t = map_create(); // JSValue -> (n: ui_node_t, s: string)=>string let parser_material_parse_surface: bool = true; let parser_material_parse_opacity: bool = true; @@ -42,24 +35,18 @@ let parser_material_triplanar: bool = false; // Sample using tex_coord/1/2 & tex let parser_material_sample_keep_aspect: bool = false; // Adjust uvs to preserve texture aspect ratio let parser_material_sample_uv_scale: string = "1.0"; let parser_material_transform_color_space: bool = true; - let parser_material_blur_passthrough: bool = false; let parser_material_warp_passthrough: bool = false; let parser_material_bake_passthrough: bool = false; -let parser_material_bake_passthrough_strength: string = "0.0"; -let parser_material_bake_passthrough_radius: string = "0.0"; -let parser_material_bake_passthrough_offset: string = "0.0"; let parser_material_start_group: ui_node_canvas_t = null; let parser_material_start_parents: ui_node_t[] = null; let parser_material_start_node: ui_node_t = null; - let parser_material_arm_export_tangents: bool = true; let parser_material_out_normaltan: string; // Raw tangent space normal parsed from normal map - let parser_material_script_links: map_t = null; - let parser_material_parsed_map: map_t = map_create(); let parser_material_texture_map: map_t = map_create(); +let parser_material_is_frag: bool = true; function parser_material_get_node(id: i32): ui_node_t { for (let i: i32 = 0; i < parser_material_nodes.length; ++i) { @@ -71,16 +58,6 @@ function parser_material_get_node(id: i32): ui_node_t { return null; } -function parser_material_get_link(id: i32): ui_node_link_t { - for (let i: i32 = 0; i < parser_material_links.length; ++i) { - let l: ui_node_link_t = parser_material_links[i]; - if (l.id == id) { - return l; - } - } - return null; -} - function parser_material_get_input_link(inp: ui_node_socket_t): ui_node_link_t { for (let i: i32 = 0; i < parser_material_links.length; ++i) { let l: ui_node_link_t = parser_material_links[i]; @@ -97,26 +74,6 @@ function parser_material_get_input_link(inp: ui_node_socket_t): ui_node_link_t { return null; } -function parser_material_get_output_links(out: ui_node_socket_t): ui_node_link_t[] { - let ls: ui_node_link_t[] = null; - for (let i: i32 = 0; i < parser_material_links.length; ++i) { - let l: ui_node_link_t = parser_material_links[i]; - if (l.from_id == out.node_id) { - let node: ui_node_t = parser_material_get_node(out.node_id); - if (node.outputs.length <= l.from_socket) { - continue; - } - if (node.outputs[l.from_socket] == out) { - if (ls == null) { - ls = []; - } - array_push(ls, l); - } - } - } - return ls; -} - function parser_material_init() { parser_material_parsed = []; parser_material_parents = []; @@ -272,7 +229,6 @@ function parser_material_parse_output(node: ui_node_t): shader_out_t { return parser_material_parse_shader_input(node.inputs[0]); } return null; - // Parse volume, displacement.. } function parser_material_parse_output_pbr(node: ui_node_t): shader_out_t { @@ -280,7 +236,6 @@ function parser_material_parse_output_pbr(node: ui_node_t): shader_out_t { return parser_material_parse_shader(node, null); } return null; - // Parse volume, displacement.. } function parser_material_get_group(name: string): ui_node_canvas_t { @@ -352,9 +307,6 @@ function parser_material_parse_shader_input(inp: ui_node_socket_t): shader_out_t let l: ui_node_link_t = parser_material_get_input_link(inp); let from_node: ui_node_t = l != null ? parser_material_get_node(l.from_id) : null; if (from_node != null) { - if (from_node.type == "REROUTE") { - return parser_material_parse_shader_input(from_node.inputs[0]); - } return parser_material_parse_shader(from_node, from_node.outputs[l.from_socket]); } else { @@ -413,7 +365,7 @@ function parser_material_parse_shader(node: ui_node_t, socket: ui_node_socket_t) } // Displacement / Height - if (node.inputs.length > 7 && parser_material_parse_height) { + if (parser_material_parse_height) { if (!parser_material_parse_height_as_channel) { parser_material_is_frag = false; } @@ -427,8 +379,6 @@ function parser_material_parse_shader(node: ui_node_t, socket: ui_node_socket_t) return sout; } -let parser_material_is_frag: bool = true; - function parser_material_write(raw: node_shader_t, s: string) { if (parser_material_is_frag) { node_shader_write_frag(raw, s); @@ -442,768 +392,28 @@ function parser_material_parse_vector_input(inp: ui_node_socket_t): string { let l: ui_node_link_t = parser_material_get_input_link(inp); let from_node: ui_node_t = l != null ? parser_material_get_node(l.from_id) : null; if (from_node != null) { - if (from_node.type == "REROUTE") { - return parser_material_parse_vector_input(from_node.inputs[0]); - } - let res_var: string = parser_material_write_result(l); let st: string = from_node.outputs[l.from_socket].type; if (st == "RGB" || st == "RGBA" || st == "VECTOR") { return res_var; } - else {// VALUE + else { // VALUE return parser_material_to_vec3(res_var); } } else { - if (inp.type == "VALUE") { // Unlinked reroute - return parser_material_vec3(f32_array_create_xyz(0.0, 0.0, 0.0)); - } - else { - return parser_material_vec3(inp.default_value); - } - } -} - -function _parser_material_cache_tex_text_node(file: string, text: string) { - if (map_get(data_cached_images, file) == null) { - sys_notify_on_next_frame(function(text: string) { - let _text_tool_text: string = context_raw.text_tool_text; - let _text_tool_image: gpu_texture_t = context_raw.text_tool_image; - context_raw.text_tool_text = text; - context_raw.text_tool_image = null; - - util_render_make_text_preview(); - let file: string = "tex_text_" + text; - - // TODO: remove old cache - map_set(data_cached_images, file, context_raw.text_tool_image); - - context_raw.text_tool_text = _text_tool_text; - context_raw.text_tool_image = _text_tool_image; - }, text); + return parser_material_vec3(inp.default_value); } } function parser_material_parse_vector(node: ui_node_t, socket: ui_node_socket_t): string { - if (node.type == "GROUP") { - return parser_material_parse_group(node, socket); + let node_vector: (node: ui_node_t, socket: ui_node_socket_t)=>string = map_get(parser_material_node_vectors, node.type); + if (node_vector != null) { + return node_vector(node, socket); } else if (node.type == "GROUP_INPUT") { return parser_material_parse_group_input(node, socket); } - else if (node.type == "ATTRIBUTE") { - if (socket == node.outputs[0]) { // Color - if (parser_material_kong.context.allow_vcols) { - node_shader_context_add_elem(parser_material_kong.context, "col", "short4norm"); // Vcols only for now - return "input.vcolor"; - } - else { - return("float3(0.0, 0.0, 0.0)"); - } - } - else { // Vector - node_shader_context_add_elem(parser_material_kong.context, "tex", "short2norm"); // UVMaps only for now - return "float3(tex_coord.x, tex_coord.y, 0.0)"; - } - } - else if (node.type == "VERTEX_COLOR") { - if (parser_material_kong.context.allow_vcols) { - node_shader_context_add_elem(parser_material_kong.context, "col", "short4norm"); - return "input.vcolor"; - } - else { - return("float3(0.0, 0.0, 0.0)"); - } - - } - else if (node.type == "RGB") { - return parser_material_vec3(socket.default_value); - } - else if (node.type == "TEX_BRICK") { - node_shader_add_function(parser_material_kong, str_tex_brick); - let co: string = parser_material_get_coord(node); - let col1: string = parser_material_parse_vector_input(node.inputs[1]); - let col2: string = parser_material_parse_vector_input(node.inputs[2]); - let col3: string = parser_material_parse_vector_input(node.inputs[3]); - let scale: string = parser_material_parse_value_input(node.inputs[4]); - let res: string = "tex_brick(" + co + " * " + scale + ", " + col1 + ", " + col2 + ", " + col3 + ")"; - return res; - } - else if (node.type == "TEX_CHECKER") { - node_shader_add_function(parser_material_kong, str_tex_checker); - let co: string = parser_material_get_coord(node); - let col1: string = parser_material_parse_vector_input(node.inputs[1]); - let col2: string = parser_material_parse_vector_input(node.inputs[2]); - let scale: string = parser_material_parse_value_input(node.inputs[3]); - let res: string = "tex_checker(" + co + ", " + col1 + ", " + col2 + ", " + scale + ")"; - return res; - } - else if (node.type == "TEX_GRADIENT") { - let co: string = parser_material_get_coord(node); - let but: ui_node_button_t = node.buttons[0]; //gradient_type; - let grad: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); - grad = string_replace_all(grad, " ", "_"); - let f: string = parser_material_get_gradient(grad, co); - let res: string = parser_material_to_vec3("clamp(" + f + ", 0.0, 1.0)"); - return res; - } - else if (node.type == "TEX_IMAGE") { - // Already fetched - if (array_index_of(parser_material_parsed, parser_material_res_var_name(node, node.outputs[1])) >= 0) { // TODO: node.outputs[0] - let varname: string = parser_material_store_var_name(node); - return varname + ".rgb"; - } - let tex_name: string = parser_material_node_name(node); - let tex: bind_tex_t = parser_material_make_texture(node, tex_name); - if (tex != null) { - let color_space: i32 = node.buttons[1].default_value[0]; - let texstore: string = parser_material_texture_store(node, tex, tex_name, color_space); - return texstore + ".rgb"; - } - else { - let tex_store: string = parser_material_store_var_name(node); // Pink color for missing texture - parser_material_write(parser_material_kong, "var " + tex_store + ": float4 = float4(1.0, 0.0, 1.0, 1.0);"); - return tex_store + ".rgb"; - } - } - else if (node.type == "TEX_TEXT") { - let tex_name: string = parser_material_node_name(node); - let text_buffer: buffer_t = node.buttons[0].default_value; - let text: string = sys_buffer_to_string(text_buffer); - let file: string = "tex_text_" + text; - _parser_material_cache_tex_text_node(file, text); - let tex: bind_tex_t = parser_material_make_bind_tex(tex_name, file); - let texstore: string = parser_material_texture_store(node, tex, tex_name, color_space_t.AUTO); - return texstore + ".rrr"; - } - else if (node.type == "TEX_MAGIC") { - node_shader_add_function(parser_material_kong, str_tex_magic); - let co: string = parser_material_get_coord(node); - let scale: string = parser_material_parse_value_input(node.inputs[1]); - let res: string = "tex_magic(" + co + " * " + scale + " * 4.0)"; - return res; - } - else if (node.type == "TEX_NOISE") { - node_shader_add_function(parser_material_kong, str_tex_noise); - let co: string = parser_material_get_coord(node); - let scale: string = parser_material_parse_value_input(node.inputs[1]); - let res: string = "float3(tex_noise(" + co + " * " + scale + "), tex_noise(" + co + " * " + scale + " + 0.33), tex_noise(" + co + " * " + scale + " + 0.66))"; - return res; - } - else if (node.type == "TEX_VORONOI") { - node_shader_add_function(parser_material_kong, str_tex_voronoi); - node_shader_add_texture(parser_material_kong, "snoise256", "$noise256.k"); - let co: string = parser_material_get_coord(node); - let scale: string = parser_material_parse_value_input(node.inputs[1]); - let but: ui_node_button_t = node.buttons[0]; //coloring; - let coloring: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); - coloring = string_replace_all(coloring, " ", "_"); - let res: string = ""; - if (coloring == "INTENSITY") { - let voronoi: string = "tex_voronoi(" + co + " * " + scale + ").a"; - res = parser_material_to_vec3(voronoi); - } - else { // Cells - res = "tex_voronoi(" + co + " * " + scale + ").rgb"; - } - return res; - } - else if (node.type == "TEX_WAVE") { - node_shader_add_function(parser_material_kong, str_tex_wave); - let co: string = parser_material_get_coord(node); - let scale: string = parser_material_parse_value_input(node.inputs[1]); - let res: string = parser_material_to_vec3("tex_wave_f(" + co + " * " + scale + ")"); - return res; - } - else if (node.type == "BRIGHTCONTRAST") { - let out_col: string = parser_material_parse_vector_input(node.inputs[0]); - let bright: string = parser_material_parse_value_input(node.inputs[1]); - let contr: string = parser_material_parse_value_input(node.inputs[2]); - node_shader_add_function(parser_material_kong, str_brightcontrast); - return "brightcontrast(" + out_col + ", " + bright + ", " + contr + ")"; - } - else if (node.type == "GAMMA") { - let out_col: string = parser_material_parse_vector_input(node.inputs[0]); - let gamma: string = parser_material_parse_value_input(node.inputs[1]); - return "pow3(" + out_col + ", " + parser_material_to_vec3(gamma) + ")"; - } - else if (node.type == "DIRECT_WARP") { - if (parser_material_warp_passthrough) { - return parser_material_parse_vector_input(node.inputs[0]); - } - let angle: string = parser_material_parse_value_input(node.inputs[1], true); - let mask: string = parser_material_parse_value_input(node.inputs[2], true); - let tex_name: string = "texwarp_" + parser_material_node_name(node); - node_shader_add_texture(parser_material_kong, "" + tex_name, "_" + tex_name); - let store: string = parser_material_store_var_name(node); - let pi: f32 = math_pi(); - parser_material_write(parser_material_kong, "var " + store + "_rad: float = " + angle + " * (" + pi + " / 180.0);"); - parser_material_write(parser_material_kong, "var " + store + "_x: float = cos(" + store + "_rad);"); - parser_material_write(parser_material_kong, "var " + store + "_y: float = sin(" + store + "_rad);"); - return "sample(" + tex_name + ", sampler_linear, tex_coord + float2(" + store + "_x, " + store + "_y) * " + mask + ").rgb"; - } - else if (node.type == "BLUR") { - if (parser_material_blur_passthrough) { - return parser_material_parse_vector_input(node.inputs[0]); - } - let strength: string = parser_material_parse_value_input(node.inputs[1]); - if (strength == "0.0") { - return "float3(0.0, 0.0, 0.0)"; - } - let steps: string = "(" + strength + " * 10.0 + 1.0)"; - let tex_name: string = "texblur_" + parser_material_node_name(node); - node_shader_add_texture(parser_material_kong, "" + tex_name, "_" + tex_name); - node_shader_add_constant(parser_material_kong, "" + tex_name + "_size: float2", "_size(_" + tex_name + ")"); - let store: string = parser_material_store_var_name(node); - parser_material_write(parser_material_kong, "var " + store + "_res: float3 = float3(0.0, 0.0, 0.0);"); - parser_material_write(parser_material_kong, "for (var i: int = 0; i <= int(" + steps + " * 2.0); i += 1) {"); - parser_material_write(parser_material_kong, "for (var j: int = 0; j <= int(" + steps + " * 2.0); j += 1) {"); - parser_material_write(parser_material_kong, store + "_res += sample(" + tex_name + ", sampler_linear, tex_coord + float2(float(i) - " + steps + ", float(j) - " + steps + ") / constants." + tex_name + "_size).rgb;"); - parser_material_write(parser_material_kong, "}"); - parser_material_write(parser_material_kong, "}"); - parser_material_write(parser_material_kong, store + "_res = " + store + "_res / (" + steps + " * 2.0 + 1.0) * (" + steps + " * 2.0 + 1.0);"); - return store + "_res"; - } - else if (node.type == "HUE_SAT") { - node_shader_add_function(parser_material_kong, str_hue_sat); - let hue: string = parser_material_parse_value_input(node.inputs[0]); - let sat: string = parser_material_parse_value_input(node.inputs[1]); - let val: string = parser_material_parse_value_input(node.inputs[2]); - let fac: string = parser_material_parse_value_input(node.inputs[3]); - let col: string = parser_material_parse_vector_input(node.inputs[4]); - return "hue_sat(" + col + ", float4(" + hue + " - 0.5, " + sat + ", " + val + ", 1.0 - " + fac + "))"; - } - else if (node.type == "INVERT") { - let fac: string = parser_material_parse_value_input(node.inputs[0]); - let out_col: string = parser_material_parse_vector_input(node.inputs[1]); - return "lerp3(" + out_col + ", float3(1.0, 1.0, 1.0) - (" + out_col + "), " + fac + ")"; - } - else if (node.type == "MIX_RGB") { - let fac: string = parser_material_parse_value_input(node.inputs[0]); - let fac_var: string = parser_material_node_name(node) + "_fac"; - parser_material_write(parser_material_kong, "var " + fac_var + ": float = " + fac + ";"); - let col1: string = parser_material_parse_vector_input(node.inputs[1]); - let col2: string = parser_material_parse_vector_input(node.inputs[2]); - let but: ui_node_button_t = node.buttons[0]; // blend_type - let blend: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); - blend = string_replace_all(blend, " ", "_"); - let use_clamp: bool = node.buttons[1].default_value[0] > 0; - let out_col: string = ""; - if (blend == "MIX") { - out_col = "lerp3(" + col1 + ", " + col2 + ", " + fac_var + ")"; - } - else if (blend == "DARKEN") { - out_col = "min3(" + col1 + ", " + col2 + " * " + fac_var + ")"; - } - else if (blend == "MULTIPLY") { - out_col = "lerp3(" + col1 + ", " + col1 + " * " + col2 + ", " + fac_var + ")"; - } - else if (blend == "BURN") { - out_col = "lerp3(" + col1 + ", float3(1.0, 1.0, 1.0) - (float3(1.0, 1.0, 1.0) - " + col1 + ") / " + col2 + ", " + fac_var + ")"; - } - else if (blend == "LIGHTEN") { - out_col = "max3(" + col1 + ", " + col2 + " * " + fac_var + ")"; - } - else if (blend == "SCREEN") { - let v3: string = parser_material_to_vec3("1.0 - " + fac_var); - out_col = "(float3(1.0, 1.0, 1.0) - (" + v3 + " + " + fac_var + " * (float3(1.0, 1.0, 1.0) - " + col2 + ")) * (float3(1.0, 1.0, 1.0) - " + col1 + "))"; - } - else if (blend == "DODGE") { - out_col = "lerp3(" + col1 + ", " + col1 + " / (float3(1.0, 1.0, 1.0) - " + col2 + "), " + fac_var + ")"; - } - else if (blend == "ADD") { - out_col = "lerp3(" + col1 + ", " + col1 + " + " + col2 + ", " + fac_var + ")"; - } - else if (blend == "OVERLAY") { - // out_col = "lerp3(" + col1 + ", float3( \ - // " + col1 + ".r < 0.5 ? 2.0 * " + col1 + ".r * " + col2 + ".r : 1.0 - 2.0 * (1.0 - " + col1 + ".r) * (1.0 - " + col2 + ".r), \ - // " + col1 + ".g < 0.5 ? 2.0 * " + col1 + ".g * " + col2 + ".g : 1.0 - 2.0 * (1.0 - " + col1 + ".g) * (1.0 - " + col2 + ".g), \ - // " + col1 + ".b < 0.5 ? 2.0 * " + col1 + ".b * " + col2 + ".b : 1.0 - 2.0 * (1.0 - " + col1 + ".b) * (1.0 - " + col2 + ".b) \ - // ), " + fac_var + ")"; - let res_r: string = parser_material_node_name(node) + "_res_r"; - let res_g: string = parser_material_node_name(node) + "_res_g"; - let res_b: string = parser_material_node_name(node) + "_res_b"; - parser_material_write(parser_material_kong, "var " + res_r + ": float;"); - parser_material_write(parser_material_kong, "var " + res_g + ": float;"); - parser_material_write(parser_material_kong, "var " + res_b + ": float;"); - parser_material_write(parser_material_kong, "if (" + col1 + ".r < 0.5) { " + res_r + " = 2.0 * " + col1 + ".r * " + col2 + ".r; } else { " + res_r + " = 1.0 - 2.0 * (1.0 - " + col1 + ".r) * (1.0 - " + col2 + ".r); }"); - parser_material_write(parser_material_kong, "if (" + col1 + ".g < 0.5) { " + res_g + " = 2.0 * " + col1 + ".g * " + col2 + ".g; } else { " + res_g + " = 1.0 - 2.0 * (1.0 - " + col1 + ".g) * (1.0 - " + col2 + ".g); }"); - parser_material_write(parser_material_kong, "if (" + col1 + ".b < 0.5) { " + res_b + " = 2.0 * " + col1 + ".b * " + col2 + ".b; } else { " + res_b + " = 1.0 - 2.0 * (1.0 - " + col1 + ".b) * (1.0 - " + col2 + ".b); }"); - out_col = "lerp3(" + col1 + ", float3(" + res_r + ", " + res_g + ", " + res_b + "), " + fac_var + ")"; - } - else if (blend == "SOFT_LIGHT") { - out_col = "((1.0 - " + fac_var + ") * " + col1 + " + " + fac_var + " * ((float3(1.0, 1.0, 1.0) - " + col1 + ") * " + col2 + " * " + col1 + " + " + col1 + " * (float3(1.0, 1.0, 1.0) - (float3(1.0, 1.0, 1.0) - " + col2 + ") * (float3(1.0, 1.0, 1.0) - " + col1 + "))))"; - } - else if (blend == "LINEAR_LIGHT") { - out_col = "(" + col1 + " + " + fac_var + " * (float3(2.0, 2.0, 2.0) * (" + col2 + " - float3(0.5, 0.5, 0.5))))"; - } - else if (blend == "DIFFERENCE") { - out_col = "lerp3(" + col1 + ", abs3(" + col1 + " - " + col2 + "), " + fac_var + ")"; - } - else if (blend == "SUBTRACT") { - out_col = "lerp3(" + col1 + ", " + col1 + " - " + col2 + ", " + fac_var + ")"; - } - else if (blend == "DIVIDE") { - let eps: f32 = 0.000001; - col2 = "max3(" + col2 + ", float3(" + eps + ", " + eps + ", " + eps + "))"; - let v3: string = "(float3(1.0, 1.0, 1.0) - float3(" + fac_var + ", " + fac_var + ", " + fac_var + ")) * " + col1 + " + float3(" + fac_var + ", " + fac_var + ", " + fac_var + ") * " + col1 + " / " + col2; - out_col = "(" + v3 + ")"; - } - else if (blend == "HUE") { - node_shader_add_function(parser_material_kong, str_hue_sat); - out_col = "lerp3(" + col1 + ", hsv_to_rgb(float3(rgb_to_hsv(" + col2 + ").r, rgb_to_hsv(" + col1 + ").g, rgb_to_hsv(" + col1 + ").b)), " + fac_var + ")"; - } - else if (blend == "SATURATION") { - node_shader_add_function(parser_material_kong, str_hue_sat); - out_col = "lerp3(" + col1 + ", hsv_to_rgb(float3(rgb_to_hsv(" + col1 + ").r, rgb_to_hsv(" + col2 + ").g, rgb_to_hsv(" + col1 + ").b)), " + fac_var + ")"; - } - else if (blend == "COLOR") { - node_shader_add_function(parser_material_kong, str_hue_sat); - out_col = "lerp3(" + col1 + ", hsv_to_rgb(float3(rgb_to_hsv(" + col2 + ").r, rgb_to_hsv(" + col2 + ").g, rgb_to_hsv(" + col1 + ").b)), " + fac_var + ")"; - } - else if (blend == "VALUE") { - node_shader_add_function(parser_material_kong, str_hue_sat); - out_col = "lerp3(" + col1 + ", hsv_to_rgb(float3(rgb_to_hsv(" + col1 + ").r, rgb_to_hsv(" + col1 + ").g, rgb_to_hsv(" + col2 + ").b)), " + fac_var + ")"; - } - if (use_clamp) { - return "clamp3(" + out_col + ", float3(0.0, 0.0, 0.0), float3(1.0, 1.0, 1.0))"; - } - else { - return out_col; - } - } - else if (node.type == "QUANTIZE") { - let strength: string = parser_material_parse_value_input(node.inputs[0]); - let col: string = parser_material_parse_vector_input(node.inputs[1]); - return "(floor3(100.0 * " + strength + " * " + col + ") / (100.0 * " + strength + "))"; - } - else if (node.type == "REPLACECOL") { - let input_color: string = parser_material_parse_vector_input(node.inputs[0]); - let old_color: string = parser_material_parse_vector_input(node.inputs[1]); - let new_color: string = parser_material_parse_vector_input(node.inputs[2]); - let radius: string = parser_material_parse_value_input(node.inputs[3]); - let fuzziness: string = parser_material_parse_value_input(node.inputs[4]); - return "lerp3(" + new_color + ", " + input_color + ", clamp((distance(" + old_color + ", " + input_color + ") - " + radius + ") / max(" + fuzziness + ", " + parser_material_eps + "), 0.0, 1.0))"; - } - else if (node.type == "VALTORGB") { // ColorRamp - let fac: string = parser_material_parse_value_input(node.inputs[0]); - let data0: i32 = node.buttons[0].data[0]; - let interp: string = data0 == 0 ? "LINEAR" : "CONSTANT"; - let elems: f32[] = node.buttons[0].default_value; - let len: i32 = elems.length / 5; - if (len == 1) { - return parser_material_vec3(elems); - } - // Write cols array - let cols_var: string = parser_material_node_name(node) + "_cols"; - parser_material_write(parser_material_kong, "var " + cols_var + ": float3[" + len + "];"); // TODO: Make const - for (let i: i32 = 0; i < len; ++i) { - let tmp: f32[] = []; - array_push(tmp, elems[i * 5]); - array_push(tmp, elems[i * 5 + 1]); - array_push(tmp, elems[i * 5 + 2]); - parser_material_write(parser_material_kong, cols_var + "[" + i + "] = " + parser_material_vec3(tmp) + ";"); - } - // Get index - let fac_var: string = parser_material_node_name(node) + "_fac"; - parser_material_write(parser_material_kong, "var " + fac_var + ": float = " + fac + ";"); - let index: string = "0"; - for (let i: i32 = 1; i < len; ++i) { - let e: f32 = elems[i * 5 + 4]; - index += " + (" + fac_var + " > " + e + " ? 1 : 0)"; - } - // Write index - let index_var: string = parser_material_node_name(node) + "_i"; - parser_material_write(parser_material_kong, "var " + index_var + ": int = " + index + ";"); - if (interp == "CONSTANT") { - return cols_var + "[" + index_var + "]"; - } - else { // Linear - // Write facs array - let facs_var: string = parser_material_node_name(node) + "_facs"; - parser_material_write(parser_material_kong, "var " + facs_var + ": float[" + len + "];"); // TODO: Make const - for (let i: i32 = 0; i < len; ++i) { - let e: f32 = elems[i * 5 + 4]; - parser_material_write(parser_material_kong, facs_var + "[" + i + "] = " + e + ";"); - } - // Mix color - // float f = (pos - start) * (1.0 / (finish - start)) - // TODO: index_var + 1 out of bounds - return "lerp3(" + cols_var + "[" + index_var + "], " + cols_var + "[" + index_var + " + 1], (" + - fac_var + " - " + facs_var + "[" + index_var + "]) * (1.0 / (" + facs_var + "[" + index_var + " + 1] - " + - facs_var + "[" + index_var + "]) ))"; - } - } - else if (node.type == "CURVE_VEC") { - let fac: string = parser_material_parse_value_input(node.inputs[0]); - let vec: string = parser_material_parse_vector_input(node.inputs[1]); - let curves: f32_array_t = node.buttons[0].default_value; - if (curves[96] == 0.0) { - curves[96] = 1.0; - curves[97] = 1.0; - curves[98] = 1.0; - } - let name: string = parser_material_node_name(node); - let vc0: string = parser_material_vector_curve(name + "0", vec + ".x", curves.buffer + 32 * 0, curves[96]); - let vc1: string = parser_material_vector_curve(name + "1", vec + ".y", curves.buffer + 32 * 1, curves[97]); - let vc2: string = parser_material_vector_curve(name + "2", vec + ".z", curves.buffer + 32 * 2, curves[98]); - // mapping.curves[0].points[0].handle_type // bezier curve - return "(float3(" + vc0 + ", " + vc1 + ", " + vc2 + ") * " + fac + ")"; - } - // else if (node.type == "CURVE_RGB") { // RGB Curves - // let fac: string = parser_material_parse_value_input(node.inputs[0]); - // let vec: string = parser_material_parse_vector_input(node.inputs[1]); - // let curves: f32_array_t = node.buttons[0].default_value; - // let name: string = parser_material_node_name(node); - // // mapping.curves[0].points[0].handle_type - // let vc0: string = parser_material_vector_curve(name + "0", vec + ".x", curves[0]); - // let vc1: string = parser_material_vector_curve(name + "1", vec + ".y", curves[1]); - // let vc2: string = parser_material_vector_curve(name + "2", vec + ".z", curves[2]); - // let vc3a: string = parser_material_vector_curve(name + "3a", vec + ".x", curves[3]); - // let vc3b: string = parser_material_vector_curve(name + "3b", vec + ".y", curves[3]); - // let vc3c: string = parser_material_vector_curve(name + "3c", vec + ".z", curves[3]); - // return "(sqrt(float3(" + vc0 + ", " + vc1 + ", " + vc2 + ") * float3(" + vc3a + ", " + vc3b + ", " + vc3c + ")) * " + fac + ")"; - // } - else if (node.type == "COMBHSV") { - node_shader_add_function(parser_material_kong, str_hue_sat); - let h: string = parser_material_parse_value_input(node.inputs[0]); - let s: string = parser_material_parse_value_input(node.inputs[1]); - let v: string = parser_material_parse_value_input(node.inputs[2]); - return "hsv_to_rgb(float3(" + h + ", " + s + ", " + v + "))"; - } - else if (node.type == "COMBRGB") { - let r: string = parser_material_parse_value_input(node.inputs[0]); - let g: string = parser_material_parse_value_input(node.inputs[1]); - let b: string = parser_material_parse_value_input(node.inputs[2]); - return "float3(" + r + ", " + g + ", " + b + ")"; - } - else if (node.type == "WAVELENGTH") { - node_shader_add_function(parser_material_kong, str_wavelength_to_rgb); - let wl: string = parser_material_parse_value_input(node.inputs[0]); - node_shader_add_function(parser_material_kong, str_wavelength_to_rgb); - return "wavelength_to_rgb((" + wl + " - 450.0) / 150.0)"; - } - else if (node.type == "CAMERA") { - parser_material_kong.frag_vvec_cam = true; - return "vvec_cam"; - } - else if (node.type == "LAYER") { - let l: i32 = node.buttons[0].default_value[0]; - if (socket == node.outputs[0]) { // Base - node_shader_add_texture(parser_material_kong, "texpaint" + l, "_texpaint" + l); - return "sample(texpaint" + l + ", sampler_linear, tex_coord).rgb"; - } - else if (socket == node.outputs[5]) { // Normal - node_shader_add_texture(parser_material_kong, "texpaint_nor" + l, "_texpaint_nor" + l); - return "sample(texpaint_nor" + l + ", sampler_linear, tex_coord).rgb"; - } - } - else if (node.type == "MATERIAL") { - let result: string = "float3(0.0, 0.0, 0.0)"; - let mi: i32 = node.buttons[0].default_value[0]; - if (mi >= project_materials.length) { - return result; - } - let m: slot_material_t = project_materials[mi]; - let _nodes: ui_node_t[] = parser_material_nodes; - let _links: ui_node_link_t[] = parser_material_links; - parser_material_nodes = m.canvas.nodes; - parser_material_links = m.canvas.links; - array_push(parser_material_parents, node); - let output_node: ui_node_t = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL_PBR"); - if (socket == node.outputs[0]) { // Base - result = parser_material_parse_vector_input(output_node.inputs[0]); - } - else if (socket == node.outputs[5]) { // Normal - result = parser_material_parse_vector_input(output_node.inputs[5]); - } - parser_material_nodes = _nodes; - parser_material_links = _links; - array_pop(parser_material_parents); - return result; - } - else if (node.type == "PICKER") { - if (socket == node.outputs[0]) { // Base - node_shader_add_constant(parser_material_kong, "picker_base: float3", "_picker_base"); - return "constants.picker_base"; - } - else if (socket == node.outputs[5]) { // Normal - node_shader_add_constant(parser_material_kong, "picker_normal: float3", "_picker_normal"); - return "constants.picker_normal"; - } - } - else if (node.type == "NEW_GEOMETRY") { - if (socket == node.outputs[0]) { // Position - parser_material_kong.frag_wposition = true; - return "input.wposition"; - } - else if (socket == node.outputs[1]) { // Normal - parser_material_kong.frag_n = true; - return "n"; - } - else if (socket == node.outputs[2]) { // Tangent - parser_material_kong.frag_wtangent = true; - return "input.wtangent"; - } - else if (socket == node.outputs[3]) { // True Normal - parser_material_kong.frag_n = true; - return "n"; - } - else if (socket == node.outputs[4]) { // Incoming - parser_material_kong.frag_vvec = true; - return "vvec"; - } - else if (socket == node.outputs[5]) { // Parametric - parser_material_kong.frag_mposition = true; - return "input.mposition"; - } - } - else if (node.type == "OBJECT_INFO") { - if (socket == node.outputs[0]) { // Location - parser_material_kong.frag_wposition = true; - return "input.wposition"; - } - else if (socket == node.outputs[1]) { // Color - return "float3(0.0, 0.0, 0.0)"; - } - } - // else if (node.type == "PARTICLE_INFO") { - // if (socket == node.outputs[3]) { // Location - // return "float3(0.0, 0.0, 0.0)"; - // } - // else if (socket == node.outputs[5]) { // Velocity - // return "float3(0.0, 0.0, 0.0)"; - // } - // else if (socket == node.outputs[6]) { // Angular Velocity - // return "float3(0.0, 0.0, 0.0)"; - // } - // } - else if (node.type == "TANGENT") { - parser_material_kong.frag_wtangent = true; - return "input.wtangent"; - } - else if (node.type == "TEX_COORD") { - if (socket == node.outputs[0]) { // Generated - bounds - parser_material_kong.frag_bposition = true; - return "bposition"; - } - else if (socket == node.outputs[1]) { // Normal - parser_material_kong.frag_n = true; - return "n"; - } - else if (socket == node.outputs[2]) {// UV - node_shader_context_add_elem(parser_material_kong.context, "tex", "short2norm"); - return "float3(tex_coord.x, tex_coord.y, 0.0)"; - } - else if (socket == node.outputs[3]) { // Object - parser_material_kong.frag_mposition = true; - return "input.mposition"; - } - else if (socket == node.outputs[4]) { // Camera - parser_material_kong.frag_vposition = true; - return "input.vposition"; - } - else if (socket == node.outputs[5]) { // Window - parser_material_kong.frag_wvpposition = true; - return "input.wvpposition.xyz"; - } - else if (socket == node.outputs[6]) { // Reflection - return "float3(0.0, 0.0, 0.0)"; - } - } - else if (node.type == "UVMAP") { - node_shader_context_add_elem(parser_material_kong.context, "tex", "short2norm"); - return "float3(tex_coord.x, tex_coord.y, 0.0)"; - } - else if (node.type == "BUMP") { - let strength: string = parser_material_parse_value_input(node.inputs[0]); - // let distance: string = parse_value_input(node.inputs[1]); - let height: string = parser_material_parse_value_input(node.inputs[2]); - let nor: string = parser_material_parse_vector_input(node.inputs[3]); - let sample_bump_res: string = parser_material_store_var_name(node) + "_bump"; - parser_material_write(parser_material_kong, "var " + sample_bump_res + "_x: float = ddx(float(" + height + ")) * (" + strength + ") * 16.0;"); - parser_material_write(parser_material_kong, "var " + sample_bump_res + "_y: float = ddy(float(" + height + ")) * (" + strength + ") * 16.0;"); - return "(normalize(float3(" + sample_bump_res + "_x, " + sample_bump_res + "_y, 1.0) + " + nor + ") * float3(0.5, 0.5, 0.5) + float3(0.5, 0.5, 0.5))"; - } - else if (node.type == "MAPPING") { - let out: string = parser_material_parse_vector_input(node.inputs[0]); - let node_translation: string = parser_material_parse_vector_input(node.inputs[1]); - let node_rotation: string = parser_material_parse_vector_input(node.inputs[2]); - let node_scale: string = parser_material_parse_vector_input(node.inputs[3]); - if (node_scale != "float3(1, 1, 1)") { - out = "(" + out + " * " + node_scale + ")"; - } - if (node_rotation != "float3(0, 0, 0)") { - // ZYX rotation, Z axis for now.. - let a: string = node_rotation + ".z * (3.1415926535 / 180)"; - // x * cos(theta) - y * sin(theta) - // x * sin(theta) + y * cos(theta) - out = "float3(" + out + ".x * cos(" + a + ") - " + out + ".y * sin(" + a + "), " + out + ".x * sin(" + a + ") + " + out + ".y * cos(" + a + "), 0.0)"; - } - // if node.rotation[1] != 0.0: - // a = node.rotation[1] - // out = "float3({0}.x * {1} - {0}.z * {2}, {0}.x * {2} + {0}.z * {1}, 0.0)".format(out, math_cos(a), math_sin(a)) - // if node.rotation[0] != 0.0: - // a = node.rotation[0] - // out = "float3({0}.y * {1} - {0}.z * {2}, {0}.y * {2} + {0}.z * {1}, 0.0)".format(out, math_cos(a), math_sin(a)) - if (node_translation != "float3(0, 0, 0)") { - out = "(" + out + " + " + node_translation + ")"; - } - // if node.use_min: - // out = "max({0}, float3({1}, {2}, {3}))".format(out, node.min[0], node.min[1]) - // if node.use_max: - // out = "min({0}, float3({1}, {2}, {3}))".format(out, node.max[0], node.max[1]) - return out; - } - else if (node.type == "NORMAL") { - if (socket == node.outputs[0]) { - return parser_material_vec3(node.outputs[0].default_value); - } - else if (socket == node.outputs[1]) { - let nor: string = parser_material_parse_vector_input(node.inputs[0]); - let norout: string = parser_material_vec3(node.outputs[0].default_value); - return parser_material_to_vec3("dot(" + norout + ", " + nor + ")"); - } - } - else if (node.type == "NORMAL_MAP") { - let strength: string = parser_material_parse_value_input(node.inputs[0]); - let norm: string = parser_material_parse_vector_input(node.inputs[1]); - - let store: string = parser_material_store_var_name(node); - parser_material_write(parser_material_kong, "var " + store + "_texn: float3 = " + norm + " * 2.0 - 1.0;"); - parser_material_write(parser_material_kong, "" + store + "_texn.xy = " + strength + " * " + store + "_texn.xy;"); - parser_material_write(parser_material_kong, "" + store + "_texn = normalize(" + store + "_texn);"); - - return "(0.5 * " + store + "_texn + 0.5)"; - } - else if (node.type == "MIX_NORMAL_MAP") { - let nm1: string = parser_material_parse_vector_input(node.inputs[0]); - let nm2: string = parser_material_parse_vector_input(node.inputs[1]); - let but: ui_node_button_t = node.buttons[0]; - let blend: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); // blend_type - blend = string_replace_all(blend, " ", "_"); - let store: string = parser_material_store_var_name(node); - - // The blending algorithms are based on the paper "Blending in Detail" by Colin Barré-Brisebois and Stephen Hill 2012 - // https://blog.selfshadow.com/publications/blending-in-detail/ - if (blend == "PARTIAL_DERIVATIVE") { //partial derivate blending - parser_material_write(parser_material_kong, "var " + store + "_n1: float3 = " + nm1 + " * 2.0 - 1.0;"); - parser_material_write(parser_material_kong, "var " + store + "_n2: float3 = " + nm2 + " * 2.0 - 1.0;"); - return "0.5 * normalize(float3(" + store + "_n1.xy * " + store + "_n2.z + " + store + "_n2.xy * " + store + "_n1.z, " + store + "_n1.z * " + store + "_n2.z)) + 0.5"; - } - else if (blend == "WHITEOUT") { //whiteout blending - parser_material_write(parser_material_kong, "var " + store + "_n1: float3 = " + nm1 + " * 2.0 - 1.0;"); - parser_material_write(parser_material_kong, "var " + store + "_n2: float3 = " + nm2 + " * 2.0 - 1.0;"); - return "0.5 * normalize(float3(" + store + "_n1.xy + " + store + "_n2.xy, " + store + "_n1.z * " + store + "_n2.z)) + 0.5"; - } - else if (blend == "REORIENTED") { //reoriented normal mapping - parser_material_write(parser_material_kong, "var " + store + "_n1: float3 = " + nm1 + " * 2.0 - float3(1.0, 1.0, 0.0);"); - parser_material_write(parser_material_kong, "var " + store + "_n2: float3 = " + nm2 + " * float3(-2.0, -2.0, 2.0) - float3(-1.0, -1.0, 1.0);"); - return "0.5 * normalize(" + store + "_n1 * dot(" + store + "_n1, " + store + "_n2) - " + store + "_n2 * " + store + "_n1.z) + 0.5"; - } - } - else if (node.type == "VECT_TRANSFORM") { - // type = node.vector_type - // conv_from = node.convert_from - // conv_to = node.convert_to - // // Pass throuh - // return parse_vector_input(node.inputs[0]) - } - else if (node.type == "COMBXYZ") { - let x: string = parser_material_parse_value_input(node.inputs[0]); - let y: string = parser_material_parse_value_input(node.inputs[1]); - let z: string = parser_material_parse_value_input(node.inputs[2]); - return "float3(" + x + ", " + y + ", " + z + ")"; - } - else if (node.type == "VECT_MATH") { - let vec1: string = parser_material_parse_vector_input(node.inputs[0]); - let vec2: string = parser_material_parse_vector_input(node.inputs[1]); - let but: ui_node_button_t = node.buttons[0]; //operation; - let op: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); - op = string_replace_all(op, " ", "_"); - if (op == "ADD") { - return "(" + vec1 + " + " + vec2 + ")"; - } - else if (op == "SUBTRACT") { - return "(" + vec1 + " - " + vec2 + ")"; - } - else if (op == "AVERAGE") { - return "((" + vec1 + " + " + vec2 + ") / 2.0)"; - } - else if (op == "DOT_PRODUCT") { - return parser_material_to_vec3("dot(" + vec1 + ", " + vec2 + ")"); - } - else if (op == "LENGTH") { - return parser_material_to_vec3("length(" + vec1 + ")"); - } - else if (op == "DISTANCE") { - return parser_material_to_vec3("distance(" + vec1 + ", " + vec2 + ")"); - } - else if (op == "CROSS_PRODUCT") { - return "cross(" + vec1 + ", " + vec2 + ")"; - } - else if (op == "NORMALIZE") { - return "normalize(" + vec1 + ")"; - } - else if (op == "MULTIPLY") { - return "(" + vec1 + " * " + vec2 + ")"; - } - else if (op == "DIVIDE") { - let store: string = parser_material_store_var_name(node) + "_vec2"; - parser_material_write(parser_material_kong, "var " + store + ": float3 = " + vec2 + ";"); - parser_material_write(parser_material_kong, "if (" + store + ".x == 0.0) { " + store + ".x = 0.000001; }"); - parser_material_write(parser_material_kong, "if (" + store + ".y == 0.0) { " + store + ".y = 0.000001; }"); - parser_material_write(parser_material_kong, "if (" + store + ".z == 0.0) { " + store + ".z = 0.000001; }"); - return "(" + vec1 + " / " + vec2 + ")"; - } - else if (op == "PROJECT") { - return "(dot(" + vec1 + ", " + vec2 + ") / dot(" + vec2 + ", " + vec2 + ") * " + vec2 + ")"; - } - else if (op == "REFLECT") { - return "reflect(" + vec1 + ", normalize(" + vec2 + "))"; - } - else if (op == "SCALE") { - return "(" + vec2 + ".x * " + vec1 + ")"; - } - else if (op == "ABSOLUTE") { - return "abs3(" + vec1 + ")"; - } - else if (op == "MINIMUM") { - return "min3(" + vec1 + ", " + vec2 + ")"; - } - else if (op == "MAXIMUM") { - return "max3(" + vec1 + ", " + vec2 + ")"; - } - else if (op == "FLOOR") { - return "floor3(" + vec1 + ")"; - } - else if (op == "CEIL") { - return "ceil3(" + vec1 + ")"; - } - else if (op == "FRACTION") { - return "frac3(" + vec1 + ")"; - } - else if (op == "MODULO") { - return "(" + vec1 + " % " + vec2 + ")"; - } - else if(op == "SNAP") { - return "(floor3(" + vec1 + " / " + vec2 + ") * " + vec2 + ")"; - } - else if (op == "SINE") { - return "float3(sin(" + vec1 + ".x), sin(" + vec1 + ".y), sin(" + vec1 + ".z))"; - } - else if (op == "COSINE") { - return "float3(cos(" + vec1 + ".x), cos(" + vec1 + ".y), cos(" + vec1 + ".z))"; - } - else if (op == "TANGENT") { - return "float3(tan(" + vec1 + ".x), tan(" + vec1 + ".y), tan(" + vec1 + ".z))"; - } - } - else if (node.type == "Displacement") { - let height: string = parser_material_parse_value_input(node.inputs[0]); - return parser_material_to_vec3(height); - } else if (map_get(parser_material_custom_nodes, node.type) != null) { let cb: any = map_get(parser_material_custom_nodes, node.type); // JSValue -> (n: ui_node_t, s: string)=>string return js_call_ptr_str(cb, node, socket.name); @@ -1236,10 +446,6 @@ function parser_material_parse_value_input(inp: ui_node_socket_t, vector_as_gray let l: ui_node_link_t = parser_material_get_input_link(inp); let from_node: ui_node_t = l != null ? parser_material_get_node(l.from_id) : null; if (from_node != null) { - if (from_node.type == "REROUTE") { - return parser_material_parse_value_input(from_node.inputs[0]); - } - let res_var: string = parser_material_write_result(l); let st: string = from_node.outputs[l.from_socket].type; if (st == "RGB" || st == "RGBA" || st == "VECTOR") { @@ -1260,537 +466,13 @@ function parser_material_parse_value_input(inp: ui_node_socket_t, vector_as_gray } function parser_material_parse_value(node: ui_node_t, socket: ui_node_socket_t): string { - if (node.type == "GROUP") { - return parser_material_parse_group(node, socket); + let node_value: (node: ui_node_t, socket: ui_node_socket_t)=>string = map_get(parser_material_node_values, node.type); + if (node_value != null) { + return node_value(node, socket); } else if (node.type == "GROUP_INPUT") { return parser_material_parse_group_input(node, socket); } - else if (node.type == "ATTRIBUTE") { - node_shader_add_constant(parser_material_kong, "time: float", "_time"); - return "constants.time"; - } - else if (node.type == "VERTEX_COLOR") { - return "1.0"; - } - else if (node.type == "WIREFRAME") { - node_shader_add_texture(parser_material_kong, "texuvmap", "_texuvmap"); - // let use_pixel_size: bool = node.buttons[0].default_value[0] > 0.0; - // let pixel_size: f32 = parse_value_input(node.inputs[0]); - return "sample_lod(texuvmap, sampler_linear, tex_coord, 0.0).r"; - } - else if (node.type == "CAMERA") { - if (socket == node.outputs[1]) { // View Z Depth - node_shader_add_constant(parser_material_kong, "camera_proj: float2", "_camera_plane_proj"); - parser_material_kong.frag_wvpposition = true; - return "(constants.camera_proj.y / ((input.wvpposition.z / input.wvpposition.w) - constants.camera_proj.x))"; - } - else { // View Distance - node_shader_add_constant(parser_material_kong, "eye: float3", "_camera_pos"); - parser_material_kong.frag_wposition = true; - return "distance(constants.eye, input.wposition)"; - } - } - else if (node.type == "LAYER") { - let l: i32 = node.buttons[0].default_value[0]; - if (socket == node.outputs[1]) { // Opac - node_shader_add_texture(parser_material_kong, "texpaint" + l, "_texpaint" + l); - return "sample(texpaint" + l + ", sampler_linear, tex_coord).a"; - } - else if (socket == node.outputs[2]) { // Occ - node_shader_add_texture(parser_material_kong, "texpaint_pack" + l, "_texpaint_pack" + l); - return "sample(texpaint_pack" + l + ", sampler_linear, tex_coord).r"; - } - else if (socket == node.outputs[3]) { // Rough - node_shader_add_texture(parser_material_kong, "texpaint_pack" + l, "_texpaint_pack" + l); - return "sample(texpaint_pack" + l + ", sampler_linear, tex_coord).g"; - } - else if (socket == node.outputs[4]) { // Metal - node_shader_add_texture(parser_material_kong, "texpaint_pack" + l, "_texpaint_pack" + l); - return "sample(texpaint_pack" + l + ", sampler_linear, tex_coord).b"; - } - else if (socket == node.outputs[7]) { // Height - node_shader_add_texture(parser_material_kong, "texpaint_pack" + l, "_texpaint_pack" + l); - return "sample(texpaint_pack" + l + ", sampler_linear, tex_coord).a"; - } - } - else if (node.type == "LAYER_MASK") { - if (socket == node.outputs[0]) { - let l: i32 = node.buttons[0].default_value[0]; - node_shader_add_texture(parser_material_kong, "texpaint" + l, "_texpaint" + l); - return "sample(texpaint" + l + ", sampler_linear, tex_coord).r"; - } - } - else if (node.type == "MATERIAL") { - let result: string = "0.0"; - let mi: i32 = node.buttons[0].default_value[0]; - if (mi >= project_materials.length) return result; - let m: slot_material_t = project_materials[mi]; - let _nodes: ui_node_t[] = parser_material_nodes; - let _links: ui_node_link_t[] = parser_material_links; - parser_material_nodes = m.canvas.nodes; - parser_material_links = m.canvas.links; - array_push(parser_material_parents, node); - let output_node: ui_node_t = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL_PBR"); - if (socket == node.outputs[1]) { // Opac - result = parser_material_parse_value_input(output_node.inputs[1]); - } - else if (socket == node.outputs[2]) { // Occ - result = parser_material_parse_value_input(output_node.inputs[2]); - } - else if (socket == node.outputs[3]) { // Rough - result = parser_material_parse_value_input(output_node.inputs[3]); - } - else if (socket == node.outputs[4]) { // Metal - result = parser_material_parse_value_input(output_node.inputs[4]); - } - else if (socket == node.outputs[7]) { // Height - result = parser_material_parse_value_input(output_node.inputs[7]); - } - parser_material_nodes = _nodes; - parser_material_links = _links; - array_pop(parser_material_parents); - return result; - } - else if (node.type == "PICKER") { - if (socket == node.outputs[1]) { - node_shader_add_constant(parser_material_kong, "picker_opacity: float", "_picker_opacity"); - return "constants.picker_opacity"; - } - else if (socket == node.outputs[2]) { - node_shader_add_constant(parser_material_kong, "picker_occlusion: float", "_picker_occlusion"); - return "constants.picker_occlusion"; - } - else if (socket == node.outputs[3]) { - node_shader_add_constant(parser_material_kong, "picker_roughness: float", "_picker_roughness"); - return "constants.picker_roughness"; - } - else if (socket == node.outputs[4]) { - node_shader_add_constant(parser_material_kong, "picker_metallic: float", "_picker_metallic"); - return "constants.picker_metallic"; - } - else if (socket == node.outputs[7]) { - node_shader_add_constant(parser_material_kong, "picker_height: float", "_picker_height"); - return "constants.picker_height"; - } - } - else if (node.type == "FRESNEL") { - let ior: string = parser_material_parse_value_input(node.inputs[0]); - parser_material_kong.frag_dotnv = true; - return "pow(1.0 - dotnv, 7.25 / " + ior + ")"; - } - else if (node.type == "NEW_GEOMETRY") { - if (socket == node.outputs[6]) { // Backfacing - return "0.0"; // SV_IsFrontFace - // return "(1.0 - float(gl_FrontFacing))"; - } - else if (socket == node.outputs[7]) { // Pointiness - let strength: f32 = 1.0; - let radius: f32 = 1.0; - let offset: f32 = 0.0; - let store: string = parser_material_store_var_name(node); - parser_material_kong.frag_n = true; - parser_material_write(parser_material_kong, "var " + store + "_dx: float3 = ddx3(n);"); - parser_material_write(parser_material_kong, "var " + store + "_dy: float3 = ddy3(n);"); - parser_material_write(parser_material_kong, "var " + store + "_curvature: float = max(dot(" + store + "_dx, " + store + "_dx), dot(" + store + "_dy, " + store + "_dy));"); - parser_material_write(parser_material_kong, store + "_curvature = clamp(pow(" + store + "_curvature, (1.0 / " + radius + ") * 0.25) * " + strength + " * 2.0 + " + offset + " / 10.0, 0.0, 1.0);"); - return store + "_curvature"; - } - else if (socket == node.outputs[8]) { // Random Per Island - return "0.0"; - } - } - else if (node.type == "HAIR_INFO") { - return "0.5"; - } - else if (node.type == "LAYER_WEIGHT") { - let blend: string = parser_material_parse_value_input(node.inputs[0]); - if (socket == node.outputs[0]) { // Fresnel - parser_material_kong.frag_dotnv = true; - return "clamp(pow(1.0 - dotnv, (1.0 - " + blend + ") * 10.0), 0.0, 1.0)"; - } - else if (socket == node.outputs[1]) { // Facing - parser_material_kong.frag_dotnv = true; - return "((1.0 - dotnv) * " + blend + ")"; - } - } - else if (node.type == "OBJECT_INFO") { - if (socket == node.outputs[1]) { // Object Index - node_shader_add_constant(parser_material_kong, "object_info_index: float", "_object_info_index"); - return "constants.object_info_index"; - } - else if (socket == node.outputs[2]) { // Material Index - node_shader_add_constant(parser_material_kong, "object_info_material_index: float", "_object_info_material_index"); - return "constants.object_info_material_index"; - } - else if (socket == node.outputs[3]) { // Random - node_shader_add_constant(parser_material_kong, "object_info_random: float", "_object_info_random"); - return "constants.object_info_random"; - } - } - else if (node.type == "VALUE") { - return parser_material_vec1(node.outputs[0].default_value[0]); - } - else if (node.type == "TEX_BRICK") { - node_shader_add_function(parser_material_kong, str_tex_brick); - let co: string = parser_material_get_coord(node); - let scale: string = parser_material_parse_value_input(node.inputs[4]); - let res: string = "tex_brick_f(" + co + " * " + scale + ")"; - return res; - } - else if (node.type == "TEX_CHECKER") { - node_shader_add_function(parser_material_kong, str_tex_checker); - let co: string = parser_material_get_coord(node); - let scale: string = parser_material_parse_value_input(node.inputs[3]); - let res: string = "tex_checker_f(" + co + ", " + scale + ")"; - return res; - } - else if (node.type == "TEX_GRADIENT") { - let co: string = parser_material_get_coord(node); - let but: ui_node_button_t = node.buttons[0]; //gradient_type; - let grad: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); - grad = string_replace_all(grad, " ", "_"); - let f: string = parser_material_get_gradient(grad, co); - let res: string = "(clamp(" + f + ", 0.0, 1.0))"; - return res; - } - else if (node.type == "TEX_IMAGE") { - // Already fetched - if (array_index_of(parser_material_parsed, parser_material_res_var_name(node, node.outputs[0])) >= 0) { // TODO: node.outputs[1] - let varname: string = parser_material_store_var_name(node); - return varname + ".a"; - } - let tex_name: string = parser_material_node_name(node); - let tex: bind_tex_t = parser_material_make_texture(node, tex_name); - if (tex != null) { - let color_space: i32 = node.buttons[1].default_value[0]; - let texstore: string = parser_material_texture_store(node, tex, tex_name, color_space); - return texstore + ".a"; - } - } - else if (node.type == "TEX_TEXT") { - let tex_name: string = parser_material_node_name(node); - let text_buffer: buffer_t = node.buttons[0].default_value; - let text: string = sys_buffer_to_string(text_buffer); - let file: string = "tex_text_" + text; - _parser_material_cache_tex_text_node(file, text); - let tex: bind_tex_t = parser_material_make_bind_tex(tex_name, file); - let texstore: string = parser_material_texture_store(node, tex, tex_name, color_space_t.AUTO); - return texstore + ".r"; - } - else if (node.type == "TEX_MAGIC") { - node_shader_add_function(parser_material_kong, str_tex_magic); - let co: string = parser_material_get_coord(node); - let scale: string = parser_material_parse_value_input(node.inputs[1]); - let res: string = "tex_magic_f(" + co + " * " + scale + " * 4.0)"; - return res; - } - else if (node.type == "TEX_MUSGRAVE") { - node_shader_add_function(parser_material_kong, str_tex_musgrave); - let co: string = parser_material_get_coord(node); - let scale: string = parser_material_parse_value_input(node.inputs[1]); - let res: string = "tex_musgrave_f(" + co + " * " + scale + " * 0.5)"; - return res; - } - else if (node.type == "TEX_NOISE") { - node_shader_add_function(parser_material_kong, str_tex_noise); - let co: string = parser_material_get_coord(node); - let scale: string = parser_material_parse_value_input(node.inputs[1]); - let res: string = "tex_noise(" + co + " * " + scale + ")"; - return res; - } - else if (node.type == "TEX_VORONOI") { - node_shader_add_function(parser_material_kong, str_tex_voronoi); - node_shader_add_texture(parser_material_kong, "snoise256", "$noise256.k"); - let co: string = parser_material_get_coord(node); - let scale: string = parser_material_parse_value_input(node.inputs[1]); - let but: ui_node_button_t = node.buttons[0]; // coloring - let coloring: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); - coloring = string_replace_all(coloring, " ", "_"); - let res: string = ""; - if (coloring == "INTENSITY") { - res = "tex_voronoi(" + co + " * " + scale + ").a"; - } - else { // Cells - res = "tex_voronoi(" + co + " * " + scale + ").r"; - } - return res; - } - else if (node.type == "TEX_WAVE") { - node_shader_add_function(parser_material_kong, str_tex_wave); - let co: string = parser_material_get_coord(node); - let scale: string = parser_material_parse_value_input(node.inputs[1]); - let res: string = "tex_wave_f(" + co + " * " + scale + ")"; - return res; - } - else if (node.type == "BAKE_CURVATURE") { - if (parser_material_bake_passthrough) { - parser_material_bake_passthrough_strength = parser_material_parse_value_input(node.inputs[0]); - parser_material_bake_passthrough_radius = parser_material_parse_value_input(node.inputs[1]); - parser_material_bake_passthrough_offset = parser_material_parse_value_input(node.inputs[2]); - return "0.0"; - } - let tex_name: string = "texbake_" + parser_material_node_name(node); - node_shader_add_texture(parser_material_kong, "" + tex_name, "_" + tex_name); - let store: string = parser_material_store_var_name(node); - parser_material_write(parser_material_kong, "var " + store + "_res: float = sample(" + tex_name + ", sampler_linear, tex_coord).r;"); - return store + "_res"; - } - else if (node.type == "NORMAL") { - let nor: string = parser_material_parse_vector_input(node.inputs[0]); - let norout: string = parser_material_vec3(node.outputs[0].default_value); - return "dot(" + norout + ", " + nor + ")"; - } - else if (node.type == "COLMASK") { - let input_color: string = parser_material_parse_vector_input(node.inputs[0]); - let mask_color: string = parser_material_parse_vector_input(node.inputs[1]); - let radius: string = parser_material_parse_value_input(node.inputs[2]); - let fuzziness: string = parser_material_parse_value_input(node.inputs[3]); - return "clamp(1.0 - (distance(" + input_color + ", " + mask_color + ") - " + radius + ") / max(" + fuzziness + ", " + parser_material_eps + "), 0.0, 1.0)"; - } - else if (node.type == "MATH") { - let val1: string = parser_material_parse_value_input(node.inputs[0]); - let val2: string = parser_material_parse_value_input(node.inputs[1]); - let but: ui_node_button_t = node.buttons[0]; // operation - let op: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); - op = string_replace_all(op, " ", "_"); - let use_clamp: bool = node.buttons[1].default_value[0] > 0; - let out_val: string = ""; - if (op == "ADD") { - out_val = "(" + val1 + " + " + val2 + ")"; - } - else if (op == "SUBTRACT") { - out_val = "(" + val1 + " - " + val2 + ")"; - } - else if (op == "MULTIPLY") { - out_val = "(" + val1 + " * " + val2 + ")"; - } - else if (op == "DIVIDE") { - let store: string = parser_material_store_var_name(node) + "_divide"; - parser_material_write(parser_material_kong, "var " + store + ": float = " + val2 + ";"); - parser_material_write(parser_material_kong, "if (" + store + " == 0.0) { " + store + " = " + parser_material_eps + "; }"); - out_val = "(" + val1 + " / " + store + ")"; - } - else if (op == "POWER") { - out_val = "pow(" + val1 + ", " + val2 + ")"; - } - else if (op == "LOGARITHM") { - out_val = "log(" + val1 + ")"; - } - else if (op == "SQUARE_ROOT") { - out_val = "sqrt(" + val1 + ")"; - } - else if(op == "INVERSE_SQUARE_ROOT") { - out_val = "rsqrt(" + val1 + ")"; - } - else if (op == "EXPONENT") { - out_val = "exp(" + val1 + ")"; - } - else if (op == "ABSOLUTE") { - out_val = "abs(" + val1 + ")"; - } - else if (op == "MINIMUM") { - out_val = "min(" + val1 + ", " + val2 + ")"; - } - else if (op == "MAXIMUM") { - out_val = "max(" + val1 + ", " + val2 + ")"; - } - else if (op == "LESS_THAN") { - // out_val = "float(" + val1 + " < " + val2 + ")"; - let store: string = parser_material_store_var_name(node) + "_lessthan"; - parser_material_write(parser_material_kong, "var " + store + ": float = 0.0;"); - parser_material_write(parser_material_kong, "if (" + val1 + " < " + val2 + ") { " + store + " = 1.0; }"); - out_val = store; - } - else if (op == "GREATER_THAN") { - // out_val = "float(" + val1 + " > " + val2 + ")"; - let store: string = parser_material_store_var_name(node) + "_greaterthan"; - parser_material_write(parser_material_kong, "var " + store + ": float = 0.0;"); - parser_material_write(parser_material_kong, "if (" + val1 + " > " + val2 + ") { " + store + " = 1.0; }"); - out_val = store; - } - else if (op == "SIGN") { - out_val = "sign(" + val1 + ")"; - } - else if (op == "ROUND") { - out_val = "floor(" + val1 + " + 0.5)"; - } - else if (op == "FLOOR") { - out_val = "floor(" + val1 + ")"; - } - else if (op == "CEIL") { - out_val = "ceil(" + val1 + ")"; - } - else if(op == "SNAP") { - out_val = "(floor(" + val1 + " / " + val2 + ") * " + val2 + ")"; - } - else if (op == "TRUNCATE") { - out_val = "trunc(" + val1 + ")"; - } - else if (op == "FRACTION") { - out_val = "frac(" + val1 + ")"; - } - else if (op == "MODULO") { - out_val = "(" + val1 + " % " + val2 + ")"; - } - else if (op == "PING-PONG") { - let store: string = parser_material_store_var_name(node) + "_pingpong"; - parser_material_write(parser_material_kong, "var " + store + ": float = 0.0;"); - parser_material_write(parser_material_kong, "if (" + val2 + " != 0.0) { " + store + " = abs(frac((" + val1 + " - " + val2 + ") / (" + val2 + " * 2.0)) * " + val2 + " * 2.0 - " + val2 + "); }"); - out_val = store; - } - else if (op == "SINE") { - out_val = "sin(" + val1 + ")"; - } - else if (op == "COSINE") { - out_val = "cos(" + val1 + ")"; - } - else if (op == "TANGENT") { - out_val = "tan(" + val1 + ")"; - } - else if (op == "ARCSINE") { - out_val = "asin(" + val1 + ")"; - } - else if (op == "ARCCOSINE") { - out_val = "acos(" + val1 + ")"; - } - else if (op == "ARCTANGENT") { - out_val = "atan(" + val1 + ")"; - } - else if (op == "ARCTAN2") { - out_val = "atan2(" + val1 + ", " + val2 + ")"; - } - else if (op == "HYPERBOLIC_SINE") { - out_val = "sinh(" + val1 + ")"; - } - else if (op == "HYPERBOLIC_COSINE") { - out_val = "cosh(" + val1 + ")"; - } - else if (op == "HYPERBOLIC_TANGENT") { - out_val = "tanh(" + val1 + ")"; - } - else if (op == "TO_RADIANS") { - out_val = "radians(" + val1 + ")"; - } - else if (op == "TO_DEGREES") { - out_val = "degrees(" + val1 + ")"; - } - if (use_clamp) { - return "clamp(" + out_val + ", 0.0, 1.0)"; - } - else { - return out_val; - } - } - else if (node.type == "SCRIPT_CPU") { - if (parser_material_script_links == null) { - parser_material_script_links = map_create(); - } - let script: buffer_t = node.buttons[0].default_value; - let str: string = sys_buffer_to_string(script); - let link: string = parser_material_node_name(node); - map_set(parser_material_script_links, link, str); - node_shader_add_constant(parser_material_kong, "" + link + ": float", "_" + link); - return "constants." + link; - } - else if (node.type == "SHADER_GPU") { - let shader: buffer_t = node.buttons[0].default_value; - let str: string = sys_buffer_to_string(shader); - return str == "" ? "0.0" : str; - } - else if (node.type == "RGBTOBW") { - let col: string = parser_material_parse_vector_input(node.inputs[0]); - return "(((" + col + ".r * 0.3 + " + col + ".g * 0.59 + " + col + ".b * 0.11) / 3.0) * 2.5)"; - } - else if (node.type == "SEPHSV") { - node_shader_add_function(parser_material_kong, str_hue_sat); - let col: string = parser_material_parse_vector_input(node.inputs[0]); - if (socket == node.outputs[0]) { - return "rgb_to_hsv(" + col + ").r"; - } - else if (socket == node.outputs[1]) { - return "rgb_to_hsv(" + col + ").g"; - } - else if (socket == node.outputs[2]) { - return "rgb_to_hsv(" + col + ").b"; - } - } - else if (node.type == "SEPRGB") { - let col: string = parser_material_parse_vector_input(node.inputs[0]); - if (socket == node.outputs[0]) { - return col + ".r"; - } - else if (socket == node.outputs[1]) { - return col + ".g"; - } - else if (socket == node.outputs[2]) { - return col + ".b"; - } - } - else if (node.type == "SEPXYZ") { - let vec: string = parser_material_parse_vector_input(node.inputs[0]); - if (socket == node.outputs[0]) { - return vec + ".x"; - } - else if (socket == node.outputs[1]) { - return vec + ".y"; - } - else if (socket == node.outputs[2]) { - return vec + ".z"; - } - } - else if (node.type == "VECT_MATH") { - let vec1: string = parser_material_parse_vector_input(node.inputs[0]); - let vec2: string = parser_material_parse_vector_input(node.inputs[1]); - let but: ui_node_button_t = node.buttons[0]; //operation; - let op: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); - op = string_replace_all(op, " ", "_"); - if (op == "DOT_PRODUCT") { - return "dot(" + vec1 + ", " + vec2 + ")"; - } - else if (op == "LENGTH") { - return "length(" + vec1 + ")"; - } - else if (op == "DISTANCE") { - return "distance(" + vec1 + ", " + vec2 + ")"; - } - else { - return "0.0"; - } - } - else if (node.type == "CLAMP") { - let val: string = parser_material_parse_value_input(node.inputs[0]); - let min: string = parser_material_parse_value_input(node.inputs[1]); - let max: string = parser_material_parse_value_input(node.inputs[2]); - let but: ui_node_button_t = node.buttons[0]; //operation; - let op: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); - op = string_replace_all(op, " ", "_"); - - if (op == "MIN_MAX") { - return "(clamp(" + val + ", " + min + ", " + max + "))"; - } - else if (op == "RANGE") { - return "(clamp(" + val + ", min(" + min + ", " + max + "), max(" + min + ", " + max + ")))"; - } - } - else if (node.type == "MAPRANGE") { - let val: string = parser_material_parse_value_input(node.inputs[0]); - let fmin: string = parser_material_parse_value_input(node.inputs[1]); - let fmax: string = parser_material_parse_value_input(node.inputs[2]); - let tmin: string = parser_material_parse_value_input(node.inputs[3]); - let tmax: string = parser_material_parse_value_input(node.inputs[4]); - - let use_clamp: bool = node.buttons[0].default_value[0] > 0; - - let a: string = "((" + tmin + " - " + tmax + ") / (" + fmin + " - " + fmax + "))"; - let out_val: string = "(" + a + " * " + val + " + " + tmin + " - " + a + " * " + fmin + ")"; - if (use_clamp) { - return "(clamp(" + out_val + ", " + tmin + ", " + tmax + "))"; - } - else { - return out_val; - } - } else if (map_get(parser_material_custom_nodes, node.type) != null) { let cb: any = map_get(parser_material_custom_nodes, node.type); return js_call_ptr_str(cb, node, socket.name); @@ -1808,64 +490,6 @@ function parser_material_get_coord(node: ui_node_t): string { } } -function parser_material_get_gradient(grad: string, co: string): string { - if (grad == "LINEAR") { - return co + ".x"; - } - else if (grad == "QUADRATIC") { - return "0.0"; - } - else if (grad == "EASING") { - return "0.0"; - } - else if (grad == "DIAGONAL") { - return "(" + co + ".x + " + co + ".y) * 0.5"; - } - else if (grad == "RADIAL") { - return "atan2(" + co + ".x, " + co + ".y) / (3.141592 * 2.0) + 0.5"; - } - else if (grad == "QUADRATIC_SPHERE") { - return "0.0"; - } - else { // "SPHERICAL" - return "max(1.0 - sqrt(" + co + ".x * " + co + ".x + " + co + ".y * " + co + ".y + " + co + ".z * " + co + ".z), 0.0)"; - } -} - -function parser_material_vector_curve(name: string, fac: string, points: f32_ptr, num: i32): string { - // Write Ys array - let ys_var: string = name + "_ys"; - parser_material_write(parser_material_kong, "var " + ys_var + ": float[" + num + "];"); // TODO: Make const - for (let i: i32 = 0; i < num; ++i) { - let p: f32 = ARRAY_ACCESS(points, i * 2 + 1); - parser_material_write(parser_material_kong, ys_var + "[" + i + "] = " + p + ";"); - } - // Get index - let fac_var: string = name + "_fac"; - parser_material_write(parser_material_kong, "var " + fac_var + ": float = " + fac + ";"); - let index: string = "0"; - for (let i: i32 = 1; i < num; ++i) { - let p: f32 = ARRAY_ACCESS(points, i * 2 + 0); - index += " + (" + fac_var + " > " + p + " ? 1 : 0)"; - } - // Write index - let index_var: string = name + "_i"; - parser_material_write(parser_material_kong, "var " + index_var + ": int = " + index + ";"); - // Linear - // Write Xs array - let facs_var: string = name + "_xs"; - parser_material_write(parser_material_kong, "var " + facs_var + ": float[" + num + "];"); // TODO: Make const - for (let i: i32 = 0; i < num; ++i) { - let p: f32 = ARRAY_ACCESS(points, i * 2 + 0); - parser_material_write(parser_material_kong, "" + facs_var + "[" + i + "] = " + p + ";"); - } - // Map vector - return "0.0"; //// - // return "lerp(" + - // ys_var + "[" + index_var + "], " + ys_var + "[" + index_var + " + 1], (" + fac_var + " - " + - // facs_var + "[" + index_var + "]) * (1.0 / (" + facs_var + "[" + index_var + " + 1] - " + facs_var + "[" + index_var + "])))"; -} - function parser_material_res_var_name(node: ui_node_t, socket: ui_node_socket_t): string { return parser_material_node_name(node) + "_" + parser_material_safesrc(socket.name) + "_res"; } @@ -1901,65 +525,6 @@ function parser_material_store_var_name(node: ui_node_t): string { return parser_material_node_name(node) + "_store"; } -function parser_material_texture_store(node: ui_node_t, tex: bind_tex_t, tex_name: string, color_space: i32): string { - array_push(parser_material_matcon.bind_textures, tex); - node_shader_context_add_elem(parser_material_kong.context, "tex", "short2norm"); - node_shader_add_texture(parser_material_kong, "" + tex_name); - let uv_name: string = ""; - if (parser_material_get_input_link(node.inputs[0]) != null) { - uv_name = parser_material_parse_vector_input(node.inputs[0]); - } - else { - uv_name = parser_material_tex_coord; - } - let tex_store: string = parser_material_store_var_name(node); - - if (parser_material_sample_keep_aspect) { - node_shader_add_constant(parser_material_kong, tex_name + "_size: float2", "_size(" + tex_name + ")"); - parser_material_write(parser_material_kong, "var " + tex_store + "_size: float2 = constants." + tex_name + "_size;"); - parser_material_write(parser_material_kong, "var " + tex_store + "_ax: float = " + tex_store + "_size.x / " + tex_store + "_size.y;"); - parser_material_write(parser_material_kong, "var " + tex_store + "_ay: float = " + tex_store + "_size.y / " + tex_store + "_size.x;"); - parser_material_write(parser_material_kong, "var " + tex_store + "_uv: float2 = ((" + uv_name + ".xy / float(" + parser_material_sample_uv_scale + ") - float2(0.5, 0.5)) * float2(max(" + tex_store + "_ay, 1.0), max(" + tex_store + "_ax, 1.0))) + float2(0.5, 0.5);"); - parser_material_write(parser_material_kong, "if (" + tex_store + "_uv.x < 0.0 || " + tex_store + "_uv.y < 0.0 || " + tex_store + "_uv.x > 1.0 || " + tex_store + "_uv.y > 1.0) { discard; }"); - parser_material_write(parser_material_kong, tex_store + "_uv = " + tex_store + "_uv * float(" + parser_material_sample_uv_scale + ");"); - uv_name = tex_store + "_uv"; - } - - if (parser_material_triplanar) { - parser_material_write(parser_material_kong, "var " + tex_store + ": float4 = float4(0.0, 0.0, 0.0, 0.0);"); - parser_material_write(parser_material_kong, "if (tex_coord_blend.x > 0.0) {" + tex_store + " += sample(" + tex_name + ", sampler_linear, " + uv_name + ".xy) * tex_coord_blend.x; }"); - parser_material_write(parser_material_kong, "if (tex_coord_blend.y > 0.0) {" + tex_store + " += sample(" + tex_name + ", sampler_linear, " + uv_name + "1.xy) * tex_coord_blend.y; }"); - parser_material_write(parser_material_kong, "if (tex_coord_blend.z > 0.0) {" + tex_store + " += sample(" + tex_name + ", sampler_linear, " + uv_name + "2.xy) * tex_coord_blend.z; }"); - } - else { - if (parser_material_is_frag) { - map_set(parser_material_texture_map, tex_store, "sample(" + tex_name + ", sampler_linear, " + uv_name + ".xy)"); - parser_material_write(parser_material_kong, "var " + tex_store + ": float4 = sample(" + tex_name + ", sampler_linear, " + uv_name + ".xy);"); - } - else { - map_set(parser_material_texture_map, tex_store, "sample_lod(" + tex_name + ", sampler_linear, " + uv_name + ".xy, 0.0)"); - parser_material_write(parser_material_kong, "var " + tex_store + ": float4 = sample_lod(" + tex_name + ", sampler_linear, " + uv_name + ".xy, 0.0);"); - } - if (!ends_with(tex.file, ".jpg")) { // Pre-mult alpha - parser_material_write(parser_material_kong, tex_store + ".rgb = " + tex_store + ".rgb * " + tex_store + ".a;"); - } - } - - if (parser_material_transform_color_space) { - // Base color socket auto-converts from sRGB to linear - if (color_space == color_space_t.LINEAR && parser_material_parsing_basecolor) { // Linear to sRGB - parser_material_write(parser_material_kong, tex_store + ".rgb = pow3(" + tex_store + ".rgb, float3(2.2, 2.2, 2.2));"); - } - else if (color_space == color_space_t.SRGB && !parser_material_parsing_basecolor) { // sRGB to linear - parser_material_write(parser_material_kong, tex_store + ".rgb = pow3(" + tex_store + ".rgb, float3(1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2));"); - } - else if (color_space == color_space_t.DIRECTX_NORMAL_MAP) { // DirectX normal map to OpenGL normal map - parser_material_write(parser_material_kong, tex_store + ".y = 1.0 - " + tex_store + ".y;"); - } - } - return tex_store; -} - function parser_material_vec1(v: f32): string { return f32_to_string_with_zeros(v); // return "float(" + v + ")"; @@ -2048,36 +613,6 @@ function parser_material_make_bind_tex(tex_name: string, file: string): bind_tex return tex; } -function parser_material_make_texture(image_node: ui_node_t, tex_name: string): bind_tex_t { - let i: i32 = image_node.buttons[0].default_value[0]; - if (i > 9000) { // 9999 - Texture deleted, use pink now - return null; - } - let filepath: string = parser_material_enum_data(base_enum_texts(image_node.type)[i]); - if (filepath == "" || string_index_of(filepath, ".") == -1) { - return null; - } - - return parser_material_make_bind_tex(tex_name, filepath); -} - -function parser_material_is_pow(num: i32): bool { - return ((num & (num - 1)) == 0) && num != 0; -} - -function parser_material_asset_path(s: string): string { - return s; -} - -function parser_material_extract_filename(s: string): string { - let ar: string[] = string_split(s, "."); - return ar[ar.length - 2] + "." + ar[ar.length - 1]; -} - -function parser_material_safestr(s: string): string { - return s; -} - function u8_array_string_at(a: u8_array_t, i: i32): string { let s: string = u8_array_to_string(a); let ss: string[] = string_split(s, "\n"); @@ -2094,10 +629,3 @@ type shader_out_t = { out_emission?: string; out_subsurface?: string; }; - -enum color_space_t { - AUTO, // sRGB for base color, otherwise linear - LINEAR, - SRGB, - DIRECTX_NORMAL_MAP, -} diff --git a/paint/sources/strings.ts b/paint/sources/strings.ts index 9f7449ae..a26f9b39 100644 --- a/paint/sources/strings.ts +++ b/paint/sources/strings.ts @@ -32,386 +32,3 @@ function strings_graphics_api(): string { return "Vulkan"; ///end } - -let str_tex_checker: string = "\ -fun tex_checker(co: float3, col1: float3, col2: float3, scale: float): float3 { \ - /* Prevent precision issues on unit coordinates */ \ - var p: float3 = (co + 0.000001 * 0.999999) * scale; \ - var xi: float = abs(floor(p.x)); \ - var yi: float = abs(floor(p.y)); \ - var zi: float = abs(floor(p.z)); \ - /* var check: bool = (xi % 2.0 == yi % 2.0) == zi % 2.0;*/ \ - var checka: int = 0; \ - var checkb: int = 0; \ - if (xi % 2.0 == yi % 2.0) { checka = 1; } \ - if (zi % 2.0 != 0.0) { checkb = 1; } \ - if (checka == checkb) { return col1; } return col2; \ -} \ -fun tex_checker_f(co: float3, scale: float): float { \ - var p: float3 = (co + 0.000001 * 0.999999) * scale; \ - var xi: float = abs(floor(p.x)); \ - var yi: float = abs(floor(p.y)); \ - var zi: float = abs(floor(p.z)); \ - /*return float((xi % 2.0 == yi % 2.0) == zi % 2.0);*/ \ - var checka: int = 0; \ - var checkb: int = 0; \ - if (xi % 2.0 == yi % 2.0) { checka = 1; } \ - if (zi % 2.0 != 0.0) { checkb = 1; } \ - if (checka == checkb) { return 1.0; } return 0.0; \ - \ -} \ -"; - - // Created by inigo quilez - iq/2013 - // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License -let str_tex_voronoi: string = "\ -fun tex_voronoi(x: float3): float4 { \ - var p: float3 = floor3(x); \ - var f: float3 = frac3(x); \ - var id: float = 0.0; \ - var res: float = 100.0; \ - for (var k: int = 0; k <= 2; k += 1) \ - for (var j: int = 0; j <= 2; j += 1) \ - for (var i: int = 0; i <= 2; i += 1) { \ - var b: float3 = float3(float(i - 1), float(j - 1), float(k - 1)); \ - var pb: float3 = p + b; \ - var snoise_sample: float3 = sample(snoise256, sampler_linear, (pb.xy + float2(3.0, 1.0) * pb.z + 0.5) / 256.0).xyz; \ - var r: float3 = b - f + snoise_sample; \ - var d: float = dot(r, r); \ - if (d < res) { \ - id = dot(p + b, float3(1.0, 57.0, 113.0)); \ - res = d; \ - } \ - } \ - /*var col: float3 = 0.5 + 0.5 * cos(id * 0.35 + float3(0.0, 1.0, 2.0));*/ \ - var col: float3; \ - col.x = 0.5 + 0.5 * cos(id * 0.35 + 0.0); \ - col.y = 0.5 + 0.5 * cos(id * 0.35 + 1.0); \ - col.z = 0.5 + 0.5 * cos(id * 0.35 + 2.0); \ - return float4(col, sqrt(res)); \ -} \ -"; - - // By Morgan McGuire @morgan3d, http://graphicscodex.com Reuse permitted under the BSD license. - // https://www.shadertoy.com/view/4dS3Wd -let str_tex_noise: string = "\ -fun hash(n: float): float { return frac(sin(n) * 10000.0); } \ -fun tex_noise_f(x: float3): float { \ - var step: float3 = float3(110.0, 241.0, 171.0); \ - var i: float3 = floor3(x); \ - var f: float3 = frac3(x); \ - var n: float = dot(i, step); \ - var u: float3 = f * f * (3.0 - 2.0 * f); \ - return lerp(lerp(lerp(hash(n + dot(step, float3(0.0, 0.0, 0.0))), hash(n + dot(step, float3(1.0, 0.0, 0.0))), u.x), \ - lerp(hash(n + dot(step, float3(0.0, 1.0, 0.0))), hash(n + dot(step, float3(1.0, 1.0, 0.0))), u.x), u.y), \ - lerp(lerp(hash(n + dot(step, float3(0.0, 0.0, 1.0))), hash(n + dot(step, float3(1.0, 0.0, 1.0))), u.x), \ - lerp(hash(n + dot(step, float3(0.0, 1.0, 1.0))), hash(n + dot(step, float3(1.0, 1.0, 1.0))), u.x), u.y), u.z); \ -} \ -fun tex_noise(p: float3): float { \ - p = p * 1.25; \ - var f: float = 0.5 * tex_noise_f(p); p = p * 2.01; \ - f += 0.25 * tex_noise_f(p); p = p * 2.02; \ - f += 0.125 * tex_noise_f(p); p = p * 2.03; \ - f += 0.0625 * tex_noise_f(p); \ - return 1.0 - f; \ -} \ -"; - - // Based on noise created by Nikita Miropolskiy, nikat/2013 - // Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License -let str_tex_musgrave: string = "\ -fun random3(c: float3): float3 { \ - var j: float = 4096.0 * sin(dot(c, float3(17.0, 59.4, 15.0))); \ - var r: float3; \ - r.z = frac(512.0 * j); \ - j *= 0.125; \ - r.x = frac(512.0 * j); \ - j *= 0.125; \ - r.y = frac(512.0 * j); \ - return r - 0.5; \ -} \ -fun tex_musgrave_f(p: float3): float { \ - var F3: float = 0.3333333; \ - var G3: float = 0.1666667; \ - var s: float3 = floor3(p + dot(p, float3(F3, F3, F3))); \ - var x: float3 = p - s + dot(s, float3(G3, G3, G3)); \ - var e: float3 = step3(float3(0.0, 0.0, 0.0), x - x.yzx); \ - var i1: float3 = e * (1.0 - e.zxy); \ - var i2: float3 = 1.0 - e.zxy * (1.0 - e); \ - var x1: float3 = x - i1 + G3; \ - var x2: float3 = x - i2 + 2.0 * G3; \ - var x3: float3 = x - 1.0 + 3.0 * G3; \ - var w: float4; \ - var d: float4; \ - w.x = dot(x, x); \ - w.y = dot(x1, x1); \ - w.z = dot(x2, x2); \ - w.w = dot(x3, x3); \ - w = max4(float4(0.6, 0.6, 0.6, 0.6) - w, float4(0.0, 0.0, 0.0, 0.0)); \ - d.x = dot(random3(s), x); \ - d.y = dot(random3(s + i1), x1); \ - d.z = dot(random3(s + i2), x2); \ - d.w = dot(random3(s + 1.0), x3); \ - w *= w; \ - w *= w; \ - d *= w; \ - return clamp(dot(d, float4(52.0, 52.0, 52.0, 52.0)), 0.0, 1.0); \ -} \ -"; - -let str_hue_sat: string = "\ -fun hsv_to_rgb(c: float3): float3 { \ - var K: float4 = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); \ - var p: float3 = abs3(frac3(c.xxx + K.xyz) * 6.0 - K.www); \ - return lerp3(K.xxx, clamp3(p - K.xxx, float3(0.0, 0.0, 0.0), float3(1.0, 1.0, 1.0)), c.y) * c.z; \ -} \ -fun rgb_to_hsv(c: float3): float3 { \ - var K: float4 = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); \ - var p: float4 = lerp4(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g)); \ - var q: float4 = lerp4(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r)); \ - var d: float = q.x - min(q.w, q.y); \ - var e: float = 0.0000000001; \ - return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); \ -} \ -fun hue_sat(col: float3, shift: float4): float3 { \ - var hsv: float3 = rgb_to_hsv(col); \ - hsv.x += shift.x; \ - hsv.y *= shift.y; \ - hsv.z *= shift.z; \ - return lerp3(hsv_to_rgb(hsv), col, shift.w); \ -} \ -"; - -// https://x.com/Donzanoid/status/903424376707657730 -let str_wavelength_to_rgb: string = "\ -fun wavelength_to_rgb(t: float): float3 { \ - var r: float3 = t * 2.1 - float3(1.8, 1.14, 0.3); \ - return 1.0 - r * r; \ -} \ -"; - -let str_tex_magic: string = "\ -fun tex_magic(p: float3): float3 { \ - var a: float = 1.0 - (sin(p.x) + sin(p.y)); \ - var b: float = 1.0 - sin(p.x - p.y); \ - var c: float = 1.0 - sin(p.x + p.y); \ - return float3(a, b, c); \ -} \ -fun tex_magic_f(p: float3): float { \ - var c: float3 = tex_magic(p); \ - return (c.x + c.y + c.z) / 3.0; \ -} \ -"; - -let str_tex_brick: string = "\ -fun tex_brick_noise(n: int): float { \ - var nn: int; \ - n = (n >> 13) ^ n; \ - /*nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;*/ \ - nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 2147483647; \ - return 0.5 * float(nn) / 1073741824.0; \ -} \ -fun tex_brick(p: float3, c1: float3, c2: float3, c3: float3): float3 { \ - var brick_size: float3 = float3(0.9, 0.49, 0.49); \ - var mortar_size: float3 = float3(0.05, 0.1, 0.1); \ - p /= brick_size / 2.0; \ - if (frac(p.y * 0.5) > 0.5) { p.x += 0.5; } \ - var col: float = floor(p.x / (brick_size.x + (mortar_size.x * 2.0))); \ - var row: float = p.y; \ - p = frac3(p); \ - var b: float3 = step3(p, 1.0 - mortar_size); \ - /*var tint: float = min(max(tex_brick_noise((int(col) << 16) + (int(row) & 0xffff)), 0.0), 1.0);*/ \ - var tint: float = min(max(tex_brick_noise((int(col) << 16) + (int(row) & 65535)), 0.0), 1.0); \ - return lerp3(c3, lerp3(c1, c2, tint), b.x * b.y * b.z); \ -} \ -fun tex_brick_f(p: float3): float { \ - p /= float3(0.9, 0.49, 0.49) / 2.0; \ - if (frac(p.y * 0.5) > 0.5) { p.x += 0.5; } \ - p = frac3(p); \ - var b: float3 = step3(p, float3(0.95, 0.9, 0.9)); \ - return lerp(1.0, 0.0, b.x * b.y * b.z); \ -} \ -"; - -let str_tex_wave: string = "\ -fun tex_wave_f(p: float3): float { \ - return 1.0 - sin((p.x + p.y) * 10.0); \ -} \ -"; - -let str_brightcontrast: string = "\ -fun brightcontrast(col: float3, bright: float, contr: float): float3 { \ - var a: float = 1.0 + contr; \ - var b: float = bright - contr * 0.5; \ - return max3(a * col + b, float3(0.0, 0.0, 0.0)); \ -} \ -"; - -let str_cotangent_frame: string = "\ -fun cotangent_frame(n: float3, p: float3, tex_coord: float2): float3x3 { \ - var duv1: float2 = ddx2(tex_coord); \ - var duv2: float2 = ddy2(tex_coord); \ - var dp1: float3 = ddx3(p); \ - var dp2: float3 = ddy3(p); \ - var dp2perp: float3 = cross(dp2, n); \ - var dp1perp: float3 = cross(n, dp1); \ - var t: float3 = dp2perp * duv1.x + dp1perp * duv2.x; \ - var b: float3 = dp2perp * duv1.y + dp1perp * duv2.y; \ - var invmax: float = rsqrt(max(dot(t, t), dot(b, b))); \ - return float3x3(t * invmax, b * invmax, n); \ -} \ -"; - -let str_octahedron_wrap: string = "\ -fun octahedron_wrap(v: float2): float2 { \ - var a: float2; \ - if (v.x >= 0.0) { a.x = 1.0; } else { a.x = -1.0; } \ - if (v.y >= 0.0) { a.y = 1.0; } else { a.y = -1.0; } \ - var r: float2; \ - r.x = abs(v.y); \ - r.y = abs(v.x); \ - r.x = 1.0 - r.x; \ - r.y = 1.0 - r.y; \ - return r * a; \ -} \ -"; - -// let str_octahedron_wrap: string = "\ -// fun octahedron_wrap(v: float2): float2 { \ -// return (1.0 - abs(v.yx)) * (float2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0)); \ -// } \ -// "; - -let str_pack_float_int16: string = "\ -fun pack_f32_i16(f: float, i: uint): float { \ - return 0.062504762 * min(f, 0.9999) + 0.062519999 * float(i); \ -} \ -"; - -// let str_pack_float_int16: string = "\ -// fun pack_f32_i16(f: float, i: uint): float { \ -// var prec: float = float(1 << 16); \ -// var maxi: float = float(1 << 4); \ -// var prec_minus_one: float = prec - 1.0; \ -// var t1: float = ((prec / maxi) - 1.0) / prec_minus_one; \ -// var t2: float = (prec / maxi) / prec_minus_one; \ -// return t1 * f + t2 * float(i); \ -// } \ -// "; - -let str_create_basis: string = "\ -fun create_basis(normal: float3, out tangent: float3, out binormal: float3) { \ - tangent = normalize(camera_right - normal * dot(camera_right, normal)); \ - binormal = cross(tangent, normal); \ -} \ -"; - -let str_sh_irradiance: string = "\ -fun sh_irradiance(nor: float3): float3 { \ - var c1: float = 0.429043; \ - var c2: float = 0.511664; \ - var c3: float = 0.743125; \ - var c4: float = 0.886227; \ - var c5: float = 0.247708; \ - var cl00: float3 = float3(constants.shirr0.x, constants.shirr0.y, constants.shirr0.z); \ - var cl1m1: float3 = float3(constants.shirr0.w, constants.shirr1.x, constants.shirr1.y); \ - var cl10: float3 = float3(constants.shirr1.z, constants.shirr1.w, constants.shirr2.x); \ - var cl11: float3 = float3(constants.shirr2.y, constants.shirr2.z, constants.shirr2.w); \ - var cl2m2: float3 = float3(constants.shirr3.x, constants.shirr3.y, constants.shirr3.z); \ - var cl2m1: float3 = float3(constants.shirr3.w, constants.shirr4.x, constants.shirr4.y); \ - var cl20: float3 = float3(constants.shirr4.z, constants.shirr4.w, constants.shirr5.x); \ - var cl21: float3 = float3(constants.shirr5.y, constants.shirr5.z, constants.shirr5.w); \ - var cl22: float3 = float3(constants.shirr6.x, constants.shirr6.y, constants.shirr6.z); \ - return ( \ - cl22 * c1 * (nor.y * nor.y - (-nor.z) * (-nor.z)) + \ - cl20 * c3 * nor.x * nor.x + \ - cl00 * c4 - \ - cl20 * c5 + \ - cl2m2 * 2.0 * c1 * nor.y * (-nor.z) + \ - cl21 * 2.0 * c1 * nor.y * nor.x + \ - cl2m1 * 2.0 * c1 * (-nor.z) * nor.x + \ - cl11 * 2.0 * c2 * nor.y + \ - cl1m1 * 2.0 * c2 * (-nor.z) + \ - cl10 * 2.0 * c2 * nor.x \ - ); \ -} \ -"; - -let str_envmap_equirect: string = "\ -fun envmap_equirect(normal: float3, angle: float): float2 { \ - var PI: float = 3.1415926535; \ - var PI2: float = PI * 2.0; \ - var phi: float = acos(normal.z); \ - var theta: float = atan2(-normal.y, normal.x) + PI + angle; \ - return float2(theta / PI2, phi / PI); \ -} \ -"; - -let str_envmap_sample: string = "\ -fun envmap_sample(lod: float, coord: float2): float3 { \ - if (lod == 0.0) { \ - return sample_lod(senvmap_radiance, sampler_linear, coord, 0.0).rgb; \ - } \ - if (lod == 1.0) { \ - return sample_lod(senvmap_radiance0, sampler_linear, coord, 0.0).rgb; \ - } \ - if (lod == 2.0) { \ - return sample_lod(senvmap_radiance1, sampler_linear, coord, 0.0).rgb; \ - } \ - if (lod == 3.0) { \ - return sample_lod(senvmap_radiance2, sampler_linear, coord, 0.0).rgb; \ - } \ - if (lod == 4.0) { \ - return sample_lod(senvmap_radiance3, sampler_linear, coord, 0.0).rgb; \ - } \ - return sample_lod(senvmap_radiance4, sampler_linear, coord, 0.0).rgb; \ -} \ -"; - -let str_get_pos_nor_from_depth: string = "\ -fun get_pos_from_depth(uv: float2, invVP: float4x4): float3 { \ - var depth: float = sample_lod(gbufferD, sampler_linear, float2(uv.x, 1.0 - uv.y), 0.0).r; \ - var wpos: float4 = float4(uv * 2.0 - 1.0, depth, 1.0); \ - wpos = invVP * wpos; \ - return wpos.xyz / wpos.w; \ -} \ -fun get_nor_from_depth(p0: float3, uv: float2, invVP: float4x4, tex_step: float2): float3 { \ - var p1: float3 = get_pos_from_depth(uv + float2(tex_step.x * 4.0, 0.0), invVP); \ - var p2: float3 = get_pos_from_depth(uv + float2(0.0, tex_step.y * 4.0), invVP); \ - return normalize(cross(p2 - p0, p1 - p0)); \ -} \ -"; - -//// -let str_get_smudge_tool_weight: string = "\ -fun get_smudge_tool_weight(i: int): float { \ - if (i == 0) { return 1.0 / 28.0; } \ - if (i == 1) { return 2.0 / 28.0; } \ - if (i == 2) { return 3.0 / 28.0; } \ - if (i == 3) { return 4.0 / 28.0; } \ - if (i == 4) { return 5.0 / 28.0; } \ - if (i == 5) { return 6.0 / 28.0; } \ - return 7.0 / 28.0; \ -} \ -"; - -let str_get_blur_tool_weight: string = "\ -fun get_blur_tool_weight(i: int): float { \ - if (i == 0) { return 0.034619 / 2.0; } \ - if (i == 1) { return 0.044859 / 2.0; } \ - if (i == 2) { return 0.055857 / 2.0; } \ - if (i == 3) { return 0.066833 / 2.0; } \ - if (i == 4) { return 0.076841 / 2.0; } \ - if (i == 5) { return 0.084894 / 2.0; } \ - if (i == 6) { return 0.090126 / 2.0; } \ - if (i == 7) { return 0.09194 / 2.0; } \ - if (i == 8) { return 0.090126 / 2.0; } \ - if (i == 9) { return 0.084894 / 2.0; } \ - if (i == 10) { return 0.076841 / 2.0; } \ - if (i == 11) { return 0.066833 / 2.0; } \ - if (i == 12) { return 0.055857 / 2.0; } \ - if (i == 13) { return 0.044859 / 2.0; } \ - return 0.034619 / 2.0; \ -} \ -"; -////