diff options
author | Hans Goudey <h.goudey@me.com> | 2022-08-31 16:07:51 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-08-31 16:15:09 +0300 |
commit | 3ecb21346248014aff621ec3b97ccbc1e7774653 (patch) | |
tree | b571a51b93d61efc01bf8a75a74ecade8e463d16 | |
parent | b5af7f967e6d5d2e7432d6efa2f47050a5bfc576 (diff) | |
parent | 773241add9d876aa0b4ba011745208f61b53a4e2 (diff) |
Merge branch 'master' into refactor-mesh-material-index-genericrefactor-mesh-material-index-generic
235 files changed, 5202 insertions, 3497 deletions
diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp index 04eb1576330..9505f4ba58f 100644 --- a/intern/cycles/blender/shader.cpp +++ b/intern/cycles/blender/shader.cpp @@ -350,6 +350,33 @@ static ShaderNode *add_node(Scene *scene, mix->set_use_clamp(b_mix_node.use_clamp()); node = mix; } + else if (b_node.is_a(&RNA_ShaderNodeMix)) { + BL::ShaderNodeMix b_mix_node(b_node); + if (b_mix_node.data_type() == BL::ShaderNodeMix::data_type_VECTOR) { + if (b_mix_node.factor_mode() == BL::ShaderNodeMix::factor_mode_UNIFORM) { + MixVectorNode *mix_node = graph->create_node<MixVectorNode>(); + mix_node->set_use_clamp(b_mix_node.clamp_factor()); + node = mix_node; + } + else { + MixVectorNonUniformNode *mix_node = graph->create_node<MixVectorNonUniformNode>(); + mix_node->set_use_clamp(b_mix_node.clamp_factor()); + node = mix_node; + } + } + else if (b_mix_node.data_type() == BL::ShaderNodeMix::data_type_RGBA) { + MixColorNode *mix_node = graph->create_node<MixColorNode>(); + mix_node->set_blend_type((NodeMix)b_mix_node.blend_type()); + mix_node->set_use_clamp(b_mix_node.clamp_factor()); + mix_node->set_use_clamp_result(b_mix_node.clamp_result()); + node = mix_node; + } + else { + MixFloatNode *mix_node = graph->create_node<MixFloatNode>(); + mix_node->set_use_clamp(b_mix_node.clamp_factor()); + node = mix_node; + } + } else if (b_node.is_a(&RNA_ShaderNodeSeparateRGB)) { node = graph->create_node<SeparateRGBNode>(); } @@ -1072,7 +1099,9 @@ static bool node_use_modified_socket_name(ShaderNode *node) return true; } -static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_socket) +static ShaderInput *node_find_input_by_name(BL::Node b_node, + ShaderNode *node, + BL::NodeSocket &b_socket) { string name = b_socket.identifier(); ShaderInput *input = node->input(name.c_str()); @@ -1082,6 +1111,35 @@ static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_ if (string_startswith(name, "Shader")) { string_replace(name, "Shader", "Closure"); } + + /* Map mix node internal name for shader. */ + if (b_node.is_a(&RNA_ShaderNodeMix)) { + if (string_endswith(name, "Factor_Float")) { + string_replace(name, "Factor_Float", "Factor"); + } + else if (string_endswith(name, "Factor_Vector")) { + string_replace(name, "Factor_Vector", "Factor"); + } + else if (string_endswith(name, "A_Float")) { + string_replace(name, "A_Float", "A"); + } + else if (string_endswith(name, "B_Float")) { + string_replace(name, "B_Float", "B"); + } + else if (string_endswith(name, "A_Color")) { + string_replace(name, "A_Color", "A"); + } + else if (string_endswith(name, "B_Color")) { + string_replace(name, "B_Color", "B"); + } + else if (string_endswith(name, "A_Vector")) { + string_replace(name, "A_Vector", "A"); + } + else if (string_endswith(name, "B_Vector")) { + string_replace(name, "B_Vector", "B"); + } + } + input = node->input(name.c_str()); if (!input) { @@ -1111,7 +1169,9 @@ static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_ return input; } -static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::NodeSocket &b_socket) +static ShaderOutput *node_find_output_by_name(BL::Node b_node, + ShaderNode *node, + BL::NodeSocket &b_socket) { string name = b_socket.identifier(); ShaderOutput *output = node->output(name.c_str()); @@ -1122,6 +1182,21 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::NodeSocket & name = "Closure"; output = node->output(name.c_str()); } + /* Map internal name for shader. */ + if (b_node.is_a(&RNA_ShaderNodeMix)) { + if (string_endswith(name, "Result_Float")) { + string_replace(name, "Result_Float", "Result"); + output = node->output(name.c_str()); + } + else if (string_endswith(name, "Result_Color")) { + string_replace(name, "Result_Color", "Result"); + output = node->output(name.c_str()); + } + else if (string_endswith(name, "Result_Vector")) { + string_replace(name, "Result_Vector", "Result"); + output = node->output(name.c_str()); + } + } } return output; @@ -1267,7 +1342,11 @@ static void add_nodes(Scene *scene, if (node) { /* map node sockets for linking */ for (BL::NodeSocket &b_input : b_node.inputs) { - ShaderInput *input = node_find_input_by_name(node, b_input); + if (b_input.is_unavailable()) { + /* Skip unavailable sockets. */ + continue; + } + ShaderInput *input = node_find_input_by_name(b_node, node, b_input); if (!input) { /* XXX should not happen, report error? */ continue; @@ -1277,7 +1356,11 @@ static void add_nodes(Scene *scene, set_default_value(input, b_input, b_data, b_ntree); } for (BL::NodeSocket &b_output : b_node.outputs) { - ShaderOutput *output = node_find_output_by_name(node, b_output); + if (b_output.is_unavailable()) { + /* Skip unavailable sockets. */ + continue; + } + ShaderOutput *output = node_find_output_by_name(b_node, node, b_output); if (!output) { /* XXX should not happen, report error? */ continue; diff --git a/intern/cycles/kernel/osl/shaders/CMakeLists.txt b/intern/cycles/kernel/osl/shaders/CMakeLists.txt index 741bce7c399..c79af3f6112 100644 --- a/intern/cycles/kernel/osl/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/osl/shaders/CMakeLists.txt @@ -57,6 +57,10 @@ set(SRC_OSL node_math.osl node_mix.osl node_mix_closure.osl + node_mix_color.osl + node_mix_float.osl + node_mix_vector.osl + node_mix_vector_non_uniform.osl node_musgrave_texture.osl node_noise_texture.osl node_normal.osl @@ -109,6 +113,7 @@ file(GLOB SRC_OSL_HEADER_DIST ${OSL_SHADER_DIR}/*.h) set(SRC_OSL_HEADERS node_color.h + node_color_blend.h node_fresnel.h node_hash.h node_math.h diff --git a/intern/cycles/kernel/osl/shaders/node_color_blend.h b/intern/cycles/kernel/osl/shaders/node_color_blend.h new file mode 100644 index 00000000000..ab4b4809a97 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_color_blend.h @@ -0,0 +1,264 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +color node_mix_blend(float t, color col1, color col2) +{ + return mix(col1, col2, t); +} + +color node_mix_add(float t, color col1, color col2) +{ + return mix(col1, col1 + col2, t); +} + +color node_mix_mul(float t, color col1, color col2) +{ + return mix(col1, col1 * col2, t); +} + +color node_mix_screen(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + return color(1.0) - (color(tm) + t * (color(1.0) - col2)) * (color(1.0) - col1); +} + +color node_mix_overlay(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color outcol = col1; + + if (outcol[0] < 0.5) + outcol[0] *= tm + 2.0 * t * col2[0]; + else + outcol[0] = 1.0 - (tm + 2.0 * t * (1.0 - col2[0])) * (1.0 - outcol[0]); + + if (outcol[1] < 0.5) + outcol[1] *= tm + 2.0 * t * col2[1]; + else + outcol[1] = 1.0 - (tm + 2.0 * t * (1.0 - col2[1])) * (1.0 - outcol[1]); + + if (outcol[2] < 0.5) + outcol[2] *= tm + 2.0 * t * col2[2]; + else + outcol[2] = 1.0 - (tm + 2.0 * t * (1.0 - col2[2])) * (1.0 - outcol[2]); + + return outcol; +} + +color node_mix_sub(float t, color col1, color col2) +{ + return mix(col1, col1 - col2, t); +} + +color node_mix_div(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color outcol = col1; + + if (col2[0] != 0.0) + outcol[0] = tm * outcol[0] + t * outcol[0] / col2[0]; + if (col2[1] != 0.0) + outcol[1] = tm * outcol[1] + t * outcol[1] / col2[1]; + if (col2[2] != 0.0) + outcol[2] = tm * outcol[2] + t * outcol[2] / col2[2]; + + return outcol; +} + +color node_mix_diff(float t, color col1, color col2) +{ + return mix(col1, abs(col1 - col2), t); +} + +color node_mix_dark(float t, color col1, color col2) +{ + return mix(col1, min(col1, col2), t); +} + +color node_mix_light(float t, color col1, color col2) +{ + return mix(col1, max(col1, col2), t); +} + +color node_mix_dodge(float t, color col1, color col2) +{ + color outcol = col1; + + if (outcol[0] != 0.0) { + float tmp = 1.0 - t * col2[0]; + if (tmp <= 0.0) + outcol[0] = 1.0; + else if ((tmp = outcol[0] / tmp) > 1.0) + outcol[0] = 1.0; + else + outcol[0] = tmp; + } + if (outcol[1] != 0.0) { + float tmp = 1.0 - t * col2[1]; + if (tmp <= 0.0) + outcol[1] = 1.0; + else if ((tmp = outcol[1] / tmp) > 1.0) + outcol[1] = 1.0; + else + outcol[1] = tmp; + } + if (outcol[2] != 0.0) { + float tmp = 1.0 - t * col2[2]; + if (tmp <= 0.0) + outcol[2] = 1.0; + else if ((tmp = outcol[2] / tmp) > 1.0) + outcol[2] = 1.0; + else + outcol[2] = tmp; + } + + return outcol; +} + +color node_mix_burn(float t, color col1, color col2) +{ + float tmp, tm = 1.0 - t; + + color outcol = col1; + + tmp = tm + t * col2[0]; + if (tmp <= 0.0) + outcol[0] = 0.0; + else if ((tmp = (1.0 - (1.0 - outcol[0]) / tmp)) < 0.0) + outcol[0] = 0.0; + else if (tmp > 1.0) + outcol[0] = 1.0; + else + outcol[0] = tmp; + + tmp = tm + t * col2[1]; + if (tmp <= 0.0) + outcol[1] = 0.0; + else if ((tmp = (1.0 - (1.0 - outcol[1]) / tmp)) < 0.0) + outcol[1] = 0.0; + else if (tmp > 1.0) + outcol[1] = 1.0; + else + outcol[1] = tmp; + + tmp = tm + t * col2[2]; + if (tmp <= 0.0) + outcol[2] = 0.0; + else if ((tmp = (1.0 - (1.0 - outcol[2]) / tmp)) < 0.0) + outcol[2] = 0.0; + else if (tmp > 1.0) + outcol[2] = 1.0; + else + outcol[2] = tmp; + + return outcol; +} + +color node_mix_hue(float t, color col1, color col2) +{ + color outcol = col1; + color hsv2 = rgb_to_hsv(col2); + + if (hsv2[1] != 0.0) { + color hsv = rgb_to_hsv(outcol); + hsv[0] = hsv2[0]; + color tmp = hsv_to_rgb(hsv); + + outcol = mix(outcol, tmp, t); + } + + return outcol; +} + +color node_mix_sat(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color outcol = col1; + + color hsv = rgb_to_hsv(outcol); + + if (hsv[1] != 0.0) { + color hsv2 = rgb_to_hsv(col2); + + hsv[1] = tm * hsv[1] + t * hsv2[1]; + outcol = hsv_to_rgb(hsv); + } + + return outcol; +} + +color node_mix_val(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color hsv = rgb_to_hsv(col1); + color hsv2 = rgb_to_hsv(col2); + + hsv[2] = tm * hsv[2] + t * hsv2[2]; + + return hsv_to_rgb(hsv); +} + +color node_mix_color(float t, color col1, color col2) +{ + color outcol = col1; + color hsv2 = rgb_to_hsv(col2); + + if (hsv2[1] != 0.0) { + color hsv = rgb_to_hsv(outcol); + hsv[0] = hsv2[0]; + hsv[1] = hsv2[1]; + color tmp = hsv_to_rgb(hsv); + + outcol = mix(outcol, tmp, t); + } + + return outcol; +} + +color node_mix_soft(float t, color col1, color col2) +{ + float tm = 1.0 - t; + + color one = color(1.0); + color scr = one - (one - col2) * (one - col1); + + return tm * col1 + t * ((one - col1) * col2 * col1 + col1 * scr); +} + +color node_mix_linear(float t, color col1, color col2) +{ + color outcol = col1; + + if (col2[0] > 0.5) + outcol[0] = col1[0] + t * (2.0 * (col2[0] - 0.5)); + else + outcol[0] = col1[0] + t * (2.0 * (col2[0]) - 1.0); + + if (col2[1] > 0.5) + outcol[1] = col1[1] + t * (2.0 * (col2[1] - 0.5)); + else + outcol[1] = col1[1] + t * (2.0 * (col2[1]) - 1.0); + + if (col2[2] > 0.5) + outcol[2] = col1[2] + t * (2.0 * (col2[2] - 0.5)); + else + outcol[2] = col1[2] + t * (2.0 * (col2[2]) - 1.0); + + return outcol; +} + +color node_mix_clamp(color col) +{ + color outcol = col; + + outcol[0] = clamp(col[0], 0.0, 1.0); + outcol[1] = clamp(col[1], 0.0, 1.0); + outcol[2] = clamp(col[2], 0.0, 1.0); + + return outcol; +} diff --git a/intern/cycles/kernel/osl/shaders/node_mix_color.osl b/intern/cycles/kernel/osl/shaders/node_mix_color.osl new file mode 100644 index 00000000000..3ddd89ed306 --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_mix_color.osl @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "node_color.h" +#include "node_color_blend.h" +#include "stdcycles.h" + +shader node_mix_color(string blend_type = "mix", + int use_clamp = 0, + int use_clamp_result = 0, + float Factor = 0.5, + color A = 0.0, + color B = 0.0, + output color Result = 0.0) +{ + float t = (use_clamp) ? clamp(Factor, 0.0, 1.0) : Factor; + + if (blend_type == "mix") + Result = mix(A, B, t); + if (blend_type == "add") + Result = node_mix_add(t, A, B); + if (blend_type == "multiply") + Result = node_mix_mul(t, A, B); + if (blend_type == "screen") + Result = node_mix_screen(t, A, B); + if (blend_type == "overlay") + Result = node_mix_overlay(t, A, B); + if (blend_type == "subtract") + Result = node_mix_sub(t, A, B); + if (blend_type == "divide") + Result = node_mix_div(t, A, B); + if (blend_type == "difference") + Result = node_mix_diff(t, A, B); + if (blend_type == "darken") + Result = node_mix_dark(t, A, B); + if (blend_type == "lighten") + Result = node_mix_light(t, A, B); + if (blend_type == "dodge") + Result = node_mix_dodge(t, A, B); + if (blend_type == "burn") + Result = node_mix_burn(t, A, B); + if (blend_type == "hue") + Result = node_mix_hue(t, A, B); + if (blend_type == "saturation") + Result = node_mix_sat(t, A, B); + if (blend_type == "value") + Result = node_mix_val(t, A, B); + if (blend_type == "color") + Result = node_mix_color(t, A, B); + if (blend_type == "soft_light") + Result = node_mix_soft(t, A, B); + if (blend_type == "linear_light") + Result = node_mix_linear(t, A, B); + + if (use_clamp_result) + Result = clamp(Result, 0.0, 1.0); +} diff --git a/intern/cycles/kernel/osl/shaders/node_mix_float.osl b/intern/cycles/kernel/osl/shaders/node_mix_float.osl new file mode 100644 index 00000000000..fdc7b4eff6e --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_mix_float.osl @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "stdcycles.h" + +shader node_mix_float( + int use_clamp = 0, float Factor = 0.5, float A = 0.0, float B = 0.0, output float Result = 0.0) +{ + float t = (use_clamp) ? clamp(Factor, 0.0, 1.0) : Factor; + Result = mix(A, B, t); +} diff --git a/intern/cycles/kernel/osl/shaders/node_mix_vector.osl b/intern/cycles/kernel/osl/shaders/node_mix_vector.osl new file mode 100644 index 00000000000..d76396afb0d --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_mix_vector.osl @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "stdcycles.h" + +shader node_mix_vector(int use_clamp = 0, + float Factor = 0.5, + vector A = 0.0, + vector B = 0.0, + output vector Result = 0.0) +{ + float t = (use_clamp) ? clamp(Factor, 0.0, 1.0) : Factor; + Result = mix(A, B, t); +} diff --git a/intern/cycles/kernel/osl/shaders/node_mix_vector_non_uniform.osl b/intern/cycles/kernel/osl/shaders/node_mix_vector_non_uniform.osl new file mode 100644 index 00000000000..217856bcf2a --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_mix_vector_non_uniform.osl @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#include "stdcycles.h" + +shader node_mix_vector_non_uniform(int use_clamp = 0, + vector Factor = 0.5, + vector A = 0.0, + vector B = 0.0, + output vector Result = 0.0) +{ + vector t = (use_clamp) ? clamp(Factor, 0.0, 1.0) : Factor; + Result = mix(A, B, t); +} diff --git a/intern/cycles/kernel/svm/color_util.h b/intern/cycles/kernel/svm/color_util.h index 41f44378ff0..96adb6fd64c 100644 --- a/intern/cycles/kernel/svm/color_util.h +++ b/intern/cycles/kernel/svm/color_util.h @@ -247,10 +247,8 @@ ccl_device float3 svm_mix_clamp(float3 col) return saturate(col); } -ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2) +ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float t, float3 c1, float3 c2) { - float t = saturatef(fac); - switch (type) { case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2); @@ -282,7 +280,7 @@ ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float return svm_mix_sat(t, c1, c2); case NODE_MIX_VAL: return svm_mix_val(t, c1, c2); - case NODE_MIX_COLOR: + case NODE_MIX_COL: return svm_mix_color(t, c1, c2); case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2); @@ -295,6 +293,12 @@ ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float return make_float3(0.0f, 0.0f, 0.0f); } +ccl_device_noinline_cpu float3 svm_mix_clamped_factor(NodeMix type, float t, float3 c1, float3 c2) +{ + float fac = saturatef(t); + return svm_mix(type, fac, c1, c2); +} + ccl_device_inline float3 svm_brightness_contrast(float3 color, float brightness, float contrast) { float a = 1.0f + contrast; diff --git a/intern/cycles/kernel/svm/mix.h b/intern/cycles/kernel/svm/mix.h index a9796096410..ead2fc44685 100644 --- a/intern/cycles/kernel/svm/mix.h +++ b/intern/cycles/kernel/svm/mix.h @@ -21,10 +21,94 @@ ccl_device_noinline int svm_node_mix(KernelGlobals kg, float fac = stack_load_float(stack, fac_offset); float3 c1 = stack_load_float3(stack, c1_offset); float3 c2 = stack_load_float3(stack, c2_offset); - float3 result = svm_mix((NodeMix)node1.y, fac, c1, c2); + float3 result = svm_mix_clamped_factor((NodeMix)node1.y, fac, c1, c2); stack_store_float3(stack, node1.z, result); return offset; } +ccl_device_noinline void svm_node_mix_color(ccl_private ShaderData *sd, + ccl_private float *stack, + uint options, + uint input_offset, + uint result_offset) +{ + uint use_clamp, blend_type, use_clamp_result; + uint fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset; + svm_unpack_node_uchar3(options, &use_clamp, &blend_type, &use_clamp_result); + svm_unpack_node_uchar3( + input_offset, &fac_in_stack_offset, &a_in_stack_offset, &b_in_stack_offset); + + float t = stack_load_float(stack, fac_in_stack_offset); + if (use_clamp > 0) { + t = saturatef(t); + } + float3 a = stack_load_float3(stack, a_in_stack_offset); + float3 b = stack_load_float3(stack, b_in_stack_offset); + float3 result = svm_mix((NodeMix)blend_type, t, a, b); + if (use_clamp_result) { + result = saturate(result); + } + stack_store_float3(stack, result_offset, result); +} + +ccl_device_noinline void svm_node_mix_float(ccl_private ShaderData *sd, + ccl_private float *stack, + uint use_clamp, + uint input_offset, + uint result_offset) +{ + uint fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset; + svm_unpack_node_uchar3( + input_offset, &fac_in_stack_offset, &a_in_stack_offset, &b_in_stack_offset); + + float t = stack_load_float(stack, fac_in_stack_offset); + if (use_clamp > 0) { + t = saturatef(t); + } + float a = stack_load_float(stack, a_in_stack_offset); + float b = stack_load_float(stack, b_in_stack_offset); + float result = a * (1 - t) + b * t; + + stack_store_float(stack, result_offset, result); +} + +ccl_device_noinline void svm_node_mix_vector(ccl_private ShaderData *sd, + ccl_private float *stack, + uint input_offset, + uint result_offset) +{ + uint use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset; + svm_unpack_node_uchar4( + input_offset, &use_clamp, &fac_in_stack_offset, &a_in_stack_offset, &b_in_stack_offset); + + float t = stack_load_float(stack, fac_in_stack_offset); + if (use_clamp > 0) { + t = saturatef(t); + } + float3 a = stack_load_float3(stack, a_in_stack_offset); + float3 b = stack_load_float3(stack, b_in_stack_offset); + float3 result = a * (one_float3() - t) + b * t; + stack_store_float3(stack, result_offset, result); +} + +ccl_device_noinline void svm_node_mix_vector_non_uniform(ccl_private ShaderData *sd, + ccl_private float *stack, + uint input_offset, + uint result_offset) +{ + uint use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset; + svm_unpack_node_uchar4( + input_offset, &use_clamp, &fac_in_stack_offset, &a_in_stack_offset, &b_in_stack_offset); + + float3 t = stack_load_float3(stack, fac_in_stack_offset); + if (use_clamp > 0) { + t = saturate(t); + } + float3 a = stack_load_float3(stack, a_in_stack_offset); + float3 b = stack_load_float3(stack, b_in_stack_offset); + float3 result = a * (one_float3() - t) + b * t; + stack_store_float3(stack, result_offset, result); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/node_types_template.h b/intern/cycles/kernel/svm/node_types_template.h index 39d279be4cb..aab9b9f1158 100644 --- a/intern/cycles/kernel/svm/node_types_template.h +++ b/intern/cycles/kernel/svm/node_types_template.h @@ -103,6 +103,10 @@ SHADER_NODE_TYPE(NODE_AOV_START) SHADER_NODE_TYPE(NODE_AOV_COLOR) SHADER_NODE_TYPE(NODE_AOV_VALUE) SHADER_NODE_TYPE(NODE_FLOAT_CURVE) +SHADER_NODE_TYPE(NODE_MIX_COLOR) +SHADER_NODE_TYPE(NODE_MIX_FLOAT) +SHADER_NODE_TYPE(NODE_MIX_VECTOR) +SHADER_NODE_TYPE(NODE_MIX_VECTOR_NON_UNIFORM) /* Padding for struct alignment. */ SHADER_NODE_TYPE(NODE_PAD1) diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 9d6d3e9222c..3ca632c5f0b 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -585,6 +585,18 @@ ccl_device void svm_eval_nodes(KernelGlobals kg, SVM_CASE(NODE_AOV_VALUE) svm_node_aov_value<node_feature_mask>(kg, state, sd, stack, node, render_buffer); break; + SVM_CASE(NODE_MIX_COLOR) + svm_node_mix_color(sd, stack, node.y, node.z, node.w); + break; + SVM_CASE(NODE_MIX_FLOAT) + svm_node_mix_float(sd, stack, node.y, node.z, node.w); + break; + SVM_CASE(NODE_MIX_VECTOR) + svm_node_mix_vector(sd, stack, node.y, node.z); + break; + SVM_CASE(NODE_MIX_VECTOR_NON_UNIFORM) + svm_node_mix_vector_non_uniform(sd, stack, node.y, node.z); + break; default: kernel_assert(!"Unknown node type was passed to the SVM machine"); return; diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h index 98dfe6a4375..9dd8f196e0f 100644 --- a/intern/cycles/kernel/svm/types.h +++ b/intern/cycles/kernel/svm/types.h @@ -133,7 +133,7 @@ typedef enum NodeMix { NODE_MIX_HUE, NODE_MIX_SAT, NODE_MIX_VAL, - NODE_MIX_COLOR, + NODE_MIX_COL, NODE_MIX_SOFT, NODE_MIX_LINEAR, NODE_MIX_CLAMP /* used for the clamp UI option */ diff --git a/intern/cycles/scene/constant_fold.cpp b/intern/cycles/scene/constant_fold.cpp index 4bce5661f9b..1aa4515a087 100644 --- a/intern/cycles/scene/constant_fold.cpp +++ b/intern/cycles/scene/constant_fold.cpp @@ -291,6 +291,101 @@ void ConstantFolder::fold_mix(NodeMix type, bool clamp) const } } +void ConstantFolder::fold_mix_color(NodeMix type, bool clamp_factor, bool clamp) const +{ + ShaderInput *fac_in = node->input("Factor"); + ShaderInput *color1_in = node->input("A"); + ShaderInput *color2_in = node->input("B"); + + float fac = clamp_factor ? saturatef(node->get_float(fac_in->socket_type)) : + node->get_float(fac_in->socket_type); + bool fac_is_zero = !fac_in->link && fac == 0.0f; + bool fac_is_one = !fac_in->link && fac == 1.0f; + + /* remove no-op node when factor is 0.0 */ + if (fac_is_zero) { + /* note that some of the modes will clamp out of bounds values even without use_clamp */ + if (!(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN)) { + if (try_bypass_or_make_constant(color1_in, clamp)) { + return; + } + } + } + + switch (type) { + case NODE_MIX_BLEND: + /* remove useless mix colors nodes */ + if (color1_in->link && color2_in->link) { + if (color1_in->link == color2_in->link) { + try_bypass_or_make_constant(color1_in, clamp); + break; + } + } + else if (!color1_in->link && !color2_in->link) { + float3 color1 = node->get_float3(color1_in->socket_type); + float3 color2 = node->get_float3(color2_in->socket_type); + if (color1 == color2) { + try_bypass_or_make_constant(color1_in, clamp); + break; + } + } + /* remove no-op mix color node when factor is 1.0 */ + if (fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + break; + } + break; + case NODE_MIX_ADD: + /* 0 + X (fac 1) == X */ + if (is_zero(color1_in) && fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + } + /* X + 0 (fac ?) == X */ + else if (is_zero(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + break; + case NODE_MIX_SUB: + /* X - 0 (fac ?) == X */ + if (is_zero(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* X - X (fac 1) == 0 */ + else if (color1_in->link && color1_in->link == color2_in->link && fac_is_one) { + make_zero(); + } + break; + case NODE_MIX_MUL: + /* X * 1 (fac ?) == X, 1 * X (fac 1) == X */ + if (is_one(color1_in) && fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + } + else if (is_one(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* 0 * ? (fac ?) == 0, ? * 0 (fac 1) == 0 */ + else if (is_zero(color1_in)) { + make_zero(); + } + else if (is_zero(color2_in) && fac_is_one) { + make_zero(); + } + break; + case NODE_MIX_DIV: + /* X / 1 (fac ?) == X */ + if (is_one(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* 0 / ? (fac ?) == 0 */ + else if (is_zero(color1_in)) { + make_zero(); + } + break; + default: + break; + } +} + void ConstantFolder::fold_math(NodeMathType type) const { ShaderInput *value1_in = node->input("Value1"); diff --git a/intern/cycles/scene/constant_fold.h b/intern/cycles/scene/constant_fold.h index 090ce367e6c..246ff2d31ee 100644 --- a/intern/cycles/scene/constant_fold.h +++ b/intern/cycles/scene/constant_fold.h @@ -51,6 +51,7 @@ class ConstantFolder { /* Specific nodes. */ void fold_mix(NodeMix type, bool clamp) const; + void fold_mix_color(NodeMix type, bool clamp_factor, bool clamp) const; void fold_math(NodeMathType type) const; void fold_vector_math(NodeVectorMathType type) const; void fold_mapping(NodeMappingType type) const; diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp index bedb0fe2902..a9cd453947b 100644 --- a/intern/cycles/scene/shader_nodes.cpp +++ b/intern/cycles/scene/shader_nodes.cpp @@ -4950,7 +4950,7 @@ NODE_DEFINE(MixNode) type_enum.insert("hue", NODE_MIX_HUE); type_enum.insert("saturation", NODE_MIX_SAT); type_enum.insert("value", NODE_MIX_VAL); - type_enum.insert("color", NODE_MIX_COLOR); + type_enum.insert("color", NODE_MIX_COL); type_enum.insert("soft_light", NODE_MIX_SOFT); type_enum.insert("linear_light", NODE_MIX_LINEAR); SOCKET_ENUM(mix_type, "Type", type_enum, NODE_MIX_BLEND); @@ -4999,13 +4999,253 @@ void MixNode::compile(OSLCompiler &compiler) void MixNode::constant_fold(const ConstantFolder &folder) { if (folder.all_inputs_constant()) { - folder.make_constant_clamp(svm_mix(mix_type, fac, color1, color2), use_clamp); + folder.make_constant_clamp(svm_mix_clamped_factor(mix_type, fac, color1, color2), use_clamp); } else { folder.fold_mix(mix_type, use_clamp); } } +/* Mix Color */ + +NODE_DEFINE(MixColorNode) +{ + NodeType *type = NodeType::add("mix_color", create, NodeType::SHADER); + + static NodeEnum type_enum; + type_enum.insert("mix", NODE_MIX_BLEND); + type_enum.insert("add", NODE_MIX_ADD); + type_enum.insert("multiply", NODE_MIX_MUL); + type_enum.insert("screen", NODE_MIX_SCREEN); + type_enum.insert("overlay", NODE_MIX_OVERLAY); + type_enum.insert("subtract", NODE_MIX_SUB); + type_enum.insert("divide", NODE_MIX_DIV); + type_enum.insert("difference", NODE_MIX_DIFF); + type_enum.insert("darken", NODE_MIX_DARK); + type_enum.insert("lighten", NODE_MIX_LIGHT); + type_enum.insert("dodge", NODE_MIX_DODGE); + type_enum.insert("burn", NODE_MIX_BURN); + type_enum.insert("hue", NODE_MIX_HUE); + type_enum.insert("saturation", NODE_MIX_SAT); + type_enum.insert("value", NODE_MIX_VAL); + type_enum.insert("color", NODE_MIX_COL); + type_enum.insert("soft_light", NODE_MIX_SOFT); + type_enum.insert("linear_light", NODE_MIX_LINEAR); + SOCKET_ENUM(blend_type, "Type", type_enum, NODE_MIX_BLEND); + + SOCKET_IN_FLOAT(fac, "Factor", 0.5f); + SOCKET_IN_COLOR(a, "A", zero_float3()); + SOCKET_IN_COLOR(b, "B", zero_float3()); + SOCKET_BOOLEAN(use_clamp_result, "Use Clamp Result", false); + SOCKET_BOOLEAN(use_clamp, "Use Clamp", true); + + SOCKET_OUT_COLOR(result, "Result"); + + return type; +} + +MixColorNode::MixColorNode() : ShaderNode(get_node_type()) +{ +} + +void MixColorNode::compile(SVMCompiler &compiler) +{ + ShaderInput *fac_in = input("Factor"); + ShaderInput *a_in = input("A"); + ShaderInput *b_in = input("B"); + ShaderOutput *result_out = output("Result"); + + int fac_in_stack_offset = compiler.stack_assign(fac_in); + int a_in_stack_offset = compiler.stack_assign(a_in); + int b_in_stack_offset = compiler.stack_assign(b_in); + + compiler.add_node( + NODE_MIX_COLOR, + compiler.encode_uchar4(use_clamp, blend_type, use_clamp_result), + compiler.encode_uchar4(fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset), + compiler.stack_assign(result_out)); +} + +void MixColorNode::compile(OSLCompiler &compiler) +{ + compiler.parameter(this, "blend_type"); + compiler.parameter(this, "use_clamp"); + compiler.parameter(this, "use_clamp_result"); + compiler.add(this, "node_mix_color"); +} + +void MixColorNode::constant_fold(const ConstantFolder &folder) +{ + if (folder.all_inputs_constant()) { + if (use_clamp) { + fac = clamp(fac, 0.0f, 1.0f); + } + folder.make_constant_clamp(svm_mix(blend_type, fac, a, b), use_clamp_result); + } + else { + folder.fold_mix_color(blend_type, use_clamp, use_clamp_result); + } +} + +/* Mix Float */ + +NODE_DEFINE(MixFloatNode) +{ + NodeType *type = NodeType::add("mix_float", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(fac, "Factor", 0.5f); + SOCKET_IN_FLOAT(a, "A", 0.0f); + SOCKET_IN_FLOAT(b, "B", 0.0f); + SOCKET_BOOLEAN(use_clamp, "Use Clamp", true); + SOCKET_OUT_FLOAT(result, "Result"); + + return type; +} + +MixFloatNode::MixFloatNode() : ShaderNode(get_node_type()) +{ +} + +void MixFloatNode::compile(SVMCompiler &compiler) +{ + ShaderInput *fac_in = input("Factor"); + ShaderInput *a_in = input("A"); + ShaderInput *b_in = input("B"); + ShaderOutput *result_out = output("Result"); + + int fac_in_stack_offset = compiler.stack_assign(fac_in); + int a_in_stack_offset = compiler.stack_assign(a_in); + int b_in_stack_offset = compiler.stack_assign(b_in); + + compiler.add_node( + NODE_MIX_FLOAT, + use_clamp, + compiler.encode_uchar4(fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset), + compiler.stack_assign(result_out)); +} + +void MixFloatNode::compile(OSLCompiler &compiler) +{ + compiler.parameter(this, "use_clamp"); + compiler.add(this, "node_mix_float"); +} + +void MixFloatNode::constant_fold(const ConstantFolder &folder) +{ + if (folder.all_inputs_constant()) { + if (use_clamp) { + fac = clamp(fac, 0.0f, 1.0f); + } + folder.make_constant(a * (1 - fac) + b * fac); + } +} + +/* Mix Vector */ + +NODE_DEFINE(MixVectorNode) +{ + NodeType *type = NodeType::add("mix_vector", create, NodeType::SHADER); + + SOCKET_IN_FLOAT(fac, "Factor", 0.5f); + SOCKET_IN_VECTOR(a, "A", zero_float3()); + SOCKET_IN_VECTOR(b, "B", zero_float3()); + SOCKET_BOOLEAN(use_clamp, "Use Clamp", true); + + SOCKET_OUT_VECTOR(result, "Result"); + + return type; +} + +MixVectorNode::MixVectorNode() : ShaderNode(get_node_type()) +{ +} + +void MixVectorNode::compile(SVMCompiler &compiler) +{ + ShaderInput *fac_in = input("Factor"); + ShaderInput *a_in = input("A"); + ShaderInput *b_in = input("B"); + ShaderOutput *result_out = output("Result"); + + int fac_in_stack_offset = compiler.stack_assign(fac_in); + int a_in_stack_offset = compiler.stack_assign(a_in); + int b_in_stack_offset = compiler.stack_assign(b_in); + + compiler.add_node( + NODE_MIX_VECTOR, + compiler.encode_uchar4(use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset), + compiler.stack_assign(result_out)); +} + +void MixVectorNode::compile(OSLCompiler &compiler) +{ + compiler.parameter(this, "use_clamp"); + compiler.add(this, "node_mix_vector"); +} + +void MixVectorNode::constant_fold(const ConstantFolder &folder) +{ + if (folder.all_inputs_constant()) { + if (use_clamp) { + fac = clamp(fac, 0.0f, 1.0f); + } + folder.make_constant(a * (one_float3() - fac) + b * fac); + } +} + +/* Mix Vector Non Uniform */ + +NODE_DEFINE(MixVectorNonUniformNode) +{ + NodeType *type = NodeType::add("mix_vector_non_uniform", create, NodeType::SHADER); + + SOCKET_IN_VECTOR(fac, "Factor", make_float3(0.5f, 0.5f, 0.5f)); + SOCKET_IN_VECTOR(a, "A", zero_float3()); + SOCKET_IN_VECTOR(b, "B", zero_float3()); + SOCKET_BOOLEAN(use_clamp, "Use Clamp", true); + + SOCKET_OUT_VECTOR(result, "Result"); + + return type; +} + +MixVectorNonUniformNode::MixVectorNonUniformNode() : ShaderNode(get_node_type()) +{ +} + +void MixVectorNonUniformNode::compile(SVMCompiler &compiler) +{ + ShaderInput *fac_in = input("Factor"); + ShaderInput *a_in = input("A"); + ShaderInput *b_in = input("B"); + ShaderOutput *result_out = output("Result"); + + int fac_in_stack_offset = compiler.stack_assign(fac_in); + int a_in_stack_offset = compiler.stack_assign(a_in); + int b_in_stack_offset = compiler.stack_assign(b_in); + + compiler.add_node( + NODE_MIX_VECTOR_NON_UNIFORM, + compiler.encode_uchar4(use_clamp, fac_in_stack_offset, a_in_stack_offset, b_in_stack_offset), + compiler.stack_assign(result_out)); +} + +void MixVectorNonUniformNode::compile(OSLCompiler &compiler) +{ + compiler.parameter(this, "use_clamp"); + compiler.add(this, "node_mix_vector_non_uniform"); +} + +void MixVectorNonUniformNode::constant_fold(const ConstantFolder &folder) +{ + if (folder.all_inputs_constant()) { + if (use_clamp) { + fac = saturate(fac); + } + folder.make_constant(a * (one_float3() - fac) + b * fac); + } +} + /* Combine Color */ NODE_DEFINE(CombineColorNode) diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h index ac40a397c1e..cc3a71a0697 100644 --- a/intern/cycles/scene/shader_nodes.h +++ b/intern/cycles/scene/shader_nodes.h @@ -1101,6 +1101,52 @@ class MixNode : public ShaderNode { NODE_SOCKET_API(float, fac) }; +class MixColorNode : public ShaderNode { + public: + SHADER_NODE_CLASS(MixColorNode) + void constant_fold(const ConstantFolder &folder); + + NODE_SOCKET_API(float3, a) + NODE_SOCKET_API(float3, b) + NODE_SOCKET_API(float, fac) + NODE_SOCKET_API(bool, use_clamp) + NODE_SOCKET_API(bool, use_clamp_result) + NODE_SOCKET_API(NodeMix, blend_type) +}; + +class MixFloatNode : public ShaderNode { + public: + SHADER_NODE_CLASS(MixFloatNode) + void constant_fold(const ConstantFolder &folder); + + NODE_SOCKET_API(float, a) + NODE_SOCKET_API(float, b) + NODE_SOCKET_API(float, fac) + NODE_SOCKET_API(bool, use_clamp) +}; + +class MixVectorNode : public ShaderNode { + public: + SHADER_NODE_CLASS(MixVectorNode) + void constant_fold(const ConstantFolder &folder); + + NODE_SOCKET_API(float3, a) + NODE_SOCKET_API(float3, b) + NODE_SOCKET_API(float, fac) + NODE_SOCKET_API(bool, use_clamp) +}; + +class MixVectorNonUniformNode : public ShaderNode { + public: + SHADER_NODE_CLASS(MixVectorNonUniformNode) + void constant_fold(const ConstantFolder &folder); + + NODE_SOCKET_API(float3, a) + NODE_SOCKET_API(float3, b) + NODE_SOCKET_API(float3, fac) + NODE_SOCKET_API(bool, use_clamp) +}; + class CombineColorNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineColorNode) diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index 0dd855bb513..aa893a66a9d 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -437,9 +437,9 @@ class GHOST_ISystem { /** * Set the Console State * \param action: console state - * \return current status (1 -visible, 0 - hidden) + * \return current status (true: visible, 0: hidden) */ - virtual int setConsoleWindowState(GHOST_TConsoleWindowState action) = 0; + virtual bool setConsoleWindowState(GHOST_TConsoleWindowState action) = 0; /*************************************************************************************** * Access to clipboard. diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 62e1e470010..710512881e8 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -869,8 +869,7 @@ void GHOST_putClipboard(const char *buffer, bool selection) bool GHOST_setConsoleWindowState(GHOST_TConsoleWindowState action) { GHOST_ISystem *system = GHOST_ISystem::getSystem(); - /* FIXME: use `bool` instead of int for this value. */ - return (bool)system->setConsoleWindowState(action); + return system->setConsoleWindowState(action); } bool GHOST_UseNativePixels(void) diff --git a/intern/ghost/intern/GHOST_ContextD3D.cpp b/intern/ghost/intern/GHOST_ContextD3D.cpp index 4fc05cf912c..857323941ea 100644 --- a/intern/ghost/intern/GHOST_ContextD3D.cpp +++ b/intern/ghost/intern/GHOST_ContextD3D.cpp @@ -123,8 +123,6 @@ class GHOST_SharedOpenGLResource { ID3D11RenderTargetView *render_target = nullptr) : m_device(device), m_device_ctx(device_ctx), m_cur_width(width), m_cur_height(height) { - ID3D11Resource *backbuffer_res; - if (!render_target) { D3D11_TEXTURE2D_DESC texDesc{}; D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc{}; @@ -157,11 +155,12 @@ class GHOST_SharedOpenGLResource { m_render_target = render_target; if (m_render_target) { + ID3D11Resource *backbuffer_res = nullptr; m_render_target->GetResource(&backbuffer_res); - } - if (backbuffer_res) { - backbuffer_res->QueryInterface<ID3D11Texture2D>(&m_render_target_tex); - backbuffer_res->Release(); + if (backbuffer_res) { + backbuffer_res->QueryInterface<ID3D11Texture2D>(&m_render_target_tex); + backbuffer_res->Release(); + } } if (!m_render_target || !m_render_target_tex) { diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp index 2283cff3827..03d55c848e3 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp +++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp @@ -219,35 +219,30 @@ void *GHOST_DropTargetWin32::getDropDataAsFilenames(IDataObject *pDataObject) hdrop = (HDROP)::GlobalLock(stgmed.hGlobal); totfiles = ::DragQueryFileW(hdrop, -1, NULL, 0); - if (!totfiles) { - ::GlobalUnlock(stgmed.hGlobal); - return NULL; - } - - strArray = (GHOST_TStringArray *)::malloc(sizeof(GHOST_TStringArray)); - strArray->count = 0; - strArray->strings = (uint8_t **)::malloc(totfiles * sizeof(uint8_t *)); - - for (UINT nfile = 0; nfile < totfiles; nfile++) { - if (::DragQueryFileW(hdrop, nfile, fpath, MAX_PATH) > 0) { - if (!(temp_path = alloc_utf_8_from_16(fpath, 0))) { - continue; + if (totfiles) { + strArray = (GHOST_TStringArray *)::malloc(sizeof(GHOST_TStringArray)); + strArray->count = 0; + strArray->strings = (uint8_t **)::malloc(totfiles * sizeof(uint8_t *)); + + for (UINT nfile = 0; nfile < totfiles; nfile++) { + if (::DragQueryFileW(hdrop, nfile, fpath, MAX_PATH) > 0) { + if (!(temp_path = alloc_utf_8_from_16(fpath, 0))) { + continue; + } + /* Just ignore paths that could not be converted verbatim. */ + + strArray->strings[nvalid] = (uint8_t *)temp_path; + strArray->count = nvalid + 1; + nvalid++; } - /* Just ignore paths that could not be converted verbatim. */ - - strArray->strings[nvalid] = (uint8_t *)temp_path; - strArray->count = nvalid + 1; - nvalid++; } } /* Free up memory. */ ::GlobalUnlock(stgmed.hGlobal); ::ReleaseStgMedium(&stgmed); - - return strArray; } } - return NULL; + return strArray; } void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject) @@ -261,16 +256,18 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject) if (pDataObject->QueryGetData(&fmtetc) == S_OK) { if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK) { LPCWSTR wstr = (LPCWSTR)::GlobalLock(stgmed.hGlobal); - if (!(tmp_string = alloc_utf_8_from_16((wchar_t *)wstr, 0))) { - ::GlobalUnlock(stgmed.hGlobal); - return NULL; - } + + tmp_string = alloc_utf_8_from_16((wchar_t *)wstr, 0); + /* Free memory. */ ::GlobalUnlock(stgmed.hGlobal); ::ReleaseStgMedium(&stgmed); + #ifdef WITH_GHOST_DEBUG - ::printf("\n<converted droped unicode string>\n%s\n</droped converted unicode string>\n", - tmp_string); + if (tmp_string) { + ::printf("\n<converted droped unicode string>\n%s\n</droped converted unicode string>\n", + tmp_string); + } #endif /* WITH_GHOST_DEBUG */ return tmp_string; } @@ -283,15 +280,8 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *pDataObject) char *str = (char *)::GlobalLock(stgmed.hGlobal); tmp_string = (char *)::malloc(::strlen(str) + 1); - if (!tmp_string) { - ::GlobalUnlock(stgmed.hGlobal); - return NULL; - } - - if (!::strcpy(tmp_string, str)) { - ::free(tmp_string); - ::GlobalUnlock(stgmed.hGlobal); - return NULL; + if (tmp_string) { + ::strcpy(tmp_string, str); } /* Free memory. */ ::GlobalUnlock(stgmed.hGlobal); diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index 8b6dfb4efed..a9e659d3565 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -236,9 +236,9 @@ class GHOST_SystemCocoa : public GHOST_System { /** * \see GHOST_ISystem */ - int setConsoleWindowState(GHOST_TConsoleWindowState action) + bool setConsoleWindowState(GHOST_TConsoleWindowState action) { - return 0; + return false; } /** diff --git a/intern/ghost/intern/GHOST_SystemHeadless.h b/intern/ghost/intern/GHOST_SystemHeadless.h index dcf445420a4..b02a82fc9eb 100644 --- a/intern/ghost/intern/GHOST_SystemHeadless.h +++ b/intern/ghost/intern/GHOST_SystemHeadless.h @@ -30,7 +30,7 @@ class GHOST_SystemHeadless : public GHOST_System { { return false; } - int setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) override + bool setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) override { return 0; } diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h index aefea5eda34..bee277ba674 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.h +++ b/intern/ghost/intern/GHOST_SystemSDL.h @@ -33,9 +33,9 @@ class GHOST_SystemSDL : public GHOST_System { bool processEvents(bool waitForEvent); - int setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) + bool setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) { - return 0; + return false; } GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const; diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index 13357a3d31a..c2859edc56b 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -3035,9 +3035,9 @@ bool GHOST_SystemWayland::processEvents(bool waitForEvent) return any_processed; } -int GHOST_SystemWayland::setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) +bool GHOST_SystemWayland::setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) { - return 0; + return false; } GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h index 632f4bf28d8..f3b42de5a1b 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.h +++ b/intern/ghost/intern/GHOST_SystemWayland.h @@ -97,7 +97,7 @@ class GHOST_SystemWayland : public GHOST_System { bool processEvents(bool waitForEvent) override; - int setConsoleWindowState(GHOST_TConsoleWindowState action) override; + bool setConsoleWindowState(GHOST_TConsoleWindowState action) override; GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const override; diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 5ea369c50bf..b583d39dd1f 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -131,7 +131,7 @@ GHOST_SystemWin32::GHOST_SystemWin32() GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n"); m_displayManager->initialize(); - m_consoleStatus = 1; + m_consoleStatus = true; /* Tell Windows we are per monitor DPI aware. This disables the default * blurry scaling and enables WM_DPICHANGED to allow us to draw at proper DPI. */ @@ -353,6 +353,7 @@ GHOST_ContextD3D *GHOST_SystemWin32::createOffscreenContextD3D() context = new GHOST_ContextD3D(false, wnd); if (context->initializeDrawingContext() == GHOST_kFailure) { delete context; + context = nullptr; } return context; @@ -900,11 +901,11 @@ void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window) new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData)); mouseMoveHandled = true; - break; } else { WINTAB_PRINTF(" ... but no system button\n"); } + break; } case GHOST_kEventButtonUp: { WINTAB_PRINTF("HWND %p Wintab button up", window->getHWND()); @@ -1156,10 +1157,10 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA * those events here as well. */ if (!is_repeated_modifier) { char utf8_char[6] = {0}; - BYTE state[256] = {0}; - GetKeyboardState((PBYTE)state); - bool ctrl_pressed = state[VK_CONTROL] & 0x80; - bool alt_pressed = state[VK_MENU] & 0x80; + BYTE state[256]; + const BOOL has_state = GetKeyboardState((PBYTE)state); + const bool ctrl_pressed = has_state && state[VK_CONTROL] & 0x80; + const bool alt_pressed = has_state && state[VK_MENU] & 0x80; if (!key_down) { /* Pass. */ @@ -2123,8 +2124,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, char *GHOST_SystemWin32::getClipboard(bool selection) const { - char *temp_buff; - if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) { wchar_t *buffer; HANDLE hData = GetClipboardData(CF_UNICODETEXT); @@ -2138,7 +2137,7 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const return NULL; } - temp_buff = alloc_utf_8_from_16(buffer, 0); + char *temp_buff = alloc_utf_8_from_16(buffer, 0); /* Buffer mustn't be accessed after CloseClipboard * it would like accessing free-d memory */ @@ -2147,7 +2146,7 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const return temp_buff; } - else if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL)) { + if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL)) { char *buffer; size_t len = 0; HANDLE hData = GetClipboardData(CF_TEXT); @@ -2162,7 +2161,7 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const } len = strlen(buffer); - temp_buff = (char *)malloc(len + 1); + char *temp_buff = (char *)malloc(len + 1); strncpy(temp_buff, buffer, len); temp_buff[len] = '\0'; @@ -2173,9 +2172,7 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const return temp_buff; } - else { - return NULL; - } + return nullptr; } void GHOST_SystemWin32::putClipboard(const char *buffer, bool selection) const @@ -2320,7 +2317,7 @@ static bool isStartedFromCommandPrompt() return false; } -int GHOST_SystemWin32::setConsoleWindowState(GHOST_TConsoleWindowState action) +bool GHOST_SystemWin32::setConsoleWindowState(GHOST_TConsoleWindowState action) { HWND wnd = GetConsoleWindow(); @@ -2328,13 +2325,13 @@ int GHOST_SystemWin32::setConsoleWindowState(GHOST_TConsoleWindowState action) case GHOST_kConsoleWindowStateHideForNonConsoleLaunch: { if (!isStartedFromCommandPrompt()) { ShowWindow(wnd, SW_HIDE); - m_consoleStatus = 0; + m_consoleStatus = false; } break; } case GHOST_kConsoleWindowStateHide: { ShowWindow(wnd, SW_HIDE); - m_consoleStatus = 0; + m_consoleStatus = false; break; } case GHOST_kConsoleWindowStateShow: { @@ -2342,7 +2339,7 @@ int GHOST_SystemWin32::setConsoleWindowState(GHOST_TConsoleWindowState action) if (!isStartedFromCommandPrompt()) { DeleteMenu(GetSystemMenu(wnd, FALSE), SC_CLOSE, MF_BYCOMMAND); } - m_consoleStatus = 1; + m_consoleStatus = true; break; } case GHOST_kConsoleWindowStateToggle: { diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index 93b56a128c0..81c565ae732 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -430,7 +430,7 @@ class GHOST_SystemWin32 : public GHOST_System { * \param action: console state * \return current status (1 -visible, 0 - hidden) */ - int setConsoleWindowState(GHOST_TConsoleWindowState action); + bool setConsoleWindowState(GHOST_TConsoleWindowState action); /** The virtual-key code (VKey) of the last press event. Used to detect repeat events. */ unsigned short m_keycode_last_repeat_key; @@ -450,7 +450,7 @@ class GHOST_SystemWin32 : public GHOST_System { HKL m_keylayout; /** Console status. */ - int m_consoleStatus; + bool m_consoleStatus; /** Wheel delta accumulator. */ int m_wheelDeltaAccum; diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index 7938aa2b646..bd6ace101e9 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -253,7 +253,7 @@ class GHOST_SystemX11 : public GHOST_System { /** * \see GHOST_ISystem */ - int setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) + bool setConsoleWindowState(GHOST_TConsoleWindowState /*action*/) { return 0; } diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 4d8e0d492d9..50ee9385e39 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -624,11 +624,9 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty GHOST_Context *context; context = new GHOST_ContextD3D(false, m_hWnd); - if (context->initializeDrawingContext()) { - return context; - } - else { + if (!context->initializeDrawingContext()) { delete context; + context = nullptr; } return context; diff --git a/release/datafiles/locale b/release/datafiles/locale -Subproject a2eb507891449a0b67582be9561840075513661 +Subproject 1b891478f44dd047c3a92fda3ebd17fae1c3acd diff --git a/release/freedesktop/org.blender.Blender.appdata.xml b/release/freedesktop/org.blender.Blender.appdata.xml index 12291860050..0f1aa5099b6 100644 --- a/release/freedesktop/org.blender.Blender.appdata.xml +++ b/release/freedesktop/org.blender.Blender.appdata.xml @@ -40,6 +40,47 @@ </screenshot> </screenshots> <releases> + <release version="3.3" date="2022-09-07"> + <description> + <p>New features:</p> + <ul> + <li>New hair system</li> + <li>Cycles Rendering on Intel Arc GPUs</li> + <li>Grease Pencil Light and Shadow calculations</li> + <li>Motion Tracker Image Plane Marker</li> + </ul> + <p>Enhancements:</p> + <ul> + <li>Faster Line Art loading time</li> + <li>Library Overrides improvements</li> + <li>Massive performance gains importing large amounts of objects in USD, Alembic, and OBJ</li> + <li>UV improvements</li> + <li>Improved sculpting performance in EEVEE</li> + <li>Cycles GPU rendering improvements for AMD GPUs and Apple Silicon</li> + </ul> + </description> + </release> + <release version="3.2" date="2022-06-08"> + <description> + <p>New features:</p> + <ul> + <li>Cycles Light Groups</li> + <li>Cycles Shadow Caustics using Manifold Next Event Estimation</li> + <li>New Tools and usability improvements for Polygon Painting</li> + <li>More Geometry Nodes, including Duplicate Elements</li> + <li>Asset Browser: Support for Asset Collections</li> + </ul> + <p>Enhancements:</p> + <ul> + <li>Enhanced channels in the video sequencer</li> + <li>Support for WebP format</li> + <li>New experimental OBJ importer</li> + <li>Motion Paths improvements</li> + <li>Grease Pencil Envelope Modifier</li> + <li>New Curve Pen Tool</li> + </ul> + </description> + </release> <release version="3.1" date="2022-03-09"> <description> <p>New features:</p> diff --git a/release/scripts/addons b/release/scripts/addons -Subproject 7a8502871c34db0343cc7de52d6b49b15a84238 +Subproject 25ffc6f430fc995b1c046b01acba1c3e6c1896b diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 2342ba33a3b..2091457aa59 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -424,7 +424,6 @@ shader_node_categories = [ NodeItem("ShaderNodeTexWhiteNoise"), ]), ShaderNodeCategory("SH_NEW_OP_COLOR", "Color", items=[ - NodeItem("ShaderNodeMixRGB"), NodeItem("ShaderNodeRGBCurve"), NodeItem("ShaderNodeInvert"), NodeItem("ShaderNodeLightFalloff"), @@ -448,6 +447,7 @@ shader_node_categories = [ NodeItem("ShaderNodeFloatCurve"), NodeItem("ShaderNodeClamp"), NodeItem("ShaderNodeMath"), + NodeItem("ShaderNodeMix"), NodeItem("ShaderNodeValToRGB"), NodeItem("ShaderNodeRGBToBW"), NodeItem("ShaderNodeShaderToRGB", poll=object_eevee_shader_nodes_poll), @@ -651,7 +651,6 @@ geometry_node_categories = [ NodeItem("GeometryNodeStoreNamedAttribute"), ]), GeometryNodeCategory("GEO_COLOR", "Color", items=[ - NodeItem("ShaderNodeMixRGB"), NodeItem("ShaderNodeRGBCurve"), NodeItem("ShaderNodeValToRGB"), NodeItem("FunctionNodeSeparateColor"), @@ -719,6 +718,7 @@ geometry_node_categories = [ NodeItem("FunctionNodeBooleanMath"), NodeItem("FunctionNodeRotateEuler"), NodeItem("FunctionNodeCompare"), + NodeItem("ShaderNodeMix"), NodeItem("FunctionNodeFloatToInt"), NodeItem("GeometryNodeSwitch"), NodeItem("FunctionNodeRandomValue"), diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 886c34654c4..fb157c71172 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -110,6 +110,10 @@ static FT_Error blf_cache_face_requester(FTC_FaceID faceID, font->face->generic.data = font; font->face->generic.finalizer = blf_face_finalizer; } + else { + /* Clear this on error to avoid exception in FTC_Manager_LookupFace. */ + *face = NULL; + } return err; } diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c index a88da6099e5..d35692f6eae 100644 --- a/source/blender/blenfont/intern/blf_font_default.c +++ b/source/blender/blenfont/intern/blf_font_default.c @@ -16,6 +16,10 @@ #include "BKE_appdir.h" +#ifdef WIN32 +# include "BLI_winstuff.h" +#endif + static int blf_load_font_default(const char *filename, const bool unique) { const char *dir = BKE_appdir_folder_id(BLENDER_DATAFILES, BLF_DATAFILES_FONTS_DIR); @@ -47,36 +51,51 @@ int BLF_load_mono_default(const bool unique) return font_id; } -void BLF_load_font_stack() +static void blf_load_datafiles_dir(void) { - /* Load these if not already, might have been replaced by user custom. */ - BLF_load_default(false); - BLF_load_mono_default(false); - const char *datafiles_fonts_dir = BLF_DATAFILES_FONTS_DIR SEP_STR; const char *path = BKE_appdir_folder_id(BLENDER_DATAFILES, datafiles_fonts_dir); if (UNLIKELY(!path)) { fprintf(stderr, "Font data directory \"%s\" could not be detected!\n", datafiles_fonts_dir); + return; } - else if (UNLIKELY(!BLI_exists(path))) { + if (UNLIKELY(!BLI_exists(path))) { fprintf(stderr, "Font data directory \"%s\" does not exist!\n", path); + return; } - else { - struct direntry *dir; - uint num_files = BLI_filelist_dir_contents(path, &dir); - for (int f = 0; f < num_files; f++) { - if (!FILENAME_IS_CURRPAR(dir[f].relname) && !BLI_is_dir(dir[f].path)) { - if (!BLF_is_loaded(dir[f].path)) { - int font_id = BLF_load(dir[f].path); - if (font_id == -1) { - fprintf(stderr, "Unable to load font: %s\n", dir[f].path); - } - else { - BLF_enable(font_id, BLF_DEFAULT); - } - } - } + + struct direntry *file_list; + uint file_list_num = BLI_filelist_dir_contents(path, &file_list); + for (int i = 0; i < file_list_num; i++) { + if (S_ISDIR(file_list[i].s.st_mode)) { + continue; + } + + const char *filepath = file_list[i].path; + if (!BLI_path_extension_check_n( + filepath, ".ttf", ".ttc", ".otf", ".otc", ".woff", ".woff2", NULL)) { + continue; + } + if (BLF_is_loaded(filepath)) { + continue; } - BLI_filelist_free(dir, num_files); + + /* Attempt to load the font. */ + int font_id = BLF_load(filepath); + if (font_id == -1) { + fprintf(stderr, "Unable to load font: %s\n", filepath); + continue; + } + + BLF_enable(font_id, BLF_DEFAULT); } + BLI_filelist_free(file_list, file_list_num); +} + +void BLF_load_font_stack() +{ + /* Load these if not already, might have been replaced by user custom. */ + BLF_load_default(false); + BLF_load_mono_default(false); + blf_load_datafiles_dir(); } diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh index c2f65c93cbe..6284cce9dc0 100644 --- a/source/blender/blenkernel/BKE_attribute.hh +++ b/source/blender/blenkernel/BKE_attribute.hh @@ -73,8 +73,13 @@ struct AttributeKind { */ struct AttributeInit { enum class Type { - Default, + /** #AttributeInitConstruct. */ + Construct, + /** #AttributeInitDefaultValue. */ + DefaultValue, + /** #AttributeInitVArray. */ VArray, + /** #AttributeInitMoveArray. */ MoveArray, }; Type type; @@ -84,11 +89,20 @@ struct AttributeInit { }; /** - * Create an attribute using the default value for the data type. - * The default values may depend on the attribute provider implementation. + * Default construct new attribute values. Does nothing for trivial types. This should be used + * if all attribute element values will be set by the caller after creating the attribute. */ -struct AttributeInitDefault : public AttributeInit { - AttributeInitDefault() : AttributeInit(Type::Default) +struct AttributeInitConstruct : public AttributeInit { + AttributeInitConstruct() : AttributeInit(Type::Construct) + { + } +}; + +/** + * Create an attribute using the default value for the data type (almost always "zero"). + */ +struct AttributeInitDefaultValue : public AttributeInit { + AttributeInitDefaultValue() : AttributeInit(Type::DefaultValue) { } }; @@ -96,14 +110,11 @@ struct AttributeInitDefault : public AttributeInit { /** * Create an attribute by copying data from an existing virtual array. The virtual array * must have the same type as the newly created attribute. - * - * Note that this can be used to fill the new attribute with the default */ struct AttributeInitVArray : public AttributeInit { - blender::GVArray varray; + GVArray varray; - AttributeInitVArray(blender::GVArray varray) - : AttributeInit(Type::VArray), varray(std::move(varray)) + AttributeInitVArray(GVArray varray) : AttributeInit(Type::VArray), varray(std::move(varray)) { } }; @@ -119,10 +130,10 @@ struct AttributeInitVArray : public AttributeInit { * The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it * can't be used directly, and that is generally how Blender expects custom data to be allocated. */ -struct AttributeInitMove : public AttributeInit { +struct AttributeInitMoveArray : public AttributeInit { void *data = nullptr; - AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data) + AttributeInitMoveArray(void *data) : AttributeInit(Type::MoveArray), data(data) { } }; @@ -579,7 +590,7 @@ class MutableAttributeAccessor : public AttributeAccessor { const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, - const AttributeInit &initializer = AttributeInitDefault()); + const AttributeInit &initializer = AttributeInitDefaultValue()); /** * Same as above, but returns a type that makes it easier to work with the attribute as a span. @@ -590,7 +601,7 @@ class MutableAttributeAccessor : public AttributeAccessor { const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, - const AttributeInit &initializer = AttributeInitDefault()); + const AttributeInit &initializer = AttributeInitDefaultValue()); /** * Same as above, but should be used when the type is known at compile time. @@ -599,7 +610,7 @@ class MutableAttributeAccessor : public AttributeAccessor { AttributeWriter<T> lookup_or_add_for_write( const AttributeIDRef &attribute_id, const eAttrDomain domain, - const AttributeInit &initializer = AttributeInitDefault()) + const AttributeInit &initializer = AttributeInitDefaultValue()) { const CPPType &cpp_type = CPPType::get<T>(); const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type); @@ -613,7 +624,7 @@ class MutableAttributeAccessor : public AttributeAccessor { SpanAttributeWriter<T> lookup_or_add_for_write_span( const AttributeIDRef &attribute_id, const eAttrDomain domain, - const AttributeInit &initializer = AttributeInitDefault()) + const AttributeInit &initializer = AttributeInitDefaultValue()) { AttributeWriter<T> attribute = this->lookup_or_add_for_write<T>( attribute_id, domain, initializer); diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 3db75fff12c..44a4f4b5395 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -55,14 +55,17 @@ extern const CustomData_MeshMasks CD_MASK_EVERYTHING; typedef enum eCDAllocType { /** Use the data pointer. */ CD_ASSIGN = 0, - /** Allocate blank memory. */ - CD_CALLOC = 1, - /** Allocate and set to default. */ - CD_DEFAULT = 2, + /** Allocate and set to default, which is usually just zeroed memory. */ + CD_SET_DEFAULT = 2, /** Use data pointers, set layer flag NOFREE. */ CD_REFERENCE = 3, /** Do a full copy of all layers, only allowed if source has same number of elements. */ CD_DUPLICATE = 4, + /** + * Default construct new layer values. Does nothing for trivial types. This should be used + * if all layer values will be set by the caller after creating the layer. + */ + CD_CONSTRUCT = 5, } eCDAllocType; #define CD_TYPE_AS_MASK(_type) (eCustomDataMask)((eCustomDataMask)1 << (eCustomDataMask)(_type)) diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 70f549a6d23..ec6799ee995 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -1043,7 +1043,7 @@ BLI_INLINE int *BKE_mesh_material_indices_for_write(Mesh *mesh) return indices; } return (int *)CustomData_add_layer_named( - &mesh->pdata, CD_PROP_INT32, CD_CALLOC, NULL, mesh->totpoly, "material_index"); + &mesh->pdata, CD_PROP_INT32, CD_SET_DEFAULT, NULL, mesh->totpoly, "material_index"); } #ifdef __cplusplus diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 509de0620c6..1118552b643 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1102,7 +1102,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i //#define SH_NODE_MATERIAL 100 #define SH_NODE_RGB 101 #define SH_NODE_VALUE 102 -#define SH_NODE_MIX_RGB 103 +#define SH_NODE_MIX_RGB_LEGACY 103 #define SH_NODE_VALTORGB 104 #define SH_NODE_RGBTOBW 105 #define SH_NODE_SHADERTORGB 106 @@ -1205,6 +1205,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define SH_NODE_POINT_INFO 710 #define SH_NODE_COMBINE_COLOR 711 #define SH_NODE_SEPARATE_COLOR 712 +#define SH_NODE_MIX 713 /** \} */ diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh index f5fb53f962b..4c13f73848c 100644 --- a/source/blender/blenkernel/BKE_node_runtime.hh +++ b/source/blender/blenkernel/BKE_node_runtime.hh @@ -3,9 +3,20 @@ #pragma once #include <memory> +#include <mutex> -#include "BLI_sys_types.h" +#include "BLI_multi_value_map.hh" #include "BLI_utility_mixins.hh" +#include "BLI_vector.hh" + +#include "DNA_node_types.h" + +#include "BKE_node.h" + +struct bNode; +struct bNodeSocket; +struct bNodeTree; +struct bNodeType; namespace blender::nodes { struct FieldInferencingInterface; @@ -36,6 +47,32 @@ class bNodeTreeRuntime : NonCopyable, NonMovable { /** Information about how inputs and outputs of the node group interact with fields. */ std::unique_ptr<nodes::FieldInferencingInterface> field_inferencing_interface; + + /** + * Protects access to all topology cache variables below. This is necessary so that the cache can + * be updated on a const #bNodeTree. + */ + std::mutex topology_cache_mutex; + bool topology_cache_is_dirty = true; + bool topology_cache_exists = false; + /** + * Under some circumstances, it can be useful to use the cached data while editing the + * #bNodeTree. By default, this is protected against using an assert. + */ + mutable std::atomic<int> allow_use_dirty_topology_cache = 0; + + /** Only valid when #topology_cache_is_dirty is false. */ + Vector<bNode *> nodes; + Vector<bNodeLink *> links; + Vector<bNodeSocket *> sockets; + Vector<bNodeSocket *> input_sockets; + Vector<bNodeSocket *> output_sockets; + MultiValueMap<const bNodeType *, bNode *> nodes_by_type; + Vector<bNode *> toposort_left_to_right; + Vector<bNode *> toposort_right_to_left; + bool has_link_cycle = false; + bool has_undefined_nodes_or_sockets = false; + bNode *group_output_node = nullptr; }; /** @@ -47,12 +84,24 @@ class bNodeSocketRuntime : NonCopyable, NonMovable { public: /** * References a socket declaration that is owned by `node->declaration`. This is only runtime - * data. It has to be updated when the node declaration changes. + * data. It has to be updated when the node declaration changes. Access can be allowed by using + * #AllowUsingOutdatedInfo. */ const SocketDeclarationHandle *declaration = nullptr; /** #eNodeTreeChangedFlag. */ uint32_t changed_flag = 0; + + /** Only valid when #topology_cache_is_dirty is false. */ + Vector<bNodeLink *> directly_linked_links; + Vector<bNodeSocket *> directly_linked_sockets; + Vector<bNodeSocket *> logically_linked_sockets; + Vector<bNodeSocket *> logically_linked_skipped_sockets; + bNode *owner_node = nullptr; + bNodeSocket *internal_link_input = nullptr; + int index_in_node = -1; + int index_in_all_sockets = -1; + int index_in_inout_sockets = -1; }; /** @@ -84,6 +133,395 @@ class bNodeRuntime : NonCopyable, NonMovable { /** #eNodeTreeChangedFlag. */ uint32_t changed_flag = 0; + + /** Only valid if #topology_cache_is_dirty is false. */ + Vector<bNodeSocket *> inputs; + Vector<bNodeSocket *> outputs; + Vector<bNodeLink *> internal_links; + Map<StringRefNull, bNodeSocket *> inputs_by_identifier; + Map<StringRefNull, bNodeSocket *> outputs_by_identifier; + int index_in_tree = -1; + bool has_linked_inputs = false; + bool has_linked_outputs = false; + bNodeTree *owner_tree = nullptr; }; +namespace node_tree_runtime { + +class AllowUsingOutdatedInfo : NonCopyable, NonMovable { + private: + const bNodeTree &tree_; + + public: + AllowUsingOutdatedInfo(const bNodeTree &tree) : tree_(tree) + { + tree_.runtime->allow_use_dirty_topology_cache.fetch_add(1); + } + + ~AllowUsingOutdatedInfo() + { + tree_.runtime->allow_use_dirty_topology_cache.fetch_sub(1); + } +}; + +inline bool topology_cache_is_available(const bNodeTree &tree) +{ + if (!tree.runtime->topology_cache_exists) { + return false; + } + if (tree.runtime->allow_use_dirty_topology_cache.load() > 0) { + return true; + } + if (tree.runtime->topology_cache_is_dirty) { + return false; + } + return true; +} + +inline bool topology_cache_is_available(const bNode &node) +{ + const bNodeTree *ntree = node.runtime->owner_tree; + if (ntree == nullptr) { + return false; + } + return topology_cache_is_available(*ntree); +} + +inline bool topology_cache_is_available(const bNodeSocket &socket) +{ + const bNode *node = socket.runtime->owner_node; + if (node == nullptr) { + return false; + } + return topology_cache_is_available(*node); +} + +} // namespace node_tree_runtime + } // namespace blender::bke + +/* -------------------------------------------------------------------- */ +/** \name #bNodeTree Inline Methods + * \{ */ + +inline blender::Span<bNode *> bNodeTree::nodes_by_type(const blender::StringRefNull type_idname) +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes_by_type.lookup(nodeTypeFind(type_idname.c_str())); +} + +inline blender::Span<const bNode *> bNodeTree::nodes_by_type( + const blender::StringRefNull type_idname) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes_by_type.lookup(nodeTypeFind(type_idname.c_str())); +} + +inline blender::Span<const bNode *> bNodeTree::toposort_left_to_right() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->toposort_left_to_right; +} + +inline blender::Span<const bNode *> bNodeTree::toposort_right_to_left() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->toposort_right_to_left; +} + +inline blender::Span<const bNode *> bNodeTree::all_nodes() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes; +} + +inline blender::Span<bNode *> bNodeTree::all_nodes() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes; +} + +inline bool bNodeTree::has_link_cycle() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->has_link_cycle; +} + +inline bool bNodeTree::has_undefined_nodes_or_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->has_undefined_nodes_or_sockets; +} + +inline const bNode *bNodeTree::group_output_node() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->group_output_node; +} + +inline blender::Span<const bNodeSocket *> bNodeTree::all_input_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->input_sockets; +} + +inline blender::Span<bNodeSocket *> bNodeTree::all_input_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->input_sockets; +} + +inline blender::Span<const bNodeSocket *> bNodeTree::all_output_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->output_sockets; +} + +inline blender::Span<bNodeSocket *> bNodeTree::all_output_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->output_sockets; +} + +inline blender::Span<const bNodeSocket *> bNodeTree::all_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->sockets; +} + +inline blender::Span<bNodeSocket *> bNodeTree::all_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->sockets; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #bNode Inline Methods + * \{ */ + +inline blender::Span<bNodeSocket *> bNode::input_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->inputs; +} + +inline blender::Span<bNodeSocket *> bNode::output_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->outputs; +} + +inline blender::Span<const bNodeSocket *> bNode::input_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->inputs; +} + +inline blender::Span<const bNodeSocket *> bNode::output_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->outputs; +} + +inline bNodeSocket &bNode::input_socket(int index) +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->inputs[index]; +} + +inline bNodeSocket &bNode::output_socket(int index) +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->outputs[index]; +} + +inline const bNodeSocket &bNode::input_socket(int index) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->inputs[index]; +} + +inline const bNodeSocket &bNode::output_socket(int index) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->outputs[index]; +} + +inline const bNodeSocket &bNode::input_by_identifier(blender::StringRef identifier) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->inputs_by_identifier.lookup_as(identifier); +} + +inline const bNodeSocket &bNode::output_by_identifier(blender::StringRef identifier) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->outputs_by_identifier.lookup_as(identifier); +} + +inline blender::StringRefNull bNode::label_or_name() const +{ + if (this->label[0] == '\0') { + return this->name; + } + return this->label; +} + +inline bool bNode::is_muted() const +{ + return this->flag & NODE_MUTED; +} + +inline bool bNode::is_reroute() const +{ + return this->type == NODE_REROUTE; +} + +inline bool bNode::is_frame() const +{ + return this->type == NODE_FRAME; +} + +inline bool bNode::is_group() const +{ + return ELEM(this->type, NODE_GROUP, NODE_CUSTOM_GROUP); +} + +inline bool bNode::is_group_input() const +{ + return this->type == NODE_GROUP_INPUT; +} + +inline bool bNode::is_group_output() const +{ + return this->type == NODE_GROUP_OUTPUT; +} + +inline blender::Span<const bNodeLink *> bNode::internal_links_span() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->internal_links; +} + +inline const blender::nodes::NodeDeclaration *bNode::declaration() const +{ + BLI_assert(this->runtime->declaration != nullptr); + return this->runtime->declaration; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #bNodeLink Inline Methods + * \{ */ + +inline bool bNodeLink::is_muted() const +{ + return this->flag & NODE_LINK_MUTED; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #bNodeSocket Inline Methods + * \{ */ + +inline int bNodeSocket::index() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->index_in_node; +} + +inline int bNodeSocket::index_in_tree() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->index_in_all_sockets; +} + +inline bool bNodeSocket::is_available() const +{ + return (this->flag & SOCK_UNAVAIL) == 0; +} + +inline bNode &bNodeSocket::owner_node() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->owner_node; +} + +inline const bNodeTree &bNodeSocket::owner_tree() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->owner_node->runtime->owner_tree; +} + +inline blender::Span<const bNodeSocket *> bNodeSocket::logically_linked_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->logically_linked_sockets; +} + +inline blender::Span<const bNodeLink *> bNodeSocket::directly_linked_links() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->directly_linked_links; +} + +inline blender::Span<bNodeLink *> bNodeSocket::directly_linked_links() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->directly_linked_links; +} + +inline blender::Span<const bNodeSocket *> bNodeSocket::directly_linked_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->directly_linked_sockets; +} + +inline bool bNodeSocket::is_directly_linked() const +{ + return !this->directly_linked_links().is_empty(); +} + +inline bool bNodeSocket::is_logically_linked() const +{ + return !this->logically_linked_sockets().is_empty(); +} + +inline const bNodeSocket *bNodeSocket::internal_link_input() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + BLI_assert(this->in_out == SOCK_OUT); + return this->runtime->internal_link_input; +} + +template<typename T> const T *bNodeSocket::default_value_typed() const +{ + return static_cast<const T *>(this->default_value); +} + +inline bool bNodeSocket::is_input() const +{ + return this->in_out == SOCK_IN; +} + +inline bool bNodeSocket::is_output() const +{ + return this->in_out == SOCK_OUT; +} + +inline bool bNodeSocket::is_multi_input() const +{ + return this->flag & SOCK_MULTI_INPUT; +} + +inline const bNode &bNodeSocket::owner_node() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->owner_node; +} + +/** \} */ diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h index ee90fea6506..62a1824d844 100644 --- a/source/blender/blenkernel/BKE_pointcloud.h +++ b/source/blender/blenkernel/BKE_pointcloud.h @@ -33,8 +33,6 @@ bool BKE_pointcloud_customdata_required(const struct PointCloud *pointcloud, con /* Dependency Graph */ -struct PointCloud *BKE_pointcloud_new_for_eval(const struct PointCloud *pointcloud_src, - int totpoint); struct PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool reference); void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 465573745ec..61549a66e1f 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -230,6 +230,7 @@ set(SRC intern/multires_versioning.c intern/nla.c intern/node.cc + intern/node_runtime.cc intern/node_tree_update.cc intern/object.cc intern/object_deform.c diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 2ce5863c176..e83720e99f1 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -95,7 +95,7 @@ static MVert *dm_getVertArray(DerivedMesh *dm) if (!mvert) { mvert = (MVert *)CustomData_add_layer( - &dm->vertData, CD_MVERT, CD_CALLOC, nullptr, dm->getNumVerts(dm)); + &dm->vertData, CD_MVERT, CD_SET_DEFAULT, nullptr, dm->getNumVerts(dm)); CustomData_set_layer_flag(&dm->vertData, CD_MVERT, CD_FLAG_TEMPORARY); dm->copyVertArray(dm, mvert); } @@ -109,7 +109,7 @@ static MEdge *dm_getEdgeArray(DerivedMesh *dm) if (!medge) { medge = (MEdge *)CustomData_add_layer( - &dm->edgeData, CD_MEDGE, CD_CALLOC, nullptr, dm->getNumEdges(dm)); + &dm->edgeData, CD_MEDGE, CD_SET_DEFAULT, nullptr, dm->getNumEdges(dm)); CustomData_set_layer_flag(&dm->edgeData, CD_MEDGE, CD_FLAG_TEMPORARY); dm->copyEdgeArray(dm, medge); } @@ -123,7 +123,7 @@ static MLoop *dm_getLoopArray(DerivedMesh *dm) if (!mloop) { mloop = (MLoop *)CustomData_add_layer( - &dm->loopData, CD_MLOOP, CD_CALLOC, nullptr, dm->getNumLoops(dm)); + &dm->loopData, CD_MLOOP, CD_SET_DEFAULT, nullptr, dm->getNumLoops(dm)); CustomData_set_layer_flag(&dm->loopData, CD_MLOOP, CD_FLAG_TEMPORARY); dm->copyLoopArray(dm, mloop); } @@ -137,7 +137,7 @@ static MPoly *dm_getPolyArray(DerivedMesh *dm) if (!mpoly) { mpoly = (MPoly *)CustomData_add_layer( - &dm->polyData, CD_MPOLY, CD_CALLOC, nullptr, dm->getNumPolys(dm)); + &dm->polyData, CD_MPOLY, CD_SET_DEFAULT, nullptr, dm->getNumPolys(dm)); CustomData_set_layer_flag(&dm->polyData, CD_MPOLY, CD_FLAG_TEMPORARY); dm->copyPolyArray(dm, mpoly); } @@ -284,11 +284,11 @@ void DM_from_template(DerivedMesh *dm, int numPolys) { const CustomData_MeshMasks *mask = &CD_MASK_DERIVEDMESH; - CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_CALLOC, numVerts); - CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_CALLOC, numEdges); - CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_CALLOC, numTessFaces); - CustomData_copy(&source->loopData, &dm->loopData, mask->lmask, CD_CALLOC, numLoops); - CustomData_copy(&source->polyData, &dm->polyData, mask->pmask, CD_CALLOC, numPolys); + CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts); + CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges); + CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces); + CustomData_copy(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops); + CustomData_copy(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys); dm->cd_flag = source->cd_flag; @@ -584,7 +584,7 @@ static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orc } if (!(layerorco = (float(*)[3])CustomData_get_layer(&mesh->vdata, layer))) { - CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, nullptr, mesh->totvert); + CustomData_add_layer(&mesh->vdata, layer, CD_SET_DEFAULT, nullptr, mesh->totvert); BKE_mesh_update_customdata_pointers(mesh, false); layerorco = (float(*)[3])CustomData_get_layer(&mesh->vdata, layer); @@ -741,6 +741,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, Mesh **r_final, GeometrySet **r_geometry_set) { + using namespace blender::bke; /* Input and final mesh. Final mesh is only created the moment the first * constructive modifier is executed, or a deform modifier needs normals * or certain data layers. */ @@ -824,18 +825,13 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); ASSERT_IS_VALID_MESH(mesh_final); } - float3 *rest_positions = static_cast<float3 *>(CustomData_add_layer_named(&mesh_final->vdata, - CD_PROP_FLOAT3, - CD_DEFAULT, - nullptr, - mesh_final->totvert, - "rest_position")); - blender::threading::parallel_for( - IndexRange(mesh_final->totvert), 1024, [&](const IndexRange range) { - for (const int i : range) { - rest_positions[i] = mesh_final->mvert[i].co; - } - }); + MutableAttributeAccessor attributes = mesh_attributes_for_write(*mesh_final); + SpanAttributeWriter<float3> rest_positions = + attributes.lookup_or_add_for_write_only_span<float3>("rest_position", ATTR_DOMAIN_POINT); + if (rest_positions) { + attributes.lookup<float3>("position").materialize(rest_positions.span); + rest_positions.finish(); + } } /* Apply all leading deform modifiers. */ @@ -1007,11 +1003,11 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, ((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX)) { /* calc */ CustomData_add_layer( - &mesh_final->vdata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totvert); + &mesh_final->vdata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totvert); CustomData_add_layer( - &mesh_final->edata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totedge); + &mesh_final->edata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totedge); CustomData_add_layer( - &mesh_final->pdata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totpoly); + &mesh_final->pdata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totpoly); /* Not worth parallelizing this, * gives less than 0.1% overall speedup in best of best cases... */ @@ -1047,8 +1043,11 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* add an origspace layer if needed */ if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) { if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { - CustomData_add_layer( - &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop); + CustomData_add_layer(&mesh_final->ldata, + CD_ORIGSPACE_MLOOP, + CD_SET_DEFAULT, + nullptr, + mesh_final->totloop); mesh_init_origspace(mesh_final); } } @@ -1510,8 +1509,11 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) { if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { - CustomData_add_layer( - &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop); + CustomData_add_layer(&mesh_final->ldata, + CD_ORIGSPACE_MLOOP, + CD_SET_DEFAULT, + nullptr, + mesh_final->totloop); mesh_init_origspace(mesh_final); } } diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc index ccaa6e56f08..0f7fabcff9b 100644 --- a/source/blender/blenkernel/intern/attribute.cc +++ b/source/blender/blenkernel/intern/attribute.cc @@ -247,7 +247,7 @@ CustomDataLayer *BKE_id_attribute_new( return nullptr; } - attributes->add(uniquename, domain, eCustomDataType(type), AttributeInitDefault()); + attributes->add(uniquename, domain, eCustomDataType(type), AttributeInitDefaultValue()); const int index = CustomData_get_named_layer_index(customdata, type, uniquename); return (index == -1) ? nullptr : &(customdata->layers[index]); @@ -421,6 +421,7 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer) if (mesh->edit_mesh != nullptr) { return 0; } + break; } default: break; diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 313e6a172ac..0187dbd6f78 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -160,12 +160,19 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data const AttributeInit &initializer) { switch (initializer.type) { - case AttributeInit::Type::Default: { - void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_num); + case AttributeInit::Type::Construct: { + void *data = CustomData_add_layer( + &custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num); + return data != nullptr; + } + case AttributeInit::Type::DefaultValue: { + void *data = CustomData_add_layer( + &custom_data, data_type, CD_SET_DEFAULT, nullptr, domain_num); return data != nullptr; } case AttributeInit::Type::VArray: { - void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_num); + void *data = CustomData_add_layer( + &custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num); if (data == nullptr) { return false; } @@ -174,7 +181,7 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data return true; } case AttributeInit::Type::MoveArray: { - void *source_data = static_cast<const AttributeInitMove &>(initializer).data; + void *source_data = static_cast<const AttributeInitMoveArray &>(initializer).data; void *data = CustomData_add_layer( &custom_data, data_type, CD_ASSIGN, source_data, domain_num); if (data == nullptr) { @@ -215,14 +222,19 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr { const int old_layer_num = custom_data.totlayer; switch (initializer.type) { - case AttributeInit::Type::Default: { + case AttributeInit::Type::Construct: { add_generic_custom_data_layer( - custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id); + custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num, attribute_id); + break; + } + case AttributeInit::Type::DefaultValue: { + add_generic_custom_data_layer( + custom_data, data_type, CD_SET_DEFAULT, nullptr, domain_num, attribute_id); break; } case AttributeInit::Type::VArray: { void *data = add_generic_custom_data_layer( - custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id); + custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num, attribute_id); if (data != nullptr) { const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; varray.materialize_to_uninitialized(varray.index_range(), data); @@ -230,7 +242,7 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr break; } case AttributeInit::Type::MoveArray: { - void *source_data = static_cast<const AttributeInitMove &>(initializer).data; + void *source_data = static_cast<const AttributeInitMoveArray &>(initializer).data; void *data = add_generic_custom_data_layer( custom_data, data_type, CD_ASSIGN, source_data, domain_num, attribute_id); if (source_data != nullptr && data == nullptr) { @@ -722,7 +734,7 @@ bool CustomDataAttributes::create(const AttributeIDRef &attribute_id, const eCustomDataType data_type) { void *result = add_generic_custom_data_layer( - data, data_type, CD_DEFAULT, nullptr, size_, attribute_id); + data, data_type, CD_SET_DEFAULT, nullptr, size_, attribute_id); return result != nullptr; } @@ -954,7 +966,8 @@ GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_span( GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_only_span( const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type) { - GAttributeWriter attribute = this->lookup_or_add_for_write(attribute_id, domain, data_type); + GAttributeWriter attribute = this->lookup_or_add_for_write( + attribute_id, domain, data_type, AttributeInitConstruct()); if (attribute) { return GSpanAttributeWriter{std::move(attribute), false}; } diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index fe9f6775995..3f549b39a00 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -58,7 +58,7 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num) CustomData_add_layer_named(&this->point_data, CD_PROP_FLOAT3, - CD_DEFAULT, + CD_CONSTRUCT, nullptr, this->point_num, ATTR_POSITION.c_str()); @@ -222,7 +222,7 @@ static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves, return {data, num}; } data = (T *)CustomData_add_layer_named( - &custom_data, type, CD_CALLOC, nullptr, num, name.c_str()); + &custom_data, type, CD_SET_DEFAULT, nullptr, num, name.c_str()); MutableSpan<T> span = {data, num}; if (num > 0 && span.first() != default_value) { span.fill(default_value); diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index fd0c781dd83..51edf8308c3 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -154,9 +154,15 @@ struct LayerTypeInfo { void (*swap)(void *data, const int *corner_indices); /** - * a function to set a layer's data to default values. if null, the - * default is assumed to be all zeros */ - void (*set_default)(void *data, int count); + * Set values to the type's default. If undefined, the default is assumed to be zeroes. + * Memory pointed to by #data is expected to be uninitialized. + */ + void (*set_default_value)(void *data, int count); + /** + * Construct and fill a valid value for the type. Necessary for non-trivial types. + * Memory pointed to by #data is expected to be uninitialized. + */ + void (*construct)(void *data, int count); /** A function used by mesh validating code, must ensures passed item has valid data. */ cd_validate validate; @@ -312,6 +318,11 @@ static void layerInterp_mdeformvert(const void **sources, } } +static void layerConstruct_mdeformvert(void *data, const int count) +{ + memset(data, 0, sizeof(MDeformVert) * count); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -497,11 +508,6 @@ static bool layerValidate_propFloat(void *data, const uint totitems, const bool /** \name Callbacks for (#MIntProperty, #CD_PROP_INT32) * \{ */ -static void layerCopy_propInt(const void *source, void *dest, const int count) -{ - memcpy(dest, source, sizeof(MIntProperty) * count); -} - static void layerInterp_propInt(const void **sources, const float *weights, const float *UNUSED(sub_weights), @@ -671,6 +677,11 @@ static void layerFree_mdisps(void *data, const int count, const int UNUSED(size) } } +static void layerConstruct_mdisps(void *data, const int count) +{ + memset(data, 0, sizeof(MDisps) * count); +} + static bool layerRead_mdisps(CDataFile *cdf, void *data, const int count) { MDisps *d = static_cast<MDisps *>(data); @@ -803,6 +814,11 @@ static void layerFree_grid_paint_mask(void *data, const int count, const int UNU } } +static void layerConstruct_grid_paint_mask(void *data, const int count) +{ + memset(data, 0, sizeof(GridPaintMask) * count); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1645,30 +1661,23 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerFree_mdeformvert, layerInterp_mdeformvert, nullptr, + layerConstruct_mdeformvert, nullptr}, /* 3: CD_MEDGE */ {sizeof(MEdge), "MEdge", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 4: CD_MFACE */ {sizeof(MFace), "MFace", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 5: CD_MTFACE */ - {sizeof(MTFace), "MTFace", 1, - N_("UVMap"), layerCopy_tface, nullptr, - layerInterp_tface, layerSwap_tface, layerDefault_tface, - nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - nullptr, layerMaxNum_tface}, - /* 6: CD_MCOL */ - /* 4 MCol structs per face */ - {sizeof(MCol[4]), - "MCol", - 4, - N_("Col"), + {sizeof(MTFace), + "MTFace", + 1, + N_("UVMap"), + layerCopy_tface, nullptr, + layerInterp_tface, + layerSwap_tface, nullptr, - layerInterp_mcol, - layerSwap_mcol, - layerDefault_mcol, + layerDefault_tface, nullptr, nullptr, nullptr, @@ -1679,7 +1688,16 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, nullptr, nullptr, - layerMaxNum_mloopcol}, + layerMaxNum_tface}, + /* 6: CD_MCOL */ + /* 4 MCol structs per face */ + {sizeof(MCol[4]), "MCol", 4, + N_("Col"), nullptr, nullptr, + layerInterp_mcol, layerSwap_mcol, layerDefault_mcol, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, nullptr, layerMaxNum_mloopcol}, /* 7: CD_ORIGINDEX */ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_origindex}, /* 8: CD_NORMAL */ @@ -1699,6 +1717,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, nullptr, nullptr, + nullptr, layerCopyValue_normal}, /* 9: CD_FACEMAP */ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_fmap, nullptr}, @@ -1712,13 +1731,14 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_propFloat, nullptr, nullptr, + nullptr, layerValidate_propFloat}, /* 11: CD_PROP_INT32 */ {sizeof(MIntProperty), "MIntProperty", 1, N_("Int"), - layerCopy_propInt, + nullptr, nullptr, layerInterp_propInt, nullptr}, @@ -1757,6 +1777,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_mloopuv, nullptr, nullptr, + nullptr, layerValidate_mloopuv, layerEqual_mloopuv, layerMultiply_mloopuv, @@ -1779,6 +1800,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, layerDefault_mloopcol, nullptr, + nullptr, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol, @@ -1801,6 +1823,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, layerSwap_mdisps, nullptr, + layerConstruct_mdisps, nullptr, nullptr, nullptr, @@ -1870,6 +1893,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, nullptr, nullptr, + nullptr, layerEqual_mloop_origspace, layerMultiply_mloop_origspace, layerInitMinMax_mloop_origspace, @@ -1887,6 +1911,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, layerDefault_mloopcol, nullptr, + nullptr, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol, @@ -1914,7 +1939,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerFree_grid_paint_mask, nullptr, nullptr, - nullptr}, + nullptr, + layerConstruct_grid_paint_mask}, /* 36: CD_MVERT_SKIN */ {sizeof(MVertSkin), "MVertSkin", @@ -1972,6 +1998,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, layerDefault_propcol, nullptr, + nullptr, layerEqual_propcol, layerMultiply_propcol, layerInitMinMax_propcol, @@ -1992,6 +2019,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_propfloat3, nullptr, nullptr, + nullptr, layerValidate_propfloat3, nullptr, layerMultiply_propfloat3, @@ -2007,6 +2035,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_propfloat2, nullptr, nullptr, + nullptr, layerValidate_propfloat2, nullptr, layerMultiply_propfloat2, @@ -2765,48 +2794,60 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, const LayerTypeInfo *typeInfo = layerType_getInfo(type); int flag = 0; - /* Passing a layer-data to copy from with an alloctype that won't copy is - * most likely a bug */ - BLI_assert(!layerdata || ELEM(alloctype, CD_ASSIGN, CD_DUPLICATE, CD_REFERENCE)); - if (!typeInfo->defaultname && CustomData_has_layer(data, type)) { return &data->layers[CustomData_get_layer_index(data, type)]; } void *newlayerdata = nullptr; - if (ELEM(alloctype, CD_ASSIGN, CD_REFERENCE)) { - newlayerdata = layerdata; - } - else if (totelem > 0 && typeInfo->size > 0) { - if (alloctype == CD_DUPLICATE && layerdata) { - newlayerdata = MEM_malloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type)); - } - else { - newlayerdata = MEM_calloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type)); - } - - if (!newlayerdata) { - return nullptr; - } - } - - if (alloctype == CD_DUPLICATE && layerdata) { - if (totelem > 0) { - if (typeInfo->copy) { - typeInfo->copy(layerdata, newlayerdata, totelem); + switch (alloctype) { + case CD_SET_DEFAULT: + if (totelem > 0) { + if (typeInfo->set_default_value) { + newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); + typeInfo->set_default_value(newlayerdata, totelem); + } + else { + newlayerdata = MEM_calloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); + } + } + break; + case CD_CONSTRUCT: + if (totelem > 0) { + newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); + if (typeInfo->construct) { + typeInfo->construct(newlayerdata, totelem); + } + } + break; + case CD_ASSIGN: + if (totelem > 0) { + BLI_assert(layerdata != nullptr); + newlayerdata = layerdata; } else { - memcpy(newlayerdata, layerdata, (size_t)totelem * typeInfo->size); + MEM_SAFE_FREE(layerdata); } - } - } - else if (alloctype == CD_DEFAULT) { - if (typeInfo->set_default) { - typeInfo->set_default(newlayerdata, totelem); - } - } - else if (alloctype == CD_REFERENCE) { - flag |= CD_FLAG_NOFREE; + break; + case CD_REFERENCE: + if (totelem > 0) { + BLI_assert(layerdata != nullptr); + newlayerdata = layerdata; + flag |= CD_FLAG_NOFREE; + } + break; + case CD_DUPLICATE: + if (totelem > 0) { + newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); + if (typeInfo->copy) { + typeInfo->copy(layerdata, newlayerdata, totelem); + } + else { + BLI_assert(layerdata != nullptr); + BLI_assert(newlayerdata != nullptr); + memcpy(newlayerdata, layerdata, totelem * typeInfo->size); + } + } + break; } int index = data->totlayer; @@ -3850,8 +3891,8 @@ static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const int offset = data->layers[n].offset; const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type); - if (typeInfo->set_default) { - typeInfo->set_default(POINTER_OFFSET(*block, offset), 1); + if (typeInfo->set_default_value) { + typeInfo->set_default_value(POINTER_OFFSET(*block, offset), 1); } else { memset(POINTER_OFFSET(*block, offset), 0, typeInfo->size); @@ -4558,8 +4599,8 @@ static bool CustomData_layer_ensure_data_exists(CustomDataLayer *layer, size_t c case CD_MLOOPUV: /* See T90620. */ layer->data = MEM_calloc_arrayN(count, typeInfo->size, layerType_getName(layer->type)); BLI_assert(layer->data); - if (typeInfo->set_default) { - typeInfo->set_default(layer->data, count); + if (typeInfo->set_default_value) { + typeInfo->set_default_value(layer->data, count); } return true; break; diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index be686635d3e..02b5175f65f 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -280,7 +280,8 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src, loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL); const bool do_loop_nors_dst = (loop_nors_dst == NULL); if (do_loop_nors_dst) { - loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst); + loop_nors_dst = CustomData_add_layer( + ldata_dst, CD_NORMAL, CD_SET_DEFAULT, NULL, num_loops_dst); CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } if (dirty_nors_dst || do_loop_nors_dst) { @@ -333,7 +334,7 @@ static void data_transfer_dtdata_type_postprocess(Object *UNUSED(ob_src), if (!custom_nors_dst) { custom_nors_dst = CustomData_add_layer( - ldata_dst, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops_dst); + ldata_dst, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, NULL, num_loops_dst); } /* Note loop_nors_dst contains our custom normals as transferred from source... */ @@ -561,7 +562,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map if (use_create) { /* Create as much data layers as necessary! */ for (; idx_dst < idx_src; idx_dst++) { - CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst); } } else { @@ -622,7 +623,8 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) { if (use_create) { - CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name); + CustomData_add_layer_named( + cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst, name); idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); } else { @@ -710,7 +712,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, if (!use_create) { return true; } - data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst); } else if (use_dupref_dst && r_map) { /* If dest is a evaluated mesh (from modifier), @@ -763,7 +765,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, if (!use_create) { return true; } - data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst); } else { /* If dest is a evaluated mesh (from modifier), @@ -786,7 +788,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, } /* Create as much data layers as necessary! */ for (; num <= idx_dst; num++) { - CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst); } } /* If dest is a evaluated mesh (from modifier), @@ -805,7 +807,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, if (!use_create) { return true; } - CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name); + CustomData_add_layer_named(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst, name); idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); } /* If dest is a evaluated mesh (from modifier), diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index ebe06fa85eb..d904744995d 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -1243,7 +1243,8 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * Again, use_create is not relevant in this case */ if (!data_dst) { - data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer( + cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, num_elem_dst); } while (idx_src--) { @@ -1303,7 +1304,8 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * use_create is not relevant in this case */ if (!data_dst) { - data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer( + cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, num_elem_dst); } data_transfer_layersmapping_add_item(r_map, @@ -1442,7 +1444,8 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map, /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * use_create is not relevant in this case */ if (!data_dst) { - data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer( + cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, num_elem_dst); } data_transfer_layersmapping_add_item(r_map, diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 423e76fce8c..8a41b2294f5 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -1944,7 +1944,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) { mloopcol = CustomData_add_layer_named(&result->ldata, CD_PROP_BYTE_COLOR, - CD_CALLOC, + CD_SET_DEFAULT, NULL, totloop, surface->output_name); @@ -1957,7 +1957,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) { mloopcol_wet = CustomData_add_layer_named(&result->ldata, CD_PROP_BYTE_COLOR, - CD_CALLOC, + CD_SET_DEFAULT, NULL, totloop, surface->output_name2); @@ -1988,7 +1988,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * /* apply weights into a vertex group, if doesn't exists add a new layer */ if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) { dvert = CustomData_add_layer( - &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, sData->total_points); + &result->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, sData->total_points); /* Make the dvert layer easily accessible from the mesh data. */ result->dvert = dvert; } diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c index 0a3107eee24..ec608f79e66 100644 --- a/source/blender/blenkernel/intern/editmesh_tangent.c +++ b/source/blender/blenkernel/intern/editmesh_tangent.c @@ -304,7 +304,7 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, "") == -1) { CustomData_add_layer_named( - loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, ""); + loopdata_out, CD_TANGENT, CD_SET_DEFAULT, NULL, (int)loopdata_out_len, ""); } if (calc_act && act_uv_name[0]) { BKE_mesh_add_loop_tangent_named_layer_for_uv( diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index 22f105af0f1..56a7e38b2fc 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -547,7 +547,8 @@ static GVArray varray_from_initializer(const AttributeInit &initializer, const Span<SplinePtr> splines) { switch (initializer.type) { - case AttributeInit::Type::Default: + case AttributeInit::Type::Construct: + case AttributeInit::Type::DefaultValue: /* This function shouldn't be called in this case, since there * is no need to copy anything to the new custom data array. */ BLI_assert_unreachable(); @@ -560,7 +561,7 @@ static GVArray varray_from_initializer(const AttributeInit &initializer, total_num += spline->size(); } return GVArray::ForSpan(GSpan(*bke::custom_data_type_to_cpp_type(data_type), - static_cast<const AttributeInitMove &>(initializer).data, + static_cast<const AttributeInitMoveArray &>(initializer).data, total_num)); } BLI_assert_unreachable(); @@ -580,7 +581,7 @@ static bool create_point_attribute(CurveEval *curve, /* First check the one case that allows us to avoid copying the input data. */ if (splines.size() == 1 && initializer.type == AttributeInit::Type::MoveArray) { - void *source_data = static_cast<const AttributeInitMove &>(initializer).data; + void *source_data = static_cast<const AttributeInitMoveArray &>(initializer).data; if (!splines.first()->attributes.create_by_move(attribute_id, data_type, source_data)) { MEM_freeN(source_data); return false; @@ -600,7 +601,7 @@ static bool create_point_attribute(CurveEval *curve, } /* With a default initializer type, we can keep the values at their initial values. */ - if (initializer.type == AttributeInit::Type::Default) { + if (ELEM(initializer.type, AttributeInit::Type::DefaultValue, AttributeInit::Type::Construct)) { return true; } @@ -616,7 +617,7 @@ static bool create_point_attribute(CurveEval *curve, write_attribute.finish(); if (initializer.type == AttributeInit::Type::MoveArray) { - MEM_freeN(static_cast<const AttributeInitMove &>(initializer).data); + MEM_freeN(static_cast<const AttributeInitMoveArray &>(initializer).data); } return true; diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 61f5a5f315f..bfa11b74782 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -1444,7 +1444,7 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name + 2); mesh->totvert = (int)process.curvertex; - MVert *mvert = CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_DEFAULT, NULL, mesh->totvert); + MVert *mvert = CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CONSTRUCT, NULL, mesh->totvert); for (int i = 0; i < mesh->totvert; i++) { copy_v3_v3(mvert[i].co, process.co[i]); mvert->bweight = 0; @@ -1453,8 +1453,9 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) MEM_freeN(process.co); mesh->totpoly = (int)process.curindex; - MPoly *mpoly = CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_DEFAULT, NULL, mesh->totpoly); - MLoop *mloop = CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_DEFAULT, NULL, mesh->totpoly * 4); + MPoly *mpoly = CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CONSTRUCT, NULL, mesh->totpoly); + MLoop *mloop = CustomData_add_layer( + &mesh->ldata, CD_MLOOP, CD_CONSTRUCT, NULL, mesh->totpoly * 4); int loop_offset = 0; for (int i = 0; i < mesh->totpoly; i++) { diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 6f91ce2a4e9..b44a956eec4 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -826,7 +826,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) else { if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) { vs = (MVertSkin *)CustomData_add_layer( - &me->vdata, CD_MVERT_SKIN, CD_DEFAULT, nullptr, me->totvert); + &me->vdata, CD_MVERT_SKIN, CD_SET_DEFAULT, nullptr, me->totvert); /* Mark an arbitrary vertex as root */ if (vs) { @@ -848,7 +848,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) } else { if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) { - CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, nullptr, me->totpoly); + CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_SET_DEFAULT, nullptr, me->totpoly); changed = true; } } @@ -991,20 +991,20 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface) { if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) { - CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert); + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, mesh->totvert); } if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) { - CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, nullptr, mesh->totedge); + CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, mesh->totedge); } if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) { - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop); } if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) { - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); } if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) { - CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, nullptr, mesh->totface); + CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_SET_DEFAULT, nullptr, mesh->totface); } } @@ -1101,12 +1101,12 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, me_dst->cd_flag = me_src->cd_flag; BKE_mesh_copy_parameters_for_eval(me_dst, me_src); - CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len); - CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len); - CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_CALLOC, loops_len); - CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_CALLOC, polys_len); + CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len); + CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len); + CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len); + CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len); if (do_tessface) { - CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_CALLOC, tessface_len); + CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len); } else { mesh_tessface_clear_intern(me_dst, false); @@ -1207,7 +1207,7 @@ static void ensure_orig_index_layer(CustomData &data, const int size) if (CustomData_has_layer(&data, CD_ORIGINDEX)) { return; } - int *indices = (int *)CustomData_add_layer(&data, CD_ORIGINDEX, CD_DEFAULT, nullptr, size); + int *indices = (int *)CustomData_add_layer(&data, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, size); range_vn_i(indices, size, 0); } @@ -1893,7 +1893,7 @@ static float (*ensure_corner_normal_layer(Mesh &mesh))[3] } else { r_loopnors = (float(*)[3])CustomData_add_layer( - &mesh.ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh.totloop); + &mesh.ldata, CD_NORMAL, CD_SET_DEFAULT, nullptr, mesh.totloop); CustomData_set_layer_flag(&mesh.ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } return r_loopnors; diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index 99cfcf01ba9..fb4a9248d8d 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -669,15 +669,15 @@ static void merge_vertex_loop_poly_customdata_layers(Mesh *target, MeshesToIMesh const Mesh *me = mim.meshes[mesh_index]; if (me->totvert) { CustomData_merge( - &me->vdata, &target->vdata, CD_MASK_MESH.vmask, CD_DEFAULT, target->totvert); + &me->vdata, &target->vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, target->totvert); } if (me->totloop) { CustomData_merge( - &me->ldata, &target->ldata, CD_MASK_MESH.lmask, CD_DEFAULT, target->totloop); + &me->ldata, &target->ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, target->totloop); } if (me->totpoly) { CustomData_merge( - &me->pdata, &target->pdata, CD_MASK_MESH.pmask, CD_DEFAULT, target->totpoly); + &me->pdata, &target->pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, target->totpoly); } } } @@ -688,7 +688,7 @@ static void merge_edge_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim) const Mesh *me = mim.meshes[mesh_index]; if (me->totedge) { CustomData_merge( - &me->edata, &target->edata, CD_MASK_MESH.emask, CD_DEFAULT, target->totedge); + &me->edata, &target->edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, target->totedge); } } } diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 0f05a3635c4..393d54bb03e 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -199,7 +199,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_only_span<int>( "material_index", ATTR_DOMAIN_FACE); MLoopUV *mloopuv = static_cast<MLoopUV *>(CustomData_add_layer_named( - &mesh->ldata, CD_MLOOPUV, CD_CALLOC, nullptr, mesh->totloop, "UVMap")); + &mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, mesh->totloop, "UVMap")); /* verts and faces */ vertcount = 0; @@ -682,7 +682,8 @@ void BKE_mesh_from_pointcloud(const PointCloud *pointcloud, Mesh *me) &pointcloud->pdata, &me->vdata, CD_MASK_PROP_ALL, CD_DUPLICATE, pointcloud->totpoint); /* Convert the Position attribute to a mesh vertex. */ - me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, me->totvert); + me->mvert = (MVert *)CustomData_add_layer( + &me->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, me->totvert); CustomData_update_typemap(&me->vdata); const int layer_idx = CustomData_get_named_layer_index( diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 33cdcb6f6ad..2fc984997b8 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -137,19 +137,19 @@ static void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int to for (int i = 0; i < fdata->totlayer; i++) { if (fdata->layers[i].type == CD_MTFACE) { CustomData_add_layer_named( - ldata, CD_MLOOPUV, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_MCOL) { CustomData_add_layer_named( - ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_MDISPS) { CustomData_add_layer_named( - ldata, CD_MDISPS, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + ldata, CD_MDISPS, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) { CustomData_add_layer_named( - ldata, CD_NORMAL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + ldata, CD_NORMAL, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); } } } @@ -849,26 +849,27 @@ void BKE_mesh_add_mface_layers(CustomData *fdata, CustomData *ldata, int total) for (int i = 0; i < ldata->totlayer; i++) { if (ldata->layers[i].type == CD_MLOOPUV) { CustomData_add_layer_named( - fdata, CD_MTFACE, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_MTFACE, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } if (ldata->layers[i].type == CD_PROP_BYTE_COLOR) { - CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name); + CustomData_add_layer_named( + fdata, CD_MCOL, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) { CustomData_add_layer_named( - fdata, CD_PREVIEW_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_PREVIEW_MCOL, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) { CustomData_add_layer_named( - fdata, CD_ORIGSPACE, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_ORIGSPACE, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_NORMAL) { CustomData_add_layer_named( - fdata, CD_TESSLOOPNORMAL, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_TESSLOOPNORMAL, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_TANGENT) { CustomData_add_layer_named( - fdata, CD_TANGENT, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_TANGENT, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } } diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 2366b7526a1..f90a2e1b887 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -2054,7 +2054,7 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const } else { clnors = (short(*)[2])CustomData_add_layer( - &mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, nullptr, numloops); + &mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, numloops); } mesh_normals_loop_custom_set(mesh->mvert, diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index 5313cc39646..4c6ee0ae3ee 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -1352,7 +1352,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, const bool do_loop_nors_dst = (loop_nors_dst == NULL); if (!loop_nors_dst) { loop_nors_dst = CustomData_add_layer( - ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst); + ldata_dst, CD_NORMAL, CD_SET_DEFAULT, NULL, numloops_dst); CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } if (dirty_nors_dst || do_loop_nors_dst) { diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index 423f76407a0..5a4fd0d7d96 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -291,7 +291,7 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, const Mesh *source) } else { target_mask = (float *)CustomData_add_layer( - &target->vdata, CD_PAINT_MASK, CD_CALLOC, nullptr, target->totvert); + &target->vdata, CD_PAINT_MASK, CD_CONSTRUCT, nullptr, target->totvert); } for (int i = 0; i < target->totvert; i++) { @@ -325,7 +325,7 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source) } else { target_face_sets = (int *)CustomData_add_layer( - &target->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, nullptr, target->totpoly); + &target->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, target->totpoly); } const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(source); @@ -376,7 +376,7 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source) int elem_num = domain == ATTR_DOMAIN_POINT ? target->totvert : target->totloop; CustomData_add_layer_named( - target_cdata, layer->type, CD_CALLOC, nullptr, elem_num, layer->name); + target_cdata, layer->type, CD_SET_DEFAULT, nullptr, elem_num, layer->name); layer_i = CustomData_get_named_layer_index(target_cdata, layer->type, layer->name); } diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c index 1772419e1f3..497f9ff3cbd 100644 --- a/source/blender/blenkernel/intern/mesh_tangent.c +++ b/source/blender/blenkernel/intern/mesh_tangent.c @@ -452,7 +452,8 @@ void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data, { if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 && CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1) { - CustomData_add_layer_named(tan_data, CD_TANGENT, CD_CALLOC, NULL, numLoopData, layer_name); + CustomData_add_layer_named( + tan_data, CD_TANGENT, CD_SET_DEFAULT, NULL, numLoopData, layer_name); } } @@ -581,7 +582,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert, if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1) { CustomData_add_layer_named( - loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, ""); + loopdata_out, CD_TANGENT, CD_SET_DEFAULT, NULL, (int)loopdata_out_len, ""); } if (calc_act && act_uv_name[0]) { BKE_mesh_add_loop_tangent_named_layer_for_uv( diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc index 0bc0822705c..3d8bbe3d6f8 100644 --- a/source/blender/blenkernel/intern/mesh_validate.cc +++ b/source/blender/blenkernel/intern/mesh_validate.cc @@ -1557,8 +1557,8 @@ void BKE_mesh_calc_edges_tessface(Mesh *mesh) /* write new edges into a temporary CustomData */ CustomData edgeData; CustomData_reset(&edgeData); - CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, nullptr, numEdges); - CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, nullptr, numEdges); + CustomData_add_layer(&edgeData, CD_MEDGE, CD_SET_DEFAULT, nullptr, numEdges); + CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, numEdges); MEdge *med = (MEdge *)CustomData_get_layer(&edgeData, CD_MEDGE); int *index = (int *)CustomData_get_layer(&edgeData, CD_ORIGINDEX); diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 63945f9ed42..5c382a4e864 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -960,7 +960,7 @@ static void multiresModifier_disp_run( if (!mdisps) { if (op == CALC_DISPLACEMENTS) { - mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_DEFAULT, NULL, me->totloop); + mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, me->totloop); } else { return; @@ -1487,7 +1487,7 @@ void multires_ensure_external_read(struct Mesh *mesh, int top_level) MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); if (mdisps == NULL) { - mdisps = CustomData_add_layer(&mesh->ldata, CD_MDISPS, CD_DEFAULT, NULL, mesh->totloop); + mdisps = CustomData_add_layer(&mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, mesh->totloop); } const int totloop = mesh->totloop; diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c index b50a0787fe3..17e4860ab1b 100644 --- a/source/blender/blenkernel/intern/multires_reshape.c +++ b/source/blender/blenkernel/intern/multires_reshape.c @@ -181,7 +181,8 @@ void multiresModifier_subdivide_to_level(struct Object *object, * are allocated at a proper level and return. */ const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS); if (!has_mdisps) { - CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop); + CustomData_add_layer( + &coarse_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, coarse_mesh->totloop); } /* NOTE: Subdivision happens from the top level of the existing multires modifier. If it is set diff --git a/source/blender/blenkernel/intern/multires_reshape_subdivide.c b/source/blender/blenkernel/intern/multires_reshape_subdivide.c index 9fa3e93a1e6..cecb57f4de4 100644 --- a/source/blender/blenkernel/intern/multires_reshape_subdivide.c +++ b/source/blender/blenkernel/intern/multires_reshape_subdivide.c @@ -68,7 +68,8 @@ void multires_subdivide_create_tangent_displacement_linear_grids(Object *object, const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS); if (!has_mdisps) { - CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop); + CustomData_add_layer( + &coarse_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, coarse_mesh->totloop); } if (new_top_level == 1) { diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c index cad680ecedd..27a1f84579e 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.c +++ b/source/blender/blenkernel/intern/multires_unsubdivide.c @@ -901,10 +901,10 @@ static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh) multires_unsubdivide_free_original_datalayers(mesh); int *l_index = CustomData_add_layer_named( - &mesh->ldata, CD_PROP_INT32, CD_CALLOC, NULL, mesh->totloop, lname); + &mesh->ldata, CD_PROP_INT32, CD_SET_DEFAULT, NULL, mesh->totloop, lname); int *v_index = CustomData_add_layer_named( - &mesh->vdata, CD_PROP_INT32, CD_CALLOC, NULL, mesh->totvert, vname); + &mesh->vdata, CD_PROP_INT32, CD_SET_DEFAULT, NULL, mesh->totvert, vname); /* Initialize these data-layer with the indices in the current mesh. */ for (int i = 0; i < mesh->totloop; i++) { @@ -1174,7 +1174,7 @@ static void multires_create_grids_in_unsubdivided_base_mesh(MultiresUnsubdivideC CustomData_free_layers(&base_mesh->ldata, CD_MDISPS, base_mesh->totloop); } MDisps *mdisps = CustomData_add_layer( - &base_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, base_mesh->totloop); + &base_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, base_mesh->totloop); const int totdisp = pow_i(BKE_ccg_gridsize(context->num_total_levels), 2); const int totloop = base_mesh->totloop; diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 4ed2885dd90..4eb48e9edc9 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -72,7 +72,6 @@ #include "NOD_function.h" #include "NOD_geometry.h" #include "NOD_node_declaration.hh" -#include "NOD_node_tree_ref.hh" #include "NOD_shader.h" #include "NOD_socket.h" #include "NOD_texture.h" @@ -104,7 +103,6 @@ using blender::nodes::NodeDeclaration; using blender::nodes::OutputFieldDependency; using blender::nodes::OutputSocketFieldType; using blender::nodes::SocketDeclaration; -using namespace blender::nodes::node_tree_ref_types; /* Fallback types for undefined tree, nodes, sockets */ static bNodeTreeType NodeTreeTypeUndefined; @@ -4583,6 +4581,7 @@ static void registerShaderNodes() register_node_type_sh_wavelength(); register_node_type_sh_blackbody(); register_node_type_sh_mix_rgb(); + register_node_type_sh_mix(); register_node_type_sh_valtorgb(); register_node_type_sh_rgbtobw(); register_node_type_sh_shadertorgb(); diff --git a/source/blender/blenkernel/intern/node_runtime.cc b/source/blender/blenkernel/intern/node_runtime.cc new file mode 100644 index 00000000000..0c78c0f09d1 --- /dev/null +++ b/source/blender/blenkernel/intern/node_runtime.cc @@ -0,0 +1,405 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_node.h" +#include "BKE_node_runtime.hh" + +#include "DNA_node_types.h" + +#include "BLI_function_ref.hh" +#include "BLI_stack.hh" +#include "BLI_task.hh" +#include "BLI_timeit.hh" + +namespace blender::bke::node_tree_runtime { + +static void double_checked_lock(std::mutex &mutex, bool &data_is_dirty, FunctionRef<void()> fn) +{ + if (!data_is_dirty) { + return; + } + std::lock_guard lock{mutex}; + if (!data_is_dirty) { + return; + } + fn(); + data_is_dirty = false; +} + +static void double_checked_lock_with_task_isolation(std::mutex &mutex, + bool &data_is_dirty, + FunctionRef<void()> fn) +{ + double_checked_lock(mutex, data_is_dirty, [&]() { threading::isolate_task(fn); }); +} + +static void update_node_vector(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.nodes.clear(); + tree_runtime.has_undefined_nodes_or_sockets = false; + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { + node->runtime->index_in_tree = tree_runtime.nodes.append_and_get_index(node); + node->runtime->owner_tree = const_cast<bNodeTree *>(&ntree); + tree_runtime.has_undefined_nodes_or_sockets |= node->typeinfo == &NodeTypeUndefined; + } +} + +static void update_link_vector(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.links.clear(); + LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { + tree_runtime.links.append(link); + } +} + +static void update_internal_links(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + for (bNode *node : tree_runtime.nodes) { + node->runtime->internal_links.clear(); + for (bNodeSocket *socket : node->runtime->outputs) { + socket->runtime->internal_link_input = nullptr; + } + LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { + node->runtime->internal_links.append(link); + link->tosock->runtime->internal_link_input = link->fromsock; + } + } +} + +static void update_socket_vectors_and_owner_node(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.sockets.clear(); + tree_runtime.input_sockets.clear(); + tree_runtime.output_sockets.clear(); + for (bNode *node : tree_runtime.nodes) { + bNodeRuntime &node_runtime = *node->runtime; + node_runtime.inputs.clear(); + node_runtime.outputs.clear(); + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + socket->runtime->index_in_node = node_runtime.inputs.append_and_get_index(socket); + socket->runtime->index_in_all_sockets = tree_runtime.sockets.append_and_get_index(socket); + socket->runtime->index_in_inout_sockets = tree_runtime.input_sockets.append_and_get_index( + socket); + socket->runtime->owner_node = node; + tree_runtime.has_undefined_nodes_or_sockets |= socket->typeinfo == &NodeSocketTypeUndefined; + } + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + socket->runtime->index_in_node = node_runtime.outputs.append_and_get_index(socket); + socket->runtime->index_in_all_sockets = tree_runtime.sockets.append_and_get_index(socket); + socket->runtime->index_in_inout_sockets = tree_runtime.output_sockets.append_and_get_index( + socket); + socket->runtime->owner_node = node; + tree_runtime.has_undefined_nodes_or_sockets |= socket->typeinfo == &NodeSocketTypeUndefined; + } + } +} + +static void update_directly_linked_links_and_sockets(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + for (bNode *node : tree_runtime.nodes) { + for (bNodeSocket *socket : node->runtime->inputs) { + socket->runtime->directly_linked_links.clear(); + socket->runtime->directly_linked_sockets.clear(); + } + for (bNodeSocket *socket : node->runtime->outputs) { + socket->runtime->directly_linked_links.clear(); + socket->runtime->directly_linked_sockets.clear(); + } + node->runtime->has_linked_inputs = false; + node->runtime->has_linked_outputs = false; + } + for (bNodeLink *link : tree_runtime.links) { + link->fromsock->runtime->directly_linked_links.append(link); + link->fromsock->runtime->directly_linked_sockets.append(link->tosock); + link->tosock->runtime->directly_linked_links.append(link); + link->fromnode->runtime->has_linked_outputs = true; + link->tonode->runtime->has_linked_inputs = true; + } + for (bNodeSocket *socket : tree_runtime.input_sockets) { + if (socket->flag & SOCK_MULTI_INPUT) { + std::sort(socket->runtime->directly_linked_links.begin(), + socket->runtime->directly_linked_links.end(), + [&](const bNodeLink *a, const bNodeLink *b) { + return a->multi_input_socket_index > b->multi_input_socket_index; + }); + } + } + for (bNodeSocket *socket : tree_runtime.input_sockets) { + for (bNodeLink *link : socket->runtime->directly_linked_links) { + /* Do this after sorting the input links. */ + socket->runtime->directly_linked_sockets.append(link->fromsock); + } + } +} + +static void find_logical_origins_for_socket_recursive( + bNodeSocket &input_socket, + bool only_follow_first_input_link, + Vector<bNodeSocket *, 16> &sockets_in_current_chain, + Vector<bNodeSocket *> &r_logical_origins, + Vector<bNodeSocket *> &r_skipped_origins) +{ + if (sockets_in_current_chain.contains(&input_socket)) { + /* Protect against reroute recursions. */ + return; + } + sockets_in_current_chain.append(&input_socket); + + Span<bNodeLink *> links_to_check = input_socket.runtime->directly_linked_links; + if (only_follow_first_input_link) { + links_to_check = links_to_check.take_front(1); + } + for (bNodeLink *link : links_to_check) { + if (link->flag & NODE_LINK_MUTED) { + continue; + } + bNodeSocket &origin_socket = *link->fromsock; + bNode &origin_node = *link->fromnode; + if (!origin_socket.is_available()) { + /* Non available sockets are ignored. */ + continue; + } + if (origin_node.type == NODE_REROUTE) { + bNodeSocket &reroute_input = *origin_node.runtime->inputs[0]; + bNodeSocket &reroute_output = *origin_node.runtime->outputs[0]; + r_skipped_origins.append(&reroute_input); + r_skipped_origins.append(&reroute_output); + find_logical_origins_for_socket_recursive( + reroute_input, false, sockets_in_current_chain, r_logical_origins, r_skipped_origins); + continue; + } + if (origin_node.is_muted()) { + if (bNodeSocket *mute_input = origin_socket.runtime->internal_link_input) { + r_skipped_origins.append(&origin_socket); + r_skipped_origins.append(mute_input); + find_logical_origins_for_socket_recursive( + *mute_input, true, sockets_in_current_chain, r_logical_origins, r_skipped_origins); + } + continue; + } + r_logical_origins.append(&origin_socket); + } + + sockets_in_current_chain.pop_last(); +} + +static void update_logical_origins(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + threading::parallel_for(tree_runtime.nodes.index_range(), 128, [&](const IndexRange range) { + for (const int i : range) { + bNode &node = *tree_runtime.nodes[i]; + for (bNodeSocket *socket : node.runtime->inputs) { + Vector<bNodeSocket *, 16> sockets_in_current_chain; + socket->runtime->logically_linked_sockets.clear(); + socket->runtime->logically_linked_skipped_sockets.clear(); + find_logical_origins_for_socket_recursive( + *socket, + false, + sockets_in_current_chain, + socket->runtime->logically_linked_sockets, + socket->runtime->logically_linked_skipped_sockets); + } + } + }); +} + +static void update_nodes_by_type(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.nodes_by_type.clear(); + for (bNode *node : tree_runtime.nodes) { + tree_runtime.nodes_by_type.add(node->typeinfo, node); + } +} + +static void update_sockets_by_identifier(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + threading::parallel_for(tree_runtime.nodes.index_range(), 128, [&](const IndexRange range) { + for (bNode *node : tree_runtime.nodes.as_span().slice(range)) { + node->runtime->inputs_by_identifier.clear(); + node->runtime->outputs_by_identifier.clear(); + for (bNodeSocket *socket : node->runtime->inputs) { + node->runtime->inputs_by_identifier.add_new(socket->identifier, socket); + } + for (bNodeSocket *socket : node->runtime->outputs) { + node->runtime->outputs_by_identifier.add_new(socket->identifier, socket); + } + } + }); +} + +enum class ToposortDirection { + LeftToRight, + RightToLeft, +}; + +struct ToposortNodeState { + bool is_done = false; + bool is_in_stack = false; +}; + +static void toposort_from_start_node(const ToposortDirection direction, + bNode &start_node, + MutableSpan<ToposortNodeState> node_states, + Vector<bNode *> &r_sorted_nodes, + bool &r_cycle_detected) +{ + struct Item { + bNode *node; + int socket_index = 0; + int link_index = 0; + }; + + Stack<Item, 64> nodes_to_check; + nodes_to_check.push({&start_node}); + while (!nodes_to_check.is_empty()) { + Item &item = nodes_to_check.peek(); + bNode &node = *item.node; + const Span<bNodeSocket *> sockets = (direction == ToposortDirection::LeftToRight) ? + node.runtime->inputs : + node.runtime->outputs; + while (true) { + if (item.socket_index == sockets.size()) { + /* All sockets have already been visited. */ + break; + } + bNodeSocket &socket = *sockets[item.socket_index]; + const Span<bNodeSocket *> linked_sockets = socket.runtime->directly_linked_sockets; + if (item.link_index == linked_sockets.size()) { + /* All links connected to this socket have already been visited. */ + item.socket_index++; + item.link_index = 0; + continue; + } + bNodeSocket &linked_socket = *linked_sockets[item.link_index]; + bNode &linked_node = *linked_socket.runtime->owner_node; + ToposortNodeState &linked_node_state = node_states[linked_node.runtime->index_in_tree]; + if (linked_node_state.is_done) { + /* The linked node has already been visited. */ + item.link_index++; + continue; + } + if (linked_node_state.is_in_stack) { + r_cycle_detected = true; + } + else { + nodes_to_check.push({&linked_node}); + linked_node_state.is_in_stack = true; + } + break; + } + + /* If no other element has been pushed, the current node can be pushed to the sorted list. */ + if (&item == &nodes_to_check.peek()) { + ToposortNodeState &node_state = node_states[node.runtime->index_in_tree]; + node_state.is_done = true; + node_state.is_in_stack = false; + r_sorted_nodes.append(&node); + nodes_to_check.pop(); + } + } +} + +static void update_toposort(const bNodeTree &ntree, + const ToposortDirection direction, + Vector<bNode *> &r_sorted_nodes, + bool &r_cycle_detected) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + r_sorted_nodes.clear(); + r_sorted_nodes.reserve(tree_runtime.nodes.size()); + r_cycle_detected = false; + + Array<ToposortNodeState> node_states(tree_runtime.nodes.size()); + for (bNode *node : tree_runtime.nodes) { + if (node_states[node->runtime->index_in_tree].is_done) { + /* Ignore nodes that are done already. */ + continue; + } + if ((direction == ToposortDirection::LeftToRight) ? node->runtime->has_linked_outputs : + node->runtime->has_linked_inputs) { + /* Ignore non-start nodes. */ + continue; + } + toposort_from_start_node(direction, *node, node_states, r_sorted_nodes, r_cycle_detected); + } + + if (r_sorted_nodes.size() < tree_runtime.nodes.size()) { + r_cycle_detected = true; + for (bNode *node : tree_runtime.nodes) { + if (node_states[node->runtime->index_in_tree].is_done) { + /* Ignore nodes that are done already. */ + continue; + } + /* Start toposort at this node which is somewhere in the middle of a loop. */ + toposort_from_start_node(direction, *node, node_states, r_sorted_nodes, r_cycle_detected); + } + } + + BLI_assert(tree_runtime.nodes.size() == r_sorted_nodes.size()); +} + +static void update_group_output_node(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + const bNodeType *node_type = nodeTypeFind("NodeGroupOutput"); + const Span<bNode *> group_output_nodes = tree_runtime.nodes_by_type.lookup(node_type); + if (group_output_nodes.is_empty()) { + tree_runtime.group_output_node = nullptr; + } + else if (group_output_nodes.size() == 1) { + tree_runtime.group_output_node = group_output_nodes[0]; + } + else { + for (bNode *group_output : group_output_nodes) { + if (group_output->flag & NODE_DO_OUTPUT) { + tree_runtime.group_output_node = group_output; + break; + } + } + } +} + +static void ensure_topology_cache(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + double_checked_lock_with_task_isolation( + tree_runtime.topology_cache_mutex, tree_runtime.topology_cache_is_dirty, [&]() { + update_node_vector(ntree); + update_link_vector(ntree); + update_socket_vectors_and_owner_node(ntree); + update_internal_links(ntree); + update_directly_linked_links_and_sockets(ntree); + threading::parallel_invoke([&]() { update_logical_origins(ntree); }, + [&]() { update_nodes_by_type(ntree); }, + [&]() { update_sockets_by_identifier(ntree); }, + [&]() { + update_toposort(ntree, + ToposortDirection::LeftToRight, + tree_runtime.toposort_left_to_right, + tree_runtime.has_link_cycle); + }, + [&]() { + bool dummy; + update_toposort(ntree, + ToposortDirection::RightToLeft, + tree_runtime.toposort_right_to_left, + dummy); + }); + update_group_output_node(ntree); + tree_runtime.topology_cache_exists = true; + }); +} + +} // namespace blender::bke::node_tree_runtime + +void bNodeTree::ensure_topology_cache() const +{ + blender::bke::node_tree_runtime::ensure_topology_cache(*this); +} diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index 58084226b00..a9097bcb94a 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -5,6 +5,7 @@ #include "BLI_noise.hh" #include "BLI_set.hh" #include "BLI_stack.hh" +#include "BLI_timeit.hh" #include "BLI_vector_set.hh" #include "DNA_anim_types.h" @@ -21,7 +22,6 @@ #include "MOD_nodes.h" #include "NOD_node_declaration.hh" -#include "NOD_node_tree_ref.hh" #include "NOD_texture.h" #include "DEG_depsgraph_query.h" @@ -50,6 +50,7 @@ enum eNodeTreeChangedFlag { static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag) { ntree->runtime->changed_flag |= flag; + ntree->runtime->topology_cache_is_dirty = true; } static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag) @@ -73,31 +74,32 @@ static bool is_field_socket_type(eNodeSocketDatatype type) return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA); } -static bool is_field_socket_type(const SocketRef &socket) +static bool is_field_socket_type(const bNodeSocket &socket) { - return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type); + return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo->type); } -static InputSocketFieldType get_interface_input_field_type(const NodeRef &node, - const InputSocketRef &socket) +static InputSocketFieldType get_interface_input_field_type(const bNode &node, + const bNodeSocket &socket) { if (!is_field_socket_type(socket)) { return InputSocketFieldType::None; } - if (node.is_reroute_node()) { + if (node.type == NODE_REROUTE) { return InputSocketFieldType::IsSupported; } - if (node.is_group_output_node()) { + if (node.type == NODE_GROUP_OUTPUT) { /* Outputs always support fields when the data type is correct. */ return InputSocketFieldType::IsSupported; } - if (node.is_undefined()) { + if (node.typeinfo == &NodeTypeUndefined) { return InputSocketFieldType::None; } - if (node.bnode()->type == NODE_CUSTOM) { + if (node.type == NODE_CUSTOM) { return InputSocketFieldType::None; } + /* TODO: Ensure declaration exists. */ const NodeDeclaration *node_decl = node.declaration(); /* Node declarations should be implemented for nodes involved here. */ @@ -116,25 +118,25 @@ static InputSocketFieldType get_interface_input_field_type(const NodeRef &node, return field_type; } -static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node, - const OutputSocketRef &socket) +static OutputFieldDependency get_interface_output_field_dependency(const bNode &node, + const bNodeSocket &socket) { if (!is_field_socket_type(socket)) { /* Non-field sockets always output data. */ return OutputFieldDependency::ForDataSource(); } - if (node.is_reroute_node()) { + if (node.type == NODE_REROUTE) { /* The reroute just forwards what is passed in. */ return OutputFieldDependency::ForDependentField(); } - if (node.is_group_input_node()) { + if (node.type == NODE_GROUP_INPUT) { /* Input nodes get special treatment in #determine_group_input_states. */ return OutputFieldDependency::ForDependentField(); } - if (node.is_undefined()) { + if (node.typeinfo == &NodeTypeUndefined) { return OutputFieldDependency::ForDataSource(); } - if (node.bnode()->type == NODE_CUSTOM) { + if (node.type == NODE_CUSTOM) { return OutputFieldDependency::ForDataSource(); } @@ -153,12 +155,13 @@ static OutputFieldDependency get_interface_output_field_dependency(const NodeRef return socket_decl.output_field_dependency(); } -static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node) +static FieldInferencingInterface get_dummy_field_inferencing_interface(const bNode &node) { FieldInferencingInterface inferencing_interface; - inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size()); + inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, + node.input_sockets().size()); inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(), - node.outputs().size()); + node.output_sockets().size()); return inferencing_interface; } @@ -167,11 +170,11 @@ static FieldInferencingInterface get_dummy_field_inferencing_interface(const Nod * In the future, this information can be stored in the node declaration. This would allow this * function to return a reference, making it more efficient. */ -static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node) +static FieldInferencingInterface get_node_field_inferencing_interface(const bNode &node) { /* Node groups already reference all required information, so just return that. */ - if (node.is_group_node()) { - bNodeTree *group = (bNodeTree *)node.bnode()->id; + if (node.is_group()) { + bNodeTree *group = (bNodeTree *)node.id; if (group == nullptr) { return FieldInferencingInterface(); } @@ -187,11 +190,11 @@ static FieldInferencingInterface get_node_field_inferencing_interface(const Node } FieldInferencingInterface inferencing_interface; - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket)); } - for (const OutputSocketRef *output_socket : node.outputs()) { + for (const bNodeSocket *output_socket : node.output_sockets()) { inferencing_interface.outputs.append( get_interface_output_field_dependency(node, *output_socket)); } @@ -215,11 +218,11 @@ struct SocketFieldState { bool requires_single = false; }; -static Vector<const InputSocketRef *> gather_input_socket_dependencies( - const OutputFieldDependency &field_dependency, const NodeRef &node) +static Vector<const bNodeSocket *> gather_input_socket_dependencies( + const OutputFieldDependency &field_dependency, const bNode &node) { const OutputSocketFieldType type = field_dependency.field_type(); - Vector<const InputSocketRef *> input_sockets; + Vector<const bNodeSocket *> input_sockets; switch (type) { case OutputSocketFieldType::FieldSource: case OutputSocketFieldType::None: { @@ -227,13 +230,13 @@ static Vector<const InputSocketRef *> gather_input_socket_dependencies( } case OutputSocketFieldType::DependentField: { /* This output depends on all inputs. */ - input_sockets.extend(node.inputs()); + input_sockets.extend(node.input_sockets()); break; } case OutputSocketFieldType::PartiallyDependent: { /* This output depends only on a few inputs. */ for (const int i : field_dependency.linked_input_indices()) { - input_sockets.append(&node.input(i)); + input_sockets.append(&node.input_socket(i)); } break; } @@ -246,8 +249,7 @@ static Vector<const InputSocketRef *> gather_input_socket_dependencies( * to figure out if it is always a field or if it depends on any group inputs. */ static OutputFieldDependency find_group_output_dependencies( - const InputSocketRef &group_output_socket, - const Span<SocketFieldState> field_state_by_socket_id) + const bNodeSocket &group_output_socket, const Span<SocketFieldState> field_state_by_socket_id) { if (!is_field_socket_type(group_output_socket)) { return OutputFieldDependency::ForDataSource(); @@ -255,8 +257,8 @@ static OutputFieldDependency find_group_output_dependencies( /* Use a Set here instead of an array indexed by socket id, because we my only need to look at * very few sockets. */ - Set<const InputSocketRef *> handled_sockets; - Stack<const InputSocketRef *> sockets_to_check; + Set<const bNodeSocket *> handled_sockets; + Stack<const bNodeSocket *> sockets_to_check; handled_sockets.add(&group_output_socket); sockets_to_check.push(&group_output_socket); @@ -265,20 +267,21 @@ static OutputFieldDependency find_group_output_dependencies( Vector<int> linked_input_indices; while (!sockets_to_check.is_empty()) { - const InputSocketRef *input_socket = sockets_to_check.pop(); + const bNodeSocket *input_socket = sockets_to_check.pop(); if (!input_socket->is_directly_linked() && - !field_state_by_socket_id[input_socket->id()].is_single) { + !field_state_by_socket_id[input_socket->index_in_tree()].is_single) { /* This socket uses a field as input by default. */ return OutputFieldDependency::ForFieldSource(); } - for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) { - const NodeRef &origin_node = origin_socket->node(); - const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()]; + for (const bNodeSocket *origin_socket : input_socket->directly_linked_sockets()) { + const bNode &origin_node = origin_socket->owner_node(); + const SocketFieldState &origin_state = + field_state_by_socket_id[origin_socket->index_in_tree()]; if (origin_state.is_field_source) { - if (origin_node.is_group_input_node()) { + if (origin_node.type == NODE_GROUP_INPUT) { /* Found a group input that the group output depends on. */ linked_input_indices.append_non_duplicates(origin_socket->index()); } @@ -294,12 +297,12 @@ static OutputFieldDependency find_group_output_dependencies( inferencing_interface.outputs[origin_socket->index()]; /* Propagate search further to the left. */ - for (const InputSocketRef *origin_input_socket : + for (const bNodeSocket *origin_input_socket : gather_input_socket_dependencies(field_dependency, origin_node)) { if (!origin_input_socket->is_available()) { continue; } - if (!field_state_by_socket_id[origin_input_socket->id()].is_single) { + if (!field_state_by_socket_id[origin_input_socket->index_in_tree()].is_single) { if (handled_sockets.add(origin_input_socket)) { sockets_to_check.push(origin_input_socket); } @@ -312,17 +315,16 @@ static OutputFieldDependency find_group_output_dependencies( } static void propagate_data_requirements_from_right_to_left( - const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id) + const bNodeTree &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id) { - const NodeTreeRef::ToposortResult toposort_result = tree.toposort( - NodeTreeRef::ToposortDirection::RightToLeft); + const Span<const bNode *> toposort_result = tree.toposort_right_to_left(); - for (const NodeRef *node : toposort_result.sorted_nodes) { + for (const bNode *node : toposort_result) { const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface( *node); - for (const OutputSocketRef *output_socket : node->outputs()) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNodeSocket *output_socket : node->output_sockets()) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; const OutputFieldDependency &field_dependency = inferencing_interface.outputs[output_socket->index()]; @@ -338,17 +340,18 @@ static void propagate_data_requirements_from_right_to_left( /* The output is required to be a single value when it is connected to any input that does * not support fields. */ - for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) { + for (const bNodeSocket *target_socket : output_socket->directly_linked_sockets()) { if (target_socket->is_available()) { - state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single; + state.requires_single |= + field_state_by_socket_id[target_socket->index_in_tree()].requires_single; } } if (state.requires_single) { bool any_input_is_field_implicitly = false; - const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies( + const Vector<const bNodeSocket *> connected_inputs = gather_input_socket_dependencies( field_dependency, *node); - for (const InputSocketRef *input_socket : connected_inputs) { + for (const bNodeSocket *input_socket : connected_inputs) { if (!input_socket->is_available()) { continue; } @@ -367,16 +370,16 @@ static void propagate_data_requirements_from_right_to_left( else { /* If the output is required to be a single value, the connected inputs in the same node * must not be fields as well. */ - for (const InputSocketRef *input_socket : connected_inputs) { - field_state_by_socket_id[input_socket->id()].requires_single = true; + for (const bNodeSocket *input_socket : connected_inputs) { + field_state_by_socket_id[input_socket->index_in_tree()].requires_single = true; } } } } /* Some inputs do not require fields independent of what the outputs are connected to. */ - for (const InputSocketRef *input_socket : node->inputs()) { - SocketFieldState &state = field_state_by_socket_id[input_socket->id()]; + for (const bNodeSocket *input_socket : node->input_sockets()) { + SocketFieldState &state = field_state_by_socket_id[input_socket->index_in_tree()]; if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) { state.requires_single = true; state.is_always_single = true; @@ -386,14 +389,14 @@ static void propagate_data_requirements_from_right_to_left( } static void determine_group_input_states( - const NodeTreeRef &tree, + const bNodeTree &tree, FieldInferencingInterface &new_inferencing_interface, const MutableSpan<SocketFieldState> field_state_by_socket_id) { { /* Non-field inputs never support fields. */ int index; - LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) { + LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.inputs, index) { if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) { new_inferencing_interface.inputs[index] = InputSocketFieldType::None; } @@ -401,18 +404,18 @@ static void determine_group_input_states( } /* Check if group inputs are required to be single values, because they are (indirectly) * connected to some socket that does not support fields. */ - for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) { - for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNode *node : tree.nodes_by_type("NodeGroupInput")) { + for (const bNodeSocket *output_socket : node->output_sockets().drop_back(1)) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; if (state.requires_single) { new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None; } } } /* If an input does not support fields, this should be reflected in all Group Input nodes. */ - for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) { - for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNode *node : tree.nodes_by_type("NodeGroupInput")) { + for (const bNodeSocket *output_socket : node->output_sockets().drop_back(1)) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] != InputSocketFieldType::None; if (supports_field) { @@ -423,19 +426,19 @@ static void determine_group_input_states( state.requires_single = true; } } - SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()]; + SocketFieldState &dummy_socket_state = + field_state_by_socket_id[node->output_sockets().last()->index_in_tree()]; dummy_socket_state.requires_single = true; } } static void propagate_field_status_from_left_to_right( - const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id) + const bNodeTree &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id) { - const NodeTreeRef::ToposortResult toposort_result = tree.toposort( - NodeTreeRef::ToposortDirection::LeftToRight); + const Span<const bNode *> toposort_result = tree.toposort_left_to_right(); - for (const NodeRef *node : toposort_result.sorted_nodes) { - if (node->is_group_input_node()) { + for (const bNode *node : toposort_result) { + if (node->type == NODE_GROUP_INPUT) { continue; } @@ -443,22 +446,22 @@ static void propagate_field_status_from_left_to_right( *node); /* Update field state of input sockets, also taking into account linked origin sockets. */ - for (const InputSocketRef *input_socket : node->inputs()) { - SocketFieldState &state = field_state_by_socket_id[input_socket->id()]; + for (const bNodeSocket *input_socket : node->input_sockets()) { + SocketFieldState &state = field_state_by_socket_id[input_socket->index_in_tree()]; if (state.is_always_single) { state.is_single = true; continue; } state.is_single = true; - if (input_socket->directly_linked_sockets().is_empty()) { + if (!input_socket->is_directly_linked()) { if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::Implicit) { state.is_single = false; } } else { - for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) { - if (!field_state_by_socket_id[origin_socket->id()].is_single) { + for (const bNodeSocket *origin_socket : input_socket->directly_linked_sockets()) { + if (!field_state_by_socket_id[origin_socket->index_in_tree()].is_single) { state.is_single = false; break; } @@ -467,8 +470,8 @@ static void propagate_field_status_from_left_to_right( } /* Update field state of output sockets, also taking into account input sockets. */ - for (const OutputSocketRef *output_socket : node->outputs()) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNodeSocket *output_socket : node->output_sockets()) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; const OutputFieldDependency &field_dependency = inferencing_interface.outputs[output_socket->index()]; @@ -484,12 +487,12 @@ static void propagate_field_status_from_left_to_right( } case OutputSocketFieldType::PartiallyDependent: case OutputSocketFieldType::DependentField: { - for (const InputSocketRef *input_socket : + for (const bNodeSocket *input_socket : gather_input_socket_dependencies(field_dependency, *node)) { if (!input_socket->is_available()) { continue; } - if (!field_state_by_socket_id[input_socket->id()].is_single) { + if (!field_state_by_socket_id[input_socket->index_in_tree()].is_single) { state.is_single = false; break; } @@ -501,17 +504,18 @@ static void propagate_field_status_from_left_to_right( } } -static void determine_group_output_states(const NodeTreeRef &tree, +static void determine_group_output_states(const bNodeTree &tree, FieldInferencingInterface &new_inferencing_interface, const Span<SocketFieldState> field_state_by_socket_id) { - for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) { + for (const bNode *group_output_node : tree.nodes_by_type("NodeGroupOutput")) { /* Ignore inactive group output nodes. */ - if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) { + if (!(group_output_node->flag & NODE_DO_OUTPUT)) { continue; } /* Determine dependencies of all group outputs. */ - for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) { + for (const bNodeSocket *group_output_socket : + group_output_node->input_sockets().drop_back(1)) { OutputFieldDependency field_dependency = find_group_output_dependencies( *group_output_socket, field_state_by_socket_id); new_inferencing_interface.outputs[group_output_socket->index()] = std::move( @@ -521,7 +525,7 @@ static void determine_group_output_states(const NodeTreeRef &tree, } } -static void update_socket_shapes(const NodeTreeRef &tree, +static void update_socket_shapes(const bNodeTree &tree, const Span<SocketFieldState> field_state_by_socket_id) { const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE; @@ -541,32 +545,30 @@ static void update_socket_shapes(const NodeTreeRef &tree, return data_but_can_be_field_shape; }; - for (const InputSocketRef *socket : tree.input_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - const SocketFieldState &state = field_state_by_socket_id[socket->id()]; - bsocket->display_shape = get_shape_for_state(state); + for (const bNodeSocket *socket : tree.all_input_sockets()) { + const SocketFieldState &state = field_state_by_socket_id[socket->index_in_tree()]; + const_cast<bNodeSocket *>(socket)->display_shape = get_shape_for_state(state); } - for (const OutputSocketRef *socket : tree.output_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - const SocketFieldState &state = field_state_by_socket_id[socket->id()]; - bsocket->display_shape = get_shape_for_state(state); + for (const bNodeSocket *socket : tree.all_sockets()) { + const SocketFieldState &state = field_state_by_socket_id[socket->index_in_tree()]; + const_cast<bNodeSocket *>(socket)->display_shape = get_shape_for_state(state); } } -static bool update_field_inferencing(const NodeTreeRef &tree) +static bool update_field_inferencing(const bNodeTree &tree) { - bNodeTree &btree = *tree.btree(); + tree.ensure_topology_cache(); /* Create new inferencing interface for this node group. */ std::unique_ptr<FieldInferencingInterface> new_inferencing_interface = std::make_unique<FieldInferencingInterface>(); - new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs), + new_inferencing_interface->inputs.resize(BLI_listbase_count(&tree.inputs), InputSocketFieldType::IsSupported); - new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs), + new_inferencing_interface->outputs.resize(BLI_listbase_count(&tree.outputs), OutputFieldDependency::ForDataSource()); /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */ - Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size()); + Array<SocketFieldState> field_state_by_socket_id(tree.all_sockets().size()); propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id); determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id); @@ -575,10 +577,10 @@ static bool update_field_inferencing(const NodeTreeRef &tree) update_socket_shapes(tree, field_state_by_socket_id); /* Update the previous group interface. */ - const bool group_interface_changed = !btree.runtime->field_inferencing_interface || - *btree.runtime->field_inferencing_interface != + const bool group_interface_changed = !tree.runtime->field_inferencing_interface || + *tree.runtime->field_inferencing_interface != *new_inferencing_interface; - btree.runtime->field_inferencing_interface = std::move(new_inferencing_interface); + tree.runtime->field_inferencing_interface = std::move(new_inferencing_interface); return group_interface_changed; } @@ -979,29 +981,22 @@ class NodeTreeMainUpdater { { TreeUpdateResult result; - /* Use a #NodeTreeRef to speedup certain queries. It is rebuilt whenever the node tree topology - * changes, which typically happens zero or one times during the entire update of the node - * tree. */ - std::unique_ptr<NodeTreeRef> tree_ref; - this->ensure_tree_ref(ntree, tree_ref); - - this->update_socket_link_and_use(*tree_ref); - this->update_individual_nodes(ntree, tree_ref); - this->update_internal_links(ntree, tree_ref); - this->update_generic_callback(ntree, tree_ref); + this->update_socket_link_and_use(ntree); + this->update_individual_nodes(ntree); + this->update_internal_links(ntree); + this->update_generic_callback(ntree); this->remove_unused_previews_when_necessary(ntree); - this->ensure_tree_ref(ntree, tree_ref); - this->propagate_runtime_flags(*tree_ref); + this->propagate_runtime_flags(ntree); if (ntree.type == NTREE_GEOMETRY) { - if (node_field_inferencing::update_field_inferencing(*tree_ref)) { + if (node_field_inferencing::update_field_inferencing(ntree)) { result.interface_changed = true; } } - result.output_changed = this->check_if_output_changed(*tree_ref); + result.output_changed = this->check_if_output_changed(ntree); - this->update_socket_link_and_use(*tree_ref); + this->update_socket_link_and_use(ntree); this->update_node_levels(ntree); this->update_link_validation(ntree); @@ -1021,86 +1016,69 @@ class NodeTreeMainUpdater { return result; } - void ensure_tree_ref(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref) - { - if (!tree_ref) { - tree_ref = std::make_unique<NodeTreeRef>(&ntree); - } - } - - void update_socket_link_and_use(const NodeTreeRef &tree) + void update_socket_link_and_use(bNodeTree &tree) { - for (const InputSocketRef *socket : tree.input_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); + tree.ensure_topology_cache(); + for (bNodeSocket *socket : tree.all_input_sockets()) { if (socket->directly_linked_links().is_empty()) { - bsocket->link = nullptr; + socket->link = nullptr; } else { - bsocket->link = socket->directly_linked_links()[0]->blink(); + socket->link = socket->directly_linked_links()[0]; } } this->update_socket_used_tags(tree); } - void update_socket_used_tags(const NodeTreeRef &tree) + void update_socket_used_tags(bNodeTree &tree) { - for (const SocketRef *socket : tree.sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - bsocket->flag &= ~SOCK_IN_USE; - for (const LinkRef *link : socket->directly_linked_links()) { + tree.ensure_topology_cache(); + for (bNodeSocket *socket : tree.all_sockets()) { + socket->flag &= ~SOCK_IN_USE; + for (const bNodeLink *link : socket->directly_linked_links()) { if (!link->is_muted()) { - bsocket->flag |= SOCK_IN_USE; + socket->flag |= SOCK_IN_USE; break; } } } } - void update_individual_nodes(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref) + void update_individual_nodes(bNodeTree &ntree) { - /* Iterate over nodes instead of #NodeTreeRef, because the #tree_ref might be outdated after - * some update functions. */ - LISTBASE_FOREACH (bNode *, bnode, &ntree.nodes) { - this->ensure_tree_ref(ntree, tree_ref); - const NodeRef &node = *tree_ref->find_node(*bnode); - if (this->should_update_individual_node(node)) { - const uint32_t old_changed_flag = ntree.runtime->changed_flag; - ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING; - - /* This may set #ntree.runtime->changed_flag which is detected below. */ - this->update_individual_node(node); - - if (ntree.runtime->changed_flag != NTREE_CHANGED_NOTHING) { - /* The tree ref is outdated and needs to be rebuilt. Generally, only very few update - * functions change the node. Typically zero or one nodes change after an update. */ - tree_ref.reset(); + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { + if (this->should_update_individual_node(ntree, *node)) { + bNodeType &ntype = *node->typeinfo; + if (ntype.group_update_func) { + ntype.group_update_func(&ntree, node); + } + if (ntype.updatefunc) { + ntype.updatefunc(&ntree, node); } - ntree.runtime->changed_flag |= old_changed_flag; } } } - bool should_update_individual_node(const NodeRef &node) + bool should_update_individual_node(const bNodeTree &ntree, const bNode &node) { - bNodeTree &ntree = *node.btree(); - bNode &bnode = *node.bnode(); if (ntree.runtime->changed_flag & NTREE_CHANGED_ANY) { return true; } - if (bnode.runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) { + if (node.runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) { return true; } if (ntree.runtime->changed_flag & NTREE_CHANGED_LINK) { + ntree.ensure_topology_cache(); /* Node groups currently always rebuilt their sockets when they are updated. * So avoid calling the update method when no new link was added to it. */ - if (node.is_group_input_node()) { - if (node.outputs().last()->is_directly_linked()) { + if (node.type == NODE_GROUP_INPUT) { + if (node.output_sockets().last()->is_directly_linked()) { return true; } } - else if (node.is_group_output_node()) { - if (node.inputs().last()->is_directly_linked()) { + else if (node.type == NODE_GROUP_OUTPUT) { + if (node.input_sockets().last()->is_directly_linked()) { return true; } } @@ -1110,95 +1088,76 @@ class NodeTreeMainUpdater { } } if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE) { - if (node.is_group_input_node() || node.is_group_output_node()) { + if (ELEM(node.type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { return true; } } return false; } - void update_individual_node(const NodeRef &node) - { - bNodeTree &ntree = *node.btree(); - bNode &bnode = *node.bnode(); - bNodeType &ntype = *bnode.typeinfo; - if (ntype.group_update_func) { - ntype.group_update_func(&ntree, &bnode); - } - if (ntype.updatefunc) { - ntype.updatefunc(&ntree, &bnode); - } - } - - void update_internal_links(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref) + void update_internal_links(bNodeTree &ntree) { - bool any_internal_links_updated = false; - this->ensure_tree_ref(ntree, tree_ref); - for (const NodeRef *node : tree_ref->nodes()) { - if (!this->should_update_individual_node(*node)) { + bke::node_tree_runtime::AllowUsingOutdatedInfo allow_outdated_info{ntree}; + ntree.ensure_topology_cache(); + for (bNode *node : ntree.all_nodes()) { + if (!this->should_update_individual_node(ntree, *node)) { continue; } /* Find all expected internal links. */ Vector<std::pair<bNodeSocket *, bNodeSocket *>> expected_internal_links; - for (const OutputSocketRef *output_socket : node->outputs()) { + for (const bNodeSocket *output_socket : node->output_sockets()) { if (!output_socket->is_available()) { continue; } if (!output_socket->is_directly_linked()) { continue; } - if (output_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) { + if (output_socket->flag & SOCK_NO_INTERNAL_LINK) { continue; } - const InputSocketRef *input_socket = this->find_internally_linked_input(output_socket); + const bNodeSocket *input_socket = this->find_internally_linked_input(output_socket); if (input_socket != nullptr) { - expected_internal_links.append({input_socket->bsocket(), output_socket->bsocket()}); + expected_internal_links.append( + {const_cast<bNodeSocket *>(input_socket), const_cast<bNodeSocket *>(output_socket)}); } } - /* rebuilt internal links if they have changed. */ - if (node->internal_links().size() != expected_internal_links.size()) { - this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links); - any_internal_links_updated = true; + /* Rebuilt internal links if they have changed. */ + if (node->internal_links_span().size() != expected_internal_links.size()) { + this->update_internal_links_in_node(ntree, *node, expected_internal_links); } else { for (auto &item : expected_internal_links) { const bNodeSocket *from_socket = item.first; const bNodeSocket *to_socket = item.second; bool found = false; - for (const InternalLinkRef *internal_link : node->internal_links()) { - if (from_socket == internal_link->from().bsocket() && - to_socket == internal_link->to().bsocket()) { + for (const bNodeLink *internal_link : node->internal_links_span()) { + if (from_socket == internal_link->fromsock && to_socket == internal_link->tosock) { found = true; } } if (!found) { - this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links); - any_internal_links_updated = true; + this->update_internal_links_in_node(ntree, *node, expected_internal_links); break; } } } } - - if (any_internal_links_updated) { - tree_ref.reset(); - } } - const InputSocketRef *find_internally_linked_input(const OutputSocketRef *output_socket) + const bNodeSocket *find_internally_linked_input(const bNodeSocket *output_socket) { - const InputSocketRef *selected_socket = nullptr; + const bNodeSocket *selected_socket = nullptr; int selected_priority = -1; bool selected_is_linked = false; - for (const InputSocketRef *input_socket : output_socket->node().inputs()) { + for (const bNodeSocket *input_socket : output_socket->owner_node().input_sockets()) { if (!input_socket->is_available()) { continue; } - if (input_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) { + if (input_socket->flag & SOCK_NO_INTERNAL_LINK) { continue; } - const int priority = get_internal_link_type_priority(input_socket->bsocket()->typeinfo, - output_socket->bsocket()->typeinfo); + const int priority = get_internal_link_type_priority(input_socket->typeinfo, + output_socket->typeinfo); if (priority < 0) { continue; } @@ -1233,23 +1192,12 @@ class NodeTreeMainUpdater { BKE_ntree_update_tag_node_internal_link(&ntree, &node); } - void update_generic_callback(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref) + void update_generic_callback(bNodeTree &ntree) { if (ntree.typeinfo->update == nullptr) { return; } - - /* Reset the changed_flag to allow detecting when the update callback changed the node tree. */ - const uint32_t old_changed_flag = ntree.runtime->changed_flag; - ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING; - ntree.typeinfo->update(&ntree); - - if (ntree.runtime->changed_flag != NTREE_CHANGED_NOTHING) { - /* The tree ref is outdated and needs to be rebuilt. */ - tree_ref.reset(); - } - ntree.runtime->changed_flag |= old_changed_flag; } void remove_unused_previews_when_necessary(bNodeTree &ntree) @@ -1264,25 +1212,26 @@ class NodeTreeMainUpdater { BKE_node_preview_remove_unused(&ntree); } - void propagate_runtime_flags(const NodeTreeRef &tree_ref) + void propagate_runtime_flags(const bNodeTree &ntree) { - bNodeTree &ntree = *tree_ref.btree(); + ntree.ensure_topology_cache(); + ntree.runtime->runtime_flag = 0; if (ntree.type != NTREE_SHADER) { return; } /* Check if a used node group has an animated image. */ - for (const NodeRef *group_node : tree_ref.nodes_by_type("ShaderNodeGroup")) { - const bNodeTree *group = reinterpret_cast<bNodeTree *>(group_node->bnode()->id); + for (const bNode *group_node : ntree.nodes_by_type("ShaderNodeGroup")) { + const bNodeTree *group = reinterpret_cast<bNodeTree *>(group_node->id); if (group != nullptr) { ntree.runtime->runtime_flag |= group->runtime->runtime_flag; } } /* Check if the tree itself has an animated image. */ for (const StringRefNull idname : {"ShaderNodeTexImage", "ShaderNodeTexEnvironment"}) { - for (const NodeRef *node : tree_ref.nodes_by_type(idname)) { - Image *image = reinterpret_cast<Image *>(node->bnode()->id); + for (const bNode *node : ntree.nodes_by_type(idname)) { + Image *image = reinterpret_cast<Image *>(node->id); if (image != nullptr && BKE_image_is_animated(image)) { ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION; break; @@ -1294,7 +1243,7 @@ class NodeTreeMainUpdater { "ShaderNodeOutputLight", "ShaderNodeOutputWorld", "ShaderNodeOutputAOV"}) { - const Span<const NodeRef *> nodes = tree_ref.nodes_by_type(idname); + const Span<const bNode *> nodes = ntree.nodes_by_type(idname); if (!nodes.is_empty()) { ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT; break; @@ -1325,20 +1274,20 @@ class NodeTreeMainUpdater { } } - bool check_if_output_changed(const NodeTreeRef &tree) + bool check_if_output_changed(const bNodeTree &tree) { - bNodeTree &btree = *tree.btree(); + tree.ensure_topology_cache(); /* Compute a hash that represents the node topology connected to the output. This always has to * be updated even if it is not used to detect changes right now. Otherwise * #btree.runtime.output_topology_hash will go out of date. */ - const Vector<const SocketRef *> tree_output_sockets = this->find_output_sockets(tree); - const uint32_t old_topology_hash = btree.runtime->output_topology_hash; + const Vector<const bNodeSocket *> tree_output_sockets = this->find_output_sockets(tree); + const uint32_t old_topology_hash = tree.runtime->output_topology_hash; const uint32_t new_topology_hash = this->get_combined_socket_topology_hash( tree, tree_output_sockets); - btree.runtime->output_topology_hash = new_topology_hash; + tree.runtime->output_topology_hash = new_topology_hash; - if (const AnimData *adt = BKE_animdata_from_id(&btree.id)) { + if (const AnimData *adt = BKE_animdata_from_id(&tree.id)) { /* Drivers may copy values in the node tree around arbitrarily and may cause the output to * change even if it wouldn't without drivers. Only some special drivers like `frame/5` can * be used without causing updates all the time currently. In the future we could try to @@ -1360,7 +1309,7 @@ class NodeTreeMainUpdater { } } - if (btree.runtime->changed_flag & NTREE_CHANGED_ANY) { + if (tree.runtime->changed_flag & NTREE_CHANGED_ANY) { return true; } @@ -1369,8 +1318,8 @@ class NodeTreeMainUpdater { } /* The topology hash can only be used when only topology-changing operations have been done. */ - if (btree.runtime->changed_flag == - (btree.runtime->changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) { + if (tree.runtime->changed_flag == + (tree.runtime->changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) { if (old_topology_hash == new_topology_hash) { return false; } @@ -1383,15 +1332,15 @@ class NodeTreeMainUpdater { return true; } - Vector<const SocketRef *> find_output_sockets(const NodeTreeRef &tree) + Vector<const bNodeSocket *> find_output_sockets(const bNodeTree &tree) { - Vector<const SocketRef *> sockets; - for (const NodeRef *node : tree.nodes()) { + Vector<const bNodeSocket *> sockets; + for (const bNode *node : tree.all_nodes()) { if (!this->is_output_node(*node)) { continue; } - for (const InputSocketRef *socket : node->inputs()) { - if (socket->idname() != "NodeSocketVirtual") { + for (const bNodeSocket *socket : node->input_sockets()) { + if (!STREQ(socket->idname, "NodeSocketVirtual")) { sockets.append(socket); } } @@ -1399,18 +1348,17 @@ class NodeTreeMainUpdater { return sockets; } - bool is_output_node(const NodeRef &node) const + bool is_output_node(const bNode &node) const { - const bNode &bnode = *node.bnode(); - if (bnode.typeinfo->nclass == NODE_CLASS_OUTPUT) { + if (node.typeinfo->nclass == NODE_CLASS_OUTPUT) { return true; } - if (bnode.type == NODE_GROUP_OUTPUT) { + if (node.type == NODE_GROUP_OUTPUT) { return true; } /* Assume node groups without output sockets are outputs. */ - if (bnode.type == NODE_GROUP) { - const bNodeTree *node_group = reinterpret_cast<const bNodeTree *>(bnode.id); + if (node.type == NODE_GROUP) { + const bNodeTree *node_group = reinterpret_cast<const bNodeTree *>(node.id); if (node_group != nullptr && node_group->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT) { return true; @@ -1423,10 +1371,10 @@ class NodeTreeMainUpdater { * Computes a hash that changes when the node tree topology connected to an output node changes. * Adding reroutes does not have an effect on the hash. */ - uint32_t get_combined_socket_topology_hash(const NodeTreeRef &tree, - Span<const SocketRef *> sockets) + uint32_t get_combined_socket_topology_hash(const bNodeTree &tree, + Span<const bNodeSocket *> sockets) { - if (tree.has_link_cycles()) { + if (tree.has_link_cycle()) { /* Return dummy value when the link has any cycles. The algorithm below could be improved to * handle cycles more gracefully. */ return 0; @@ -1439,29 +1387,28 @@ class NodeTreeMainUpdater { return combined_hash; } - Array<uint32_t> get_socket_topology_hashes(const NodeTreeRef &tree, - Span<const SocketRef *> sockets) + Array<uint32_t> get_socket_topology_hashes(const bNodeTree &tree, + Span<const bNodeSocket *> sockets) { - BLI_assert(!tree.has_link_cycles()); - Array<std::optional<uint32_t>> hash_by_socket_id(tree.sockets().size()); - Stack<const SocketRef *> sockets_to_check = sockets; + BLI_assert(!tree.has_link_cycle()); + Array<std::optional<uint32_t>> hash_by_socket_id(tree.all_sockets().size()); + Stack<const bNodeSocket *> sockets_to_check = sockets; while (!sockets_to_check.is_empty()) { - const SocketRef &in_out_socket = *sockets_to_check.peek(); - const NodeRef &node = in_out_socket.node(); + const bNodeSocket &socket = *sockets_to_check.peek(); + const bNode &node = socket.owner_node(); - if (hash_by_socket_id[in_out_socket.id()].has_value()) { + if (hash_by_socket_id[socket.index_in_tree()].has_value()) { sockets_to_check.pop(); /* Socket is handled already. */ continue; } - if (in_out_socket.is_input()) { + if (socket.is_input()) { /* For input sockets, first compute the hashes of all linked sockets. */ - const InputSocketRef &socket = in_out_socket.as_input(); bool all_origins_computed = true; - for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { - if (!hash_by_socket_id[origin_socket->id()].has_value()) { + for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + if (!hash_by_socket_id[origin_socket->index_in_tree()].has_value()) { sockets_to_check.push(origin_socket); all_origins_computed = false; } @@ -1471,22 +1418,21 @@ class NodeTreeMainUpdater { } /* When the hashes for the linked sockets are ready, combine them into a hash for the input * socket. */ - const uint64_t socket_ptr = (uintptr_t)socket.bsocket(); + const uint64_t socket_ptr = (uintptr_t)&socket; uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32); - for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { - const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->id()]; + for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->index_in_tree()]; socket_hash = noise::hash(socket_hash, origin_socket_hash); } - hash_by_socket_id[socket.id()] = socket_hash; + hash_by_socket_id[socket.index_in_tree()] = socket_hash; sockets_to_check.pop(); } else { /* For output sockets, first compute the hashes of all available input sockets. */ - const OutputSocketRef &socket = in_out_socket.as_output(); bool all_available_inputs_computed = true; - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { - if (!hash_by_socket_id[input_socket->id()].has_value()) { + if (!hash_by_socket_id[input_socket->index_in_tree()].has_value()) { sockets_to_check.push(input_socket); all_available_inputs_computed = false; } @@ -1497,25 +1443,25 @@ class NodeTreeMainUpdater { } /* When all input socket hashes have been computed, combine them into a hash for the output * socket. */ - const uint64_t socket_ptr = (uintptr_t)socket.bsocket(); + const uint64_t socket_ptr = (uintptr_t)&socket; uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32); - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { - const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->id()]; + const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->index_in_tree()]; socket_hash = noise::hash(socket_hash, input_socket_hash); } } /* The Image Texture node has a special case. The behavior of the color output changes * depending on whether the Alpha output is linked. */ - if (node.bnode()->type == SH_NODE_TEX_IMAGE && socket.index() == 0) { - BLI_assert(socket.name() == "Color"); - const OutputSocketRef &alpha_socket = node.output(1); - BLI_assert(alpha_socket.name() == "Alpha"); + if (node.type == SH_NODE_TEX_IMAGE && socket.index() == 0) { + BLI_assert(STREQ(socket.name, "Color")); + const bNodeSocket &alpha_socket = node.output_socket(1); + BLI_assert(STREQ(alpha_socket.name, "Alpha")); if (alpha_socket.is_directly_linked()) { socket_hash = noise::hash(socket_hash); } } - hash_by_socket_id[socket.id()] = socket_hash; + hash_by_socket_id[socket.index_in_tree()] = socket_hash; sockets_to_check.pop(); } } @@ -1523,7 +1469,7 @@ class NodeTreeMainUpdater { /* Create output array. */ Array<uint32_t> hashes(sockets.size()); for (const int i : sockets.index_range()) { - hashes[i] = *hash_by_socket_id[sockets[i]->id()]; + hashes[i] = *hash_by_socket_id[sockets[i]->index_in_tree()]; } return hashes; } @@ -1532,37 +1478,34 @@ class NodeTreeMainUpdater { * Returns true when any of the provided sockets changed its values. A change is detected by * checking the #changed_flag on connected sockets and nodes. */ - bool check_if_socket_outputs_changed_based_on_flags(const NodeTreeRef &tree, - Span<const SocketRef *> sockets) + bool check_if_socket_outputs_changed_based_on_flags(const bNodeTree &tree, + Span<const bNodeSocket *> sockets) { /* Avoid visiting the same socket twice when multiple links point to the same socket. */ - Array<bool> pushed_by_socket_id(tree.sockets().size(), false); - Stack<const SocketRef *> sockets_to_check = sockets; + Array<bool> pushed_by_socket_id(tree.all_sockets().size(), false); + Stack<const bNodeSocket *> sockets_to_check = sockets; - for (const SocketRef *socket : sockets) { - pushed_by_socket_id[socket->id()] = true; + for (const bNodeSocket *socket : sockets) { + pushed_by_socket_id[socket->index_in_tree()] = true; } while (!sockets_to_check.is_empty()) { - const SocketRef &in_out_socket = *sockets_to_check.pop(); - const NodeRef &node = in_out_socket.node(); - const bNode &bnode = *node.bnode(); - const bNodeSocket &bsocket = *in_out_socket.bsocket(); - if (bsocket.runtime->changed_flag != NTREE_CHANGED_NOTHING) { + const bNodeSocket &socket = *sockets_to_check.pop(); + const bNode &node = socket.owner_node(); + if (socket.runtime->changed_flag != NTREE_CHANGED_NOTHING) { return true; } - if (bnode.runtime->changed_flag != NTREE_CHANGED_NOTHING) { - const bool only_unused_internal_link_changed = (bnode.flag & NODE_MUTED) == 0 && - bnode.runtime->changed_flag == + if (node.runtime->changed_flag != NTREE_CHANGED_NOTHING) { + const bool only_unused_internal_link_changed = !node.is_muted() && + node.runtime->changed_flag == NTREE_CHANGED_INTERNAL_LINK; if (!only_unused_internal_link_changed) { return true; } } - if (in_out_socket.is_input()) { - const InputSocketRef &socket = in_out_socket.as_input(); - for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { - bool &pushed = pushed_by_socket_id[origin_socket->id()]; + if (socket.is_input()) { + for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + bool &pushed = pushed_by_socket_id[origin_socket->index_in_tree()]; if (!pushed) { sockets_to_check.push(origin_socket); pushed = true; @@ -1570,10 +1513,9 @@ class NodeTreeMainUpdater { } } else { - const OutputSocketRef &socket = in_out_socket.as_output(); - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { - bool &pushed = pushed_by_socket_id[input_socket->id()]; + bool &pushed = pushed_by_socket_id[input_socket->index_in_tree()]; if (!pushed) { sockets_to_check.push(input_socket); pushed = true; @@ -1582,11 +1524,11 @@ class NodeTreeMainUpdater { } /* The Normal node has a special case, because the value stored in the first output socket * is used as input in the node. */ - if (bnode.type == SH_NODE_NORMAL && socket.index() == 1) { - BLI_assert(socket.name() == "Dot"); - const OutputSocketRef &normal_output = node.output(0); - BLI_assert(normal_output.name() == "Normal"); - bool &pushed = pushed_by_socket_id[normal_output.id()]; + if (node.type == SH_NODE_NORMAL && socket.index() == 1) { + BLI_assert(STREQ(socket.name, "Dot")); + const bNodeSocket &normal_output = node.output_socket(0); + BLI_assert(STREQ(normal_output.name, "Normal")); + bool &pushed = pushed_by_socket_id[normal_output.index_in_tree()]; if (!pushed) { sockets_to_check.push(&normal_output); pushed = true; diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 2a85811e2e8..c90c83074bd 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -1665,7 +1665,7 @@ static void copy_ccg_data(Mesh *mesh_destination, Mesh *mesh_source, int layer_t const int layer_index = CustomData_get_layer_index(data_destination, layer_type); CustomData_free_layer(data_destination, layer_type, num_elements, layer_index); BLI_assert(!CustomData_has_layer(data_destination, layer_type)); - CustomData_add_layer(data_destination, layer_type, CD_CALLOC, nullptr, num_elements); + CustomData_add_layer(data_destination, layer_type, CD_SET_DEFAULT, nullptr, num_elements); BLI_assert(CustomData_has_layer(data_destination, layer_type)); CustomData_copy_layer_type_data(data_source, data_destination, layer_type, 0, 0, num_elements); } diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index 310ec7678bd..08d98775e34 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -115,7 +115,8 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id) { if (GS(id->name) == ID_ME) { Mesh *me = (Mesh *)id; - me->dvert = CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert); + me->dvert = CustomData_add_layer( + &me->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, me->totvert); return me->dvert; } if (GS(id->name) == ID_LT) { diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index a6b0a4d96ee..4c3da5eabc4 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -1835,8 +1835,8 @@ static void sculpt_face_sets_ensure(Mesh *mesh) return; } - int *new_face_sets = static_cast<int *>( - CustomData_add_layer(&mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, nullptr, mesh->totpoly)); + int *new_face_sets = static_cast<int *>(CustomData_add_layer( + &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)); /* Initialize the new Face Set data-layer with a default valid visible ID and set the default * color to render it white. */ @@ -1917,7 +1917,7 @@ void BKE_sculpt_color_layer_create_if_needed(Object *object) return; } - CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, nullptr, orig_me->totvert); + CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_CONSTRUCT, nullptr, orig_me->totvert); CustomDataLayer *layer = orig_me->vdata.layers + CustomData_get_layer_index(&orig_me->vdata, CD_PROP_COLOR); @@ -1958,8 +1958,8 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) int gridarea = gridsize * gridsize; int i, j; - gmask = static_cast<GridPaintMask *>( - CustomData_add_layer(&me->ldata, CD_GRID_PAINT_MASK, CD_CALLOC, nullptr, me->totloop)); + gmask = static_cast<GridPaintMask *>(CustomData_add_layer( + &me->ldata, CD_GRID_PAINT_MASK, CD_SET_DEFAULT, nullptr, me->totloop)); for (i = 0; i < me->totloop; i++) { GridPaintMask *gpm = &gmask[i]; @@ -2002,7 +2002,7 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) /* create vertex paint mask layer if there isn't one already */ if (!paint_mask) { - CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_CALLOC, nullptr, me->totvert); + CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_SET_DEFAULT, nullptr, me->totvert); ret |= SCULPT_MASK_LAYER_CALC_VERT; } @@ -2078,7 +2078,7 @@ void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) else { initialize_new_face_sets = true; int *new_face_sets = static_cast<int *>(CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, nullptr, mesh->totpoly)); + &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)); /* Initialize the new Face Set data-layer with a default valid visible ID and set the default * color to render it white. */ diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index abecb9f8d9d..254cea0bd8b 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -3322,7 +3322,7 @@ static void hair_create_input_mesh(ParticleSimulationData *sim, mesh = *r_mesh; if (!mesh) { *r_mesh = mesh = BKE_mesh_new_nomain(totpoint, totedge, 0, 0, 0); - CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, mesh->totvert); + CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, mesh->totvert); BKE_mesh_update_customdata_pointers(mesh, false); } mvert = mesh->mvert; diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index e2e8dedbd06..1c6274ef35e 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -3230,7 +3230,7 @@ bool *BKE_pbvh_get_vert_hide_for_write(PBVH *pbvh) return pbvh->hide_vert; } pbvh->hide_vert = (bool *)CustomData_add_layer_named( - &pbvh->mesh->vdata, CD_PROP_BOOL, CD_CALLOC, NULL, pbvh->mesh->totvert, ".hide_vert"); + &pbvh->mesh->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, pbvh->mesh->totvert, ".hide_vert"); return pbvh->hide_vert; } diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 426ad797cef..14ca3f58db9 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -64,7 +64,7 @@ static void pointcloud_init_data(ID *id) CustomData_reset(&pointcloud->pdata); CustomData_add_layer_named(&pointcloud->pdata, CD_PROP_FLOAT3, - CD_CALLOC, + CD_SET_DEFAULT, nullptr, pointcloud->totpoint, POINTCLOUD_ATTR_POSITION); @@ -228,13 +228,6 @@ void *BKE_pointcloud_add_default(Main *bmain, const char *name) PointCloud *pointcloud = static_cast<PointCloud *>(BKE_libblock_alloc(bmain, ID_PT, name, 0)); pointcloud_init_data(&pointcloud->id); - - CustomData_add_layer_named(&pointcloud->pdata, - CD_PROP_FLOAT, - CD_CALLOC, - nullptr, - pointcloud->totpoint, - POINTCLOUD_ATTR_RADIUS); pointcloud_random(pointcloud); return pointcloud; @@ -251,7 +244,7 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint) CustomData_add_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, - CD_CALLOC, + CD_SET_DEFAULT, nullptr, pointcloud->totpoint, POINTCLOUD_ATTR_RADIUS); @@ -325,22 +318,6 @@ bool BKE_pointcloud_customdata_required(const PointCloud *UNUSED(pointcloud), co /* Dependency Graph */ -PointCloud *BKE_pointcloud_new_for_eval(const PointCloud *pointcloud_src, int totpoint) -{ - PointCloud *pointcloud_dst = static_cast<PointCloud *>(BKE_id_new_nomain(ID_PT, nullptr)); - CustomData_free(&pointcloud_dst->pdata, pointcloud_dst->totpoint); - - STRNCPY(pointcloud_dst->id.name, pointcloud_src->id.name); - pointcloud_dst->mat = static_cast<Material **>(MEM_dupallocN(pointcloud_src->mat)); - pointcloud_dst->totcol = pointcloud_src->totcol; - - pointcloud_dst->totpoint = totpoint; - CustomData_copy( - &pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, CD_CALLOC, totpoint); - - return pointcloud_dst; -} - PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool reference) { int flags = LIB_ID_COPY_LOCALIZE; diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc index e026a013498..da22ee6fd47 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.cc +++ b/source/blender/blenkernel/intern/subdiv_mesh.cc @@ -186,7 +186,7 @@ static void vertex_interpolation_init(const SubdivMeshContext *ctx, CustomData_copy(&ctx->coarse_mesh->vdata, &vertex_interpolation->vertex_data_storage, CD_MASK_EVERYTHING.vmask, - CD_CALLOC, + CD_SET_DEFAULT, 4); /* Initialize indices. */ vertex_interpolation->vertex_indices[0] = 0; @@ -321,7 +321,7 @@ static void loop_interpolation_init(const SubdivMeshContext *ctx, CustomData_copy(&ctx->coarse_mesh->ldata, &loop_interpolation->loop_data_storage, CD_MASK_EVERYTHING.lmask, - CD_CALLOC, + CD_SET_DEFAULT, 4); /* Initialize indices. */ loop_interpolation->loop_indices[0] = 0; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 1dbfd73b958..52df555090f 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -1246,7 +1246,7 @@ static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type) BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE); origindex = CustomData_add_layer( - &dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, dm->numVertData); + &dm->vertData, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, dm->numVertData); totorig = ccgSubSurf_getNumVerts(ss); totnone = dm->numVertData - totorig; @@ -1285,7 +1285,7 @@ static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type) } origindex = CustomData_add_layer( - &dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, dm->numEdgeData); + &dm->edgeData, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, dm->numEdgeData); totedge = ccgSubSurf_getNumEdges(ss); totorig = totedge * (edgeSize - 1); @@ -1328,7 +1328,7 @@ static void *ccgDM_get_poly_data_layer(DerivedMesh *dm, int type) } origindex = CustomData_add_layer( - &dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, dm->numPolyData); + &dm->polyData, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, dm->numPolyData); totface = ccgSubSurf_getNumFaces(ss); diff --git a/source/blender/blenlib/BLI_multi_value_map.hh b/source/blender/blenlib/BLI_multi_value_map.hh index 4b6300c09aa..1fc5a797574 100644 --- a/source/blender/blenlib/BLI_multi_value_map.hh +++ b/source/blender/blenlib/BLI_multi_value_map.hh @@ -137,6 +137,11 @@ template<typename Key, typename Value> class MultiValueMap { { return map_.values(); } + + void clear() + { + map_.clear(); + } }; } // namespace blender diff --git a/source/blender/blenlib/intern/BLI_memarena.c b/source/blender/blenlib/intern/BLI_memarena.c index 3b73a81012d..ada2d27f9b2 100644 --- a/source/blender/blenlib/intern/BLI_memarena.c +++ b/source/blender/blenlib/intern/BLI_memarena.c @@ -158,6 +158,7 @@ void *BLI_memarena_calloc(MemArena *ma, size_t size) BLI_assert(ma->use_calloc == false); ptr = BLI_memarena_alloc(ma, size); + BLI_assert(ptr != NULL); memset(ptr, 0, size); return ptr; diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c index e90a0ee02db..7e2c5e8f1dd 100644 --- a/source/blender/blenlib/intern/winstuff.c +++ b/source/blender/blenlib/intern/winstuff.c @@ -63,23 +63,17 @@ bool BLI_windows_register_blend_extension(const bool background) char buffer[256]; char BlPath[MAX_PATH]; - char InstallDir[FILE_MAXDIR]; - char SysDir[FILE_MAXDIR]; - const char *ThumbHandlerDLL; - char RegCmd[MAX_PATH * 2]; char MBox[256]; - char *blender_app; -# ifndef _WIN64 - BOOL IsWOW64; -# endif printf("Registering file extension..."); GetModuleFileName(0, BlPath, MAX_PATH); /* Replace the actual app name with the wrapper. */ - blender_app = strstr(BlPath, "blender.exe"); - if (blender_app != NULL) { - strcpy(blender_app, "blender-launcher.exe"); + { + char *blender_app = strstr(BlPath, "blender.exe"); + if (blender_app != NULL) { + strcpy(blender_app, "blender-launcher.exe"); + } } /* root is HKLM by default */ @@ -157,12 +151,17 @@ bool BLI_windows_register_blend_extension(const bool background) } # ifdef WITH_BLENDER_THUMBNAILER - BLI_windows_get_executable_dir(InstallDir); - GetSystemDirectory(SysDir, FILE_MAXDIR); - ThumbHandlerDLL = "BlendThumb.dll"; - snprintf( - RegCmd, MAX_PATH * 2, "%s\\regsvr32 /s \"%s\\%s\"", SysDir, InstallDir, ThumbHandlerDLL); - system(RegCmd); + { + char RegCmd[MAX_PATH * 2]; + char InstallDir[FILE_MAXDIR]; + char SysDir[FILE_MAXDIR]; + BLI_windows_get_executable_dir(InstallDir); + GetSystemDirectory(SysDir, FILE_MAXDIR); + const char *ThumbHandlerDLL = "BlendThumb.dll"; + snprintf( + RegCmd, MAX_PATH * 2, "%s\\regsvr32 /s \"%s\\%s\"", SysDir, InstallDir, ThumbHandlerDLL); + system(RegCmd); + } # endif RegCloseKey(root); diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index b98f8996a2c..4d604fc7eec 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -1697,6 +1697,27 @@ static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTre } } +static void versioning_replace_legacy_mix_rgb_node(bNodeTree *ntree) +{ + version_node_input_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Fac", "Factor_Float"); + version_node_input_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color1", "A_Color"); + version_node_input_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color2", "B_Color"); + version_node_output_socket_name(ntree, SH_NODE_MIX_RGB_LEGACY, "Color", "Result_Color"); + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == SH_NODE_MIX_RGB_LEGACY) { + strcpy(node->idname, "ShaderNodeMix"); + node->type = SH_NODE_MIX; + NodeShaderMix *data = (NodeShaderMix *)MEM_callocN(sizeof(NodeShaderMix), __func__); + data->blend_type = node->custom1; + data->clamp_result = node->custom2; + data->clamp_factor = 1; + data->data_type = SOCK_RGBA; + data->factor_mode = NODE_MIX_MODE_UNIFORM; + node->storage = data; + } + } +} + static void version_fix_image_format_copy(Main *bmain, ImageFormatData *format) { /* Fix bug where curves in image format were not properly copied to file output @@ -3332,5 +3353,13 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /* Convert mix rgb node to new mix node and add storage. */ + { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + versioning_replace_legacy_mix_rgb_node(ntree); + } + FOREACH_NODETREE_END; + } } } diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 75cc333e4b5..20659daabd6 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -291,8 +291,8 @@ static void customdata_version_242(Mesh *me) MEM_freeN(me->mcol); } - me->mcol = CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface); - me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface); + me->mcol = CustomData_add_layer(&me->fdata, CD_MCOL, CD_SET_DEFAULT, NULL, me->totface); + me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE, CD_SET_DEFAULT, NULL, me->totface); mtf = me->mtface; mcol = me->mcol; diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 0ee5545527b..757d006b04d 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -513,23 +513,23 @@ void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst, const Mesh *me_src = me_src_array[i]; if (i == 0) { CustomData_copy_mesh_to_bmesh( - &me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); + &me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); CustomData_copy_mesh_to_bmesh( - &me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); + &me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); CustomData_copy_mesh_to_bmesh( - &me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); + &me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); CustomData_copy_mesh_to_bmesh( - &me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + &me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); } else { CustomData_merge_mesh_to_bmesh( - &me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); + &me_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); CustomData_merge_mesh_to_bmesh( - &me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); + &me_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); CustomData_merge_mesh_to_bmesh( - &me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); + &me_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); CustomData_merge_mesh_to_bmesh( - &me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + &me_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); } cd_flag |= me_src->cd_flag; @@ -558,10 +558,10 @@ void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTem allocsize = &bm_mesh_allocsize_default; } - CustomData_copy(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); - CustomData_copy(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); - CustomData_copy(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); - CustomData_copy(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); + CustomData_copy(&bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0); + CustomData_copy(&bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0); + CustomData_copy(&bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0); + CustomData_copy(&bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0); CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE); @@ -596,7 +596,7 @@ void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst, for (int l = 0; l < src->totlayer; l++) { CustomData_add_layer_named( - dst, src->layers[l].type, CD_CALLOC, NULL, 0, src->layers[l].name); + dst, src->layers[l].type, CD_SET_DEFAULT, NULL, 0, src->layers[l].name); } CustomData_bmesh_init_pool(dst, size, htypes[i]); } diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index 0c3db31dd1f..b7028dee5e1 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -846,7 +846,7 @@ void BM_data_layer_add(BMesh *bm, CustomData *data, int type) /* the pool is now owned by olddata and must not be shared */ data->pool = NULL; - CustomData_add_layer(data, type, CD_DEFAULT, NULL, 0); + CustomData_add_layer(data, type, CD_SET_DEFAULT, NULL, 0); update_data_blocks(bm, &olddata, data); if (olddata.layers) { @@ -864,7 +864,7 @@ void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char * /* the pool is now owned by olddata and must not be shared */ data->pool = NULL; - CustomData_add_layer_named(data, type, CD_DEFAULT, NULL, 0, name); + CustomData_add_layer_named(data, type, CD_SET_DEFAULT, NULL, 0, name); update_data_blocks(bm, &olddata, data); if (olddata.layers) { diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index f509eef2141..47ad5080451 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -217,10 +217,10 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar if (!me || !me->totvert) { if (me && is_new) { /* No verts? still copy custom-data layout. */ - CustomData_copy_mesh_to_bmesh(&me->vdata, &bm->vdata, mask.vmask, CD_DEFAULT, 0); - CustomData_copy_mesh_to_bmesh(&me->edata, &bm->edata, mask.emask, CD_DEFAULT, 0); - CustomData_copy_mesh_to_bmesh(&me->ldata, &bm->ldata, mask.lmask, CD_DEFAULT, 0); - CustomData_copy_mesh_to_bmesh(&me->pdata, &bm->pdata, mask.pmask, CD_DEFAULT, 0); + CustomData_copy_mesh_to_bmesh(&me->vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0); + CustomData_copy_mesh_to_bmesh(&me->edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0); + CustomData_copy_mesh_to_bmesh(&me->ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0); + CustomData_copy_mesh_to_bmesh(&me->pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0); CustomData_bmesh_init_pool(&bm->vdata, me->totvert, BM_VERT); CustomData_bmesh_init_pool(&bm->edata, me->totedge, BM_EDGE); @@ -236,16 +236,16 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar } if (is_new) { - CustomData_copy_mesh_to_bmesh(&me->vdata, &bm->vdata, mask.vmask, CD_CALLOC, 0); - CustomData_copy_mesh_to_bmesh(&me->edata, &bm->edata, mask.emask, CD_CALLOC, 0); - CustomData_copy_mesh_to_bmesh(&me->ldata, &bm->ldata, mask.lmask, CD_CALLOC, 0); - CustomData_copy_mesh_to_bmesh(&me->pdata, &bm->pdata, mask.pmask, CD_CALLOC, 0); + CustomData_copy_mesh_to_bmesh(&me->vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0); + CustomData_copy_mesh_to_bmesh(&me->edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0); + CustomData_copy_mesh_to_bmesh(&me->ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0); + CustomData_copy_mesh_to_bmesh(&me->pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0); } else { - CustomData_bmesh_merge(&me->vdata, &bm->vdata, mask.vmask, CD_CALLOC, bm, BM_VERT); - CustomData_bmesh_merge(&me->edata, &bm->edata, mask.emask, CD_CALLOC, bm, BM_EDGE); - CustomData_bmesh_merge(&me->ldata, &bm->ldata, mask.lmask, CD_CALLOC, bm, BM_LOOP); - CustomData_bmesh_merge(&me->pdata, &bm->pdata, mask.pmask, CD_CALLOC, bm, BM_FACE); + CustomData_bmesh_merge(&me->vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT); + CustomData_bmesh_merge(&me->edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE); + CustomData_bmesh_merge(&me->ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP); + CustomData_bmesh_merge(&me->pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE); } /* -------------------------------------------------------------------- */ @@ -1018,10 +1018,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh { CustomData_MeshMasks mask = CD_MASK_MESH; CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); - CustomData_copy_mesh_to_bmesh(&bm->vdata, &me->vdata, mask.vmask, CD_CALLOC, me->totvert); - CustomData_copy_mesh_to_bmesh(&bm->edata, &me->edata, mask.emask, CD_CALLOC, me->totedge); - CustomData_copy_mesh_to_bmesh(&bm->ldata, &me->ldata, mask.lmask, CD_CALLOC, me->totloop); - CustomData_copy_mesh_to_bmesh(&bm->pdata, &me->pdata, mask.pmask, CD_CALLOC, me->totpoly); + CustomData_copy_mesh_to_bmesh(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); + CustomData_copy_mesh_to_bmesh(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); + CustomData_copy_mesh_to_bmesh(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); + CustomData_copy_mesh_to_bmesh(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); } MVert *mvert = bm->totvert ? (MVert *)MEM_callocN(sizeof(MVert) * bm->totvert, "bm_to_me.vert") : @@ -1286,10 +1286,10 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * me->totloop = bm->totloop; me->totpoly = bm->totface; - CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, bm->totvert); - CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, nullptr, bm->totedge); - CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, nullptr, bm->totloop); - CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, nullptr, bm->totface); + CustomData_add_layer(&me->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, bm->totvert); + CustomData_add_layer(&me->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, bm->totedge); + CustomData_add_layer(&me->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, bm->totloop); + CustomData_add_layer(&me->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, bm->totface); /* Don't process shape-keys, we only feed them through the modifier stack as needed, * e.g. for applying modifiers or the like. */ @@ -1298,10 +1298,10 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * CustomData_MeshMasks_update(&mask, cd_mask_extra); } mask.vmask &= ~CD_MASK_SHAPEKEY; - CustomData_merge(&bm->vdata, &me->vdata, mask.vmask, CD_CALLOC, me->totvert); - CustomData_merge(&bm->edata, &me->edata, mask.emask, CD_CALLOC, me->totedge); - CustomData_merge(&bm->ldata, &me->ldata, mask.lmask, CD_CALLOC, me->totloop); - CustomData_merge(&bm->pdata, &me->pdata, mask.pmask, CD_CALLOC, me->totpoly); + CustomData_merge(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); + CustomData_merge(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); + CustomData_merge(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); + CustomData_merge(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); BKE_mesh_update_customdata_pointers(me, false); diff --git a/source/blender/compositor/realtime_compositor/COM_evaluator.hh b/source/blender/compositor/realtime_compositor/COM_evaluator.hh index fd6feb0948b..258a2a038c4 100644 --- a/source/blender/compositor/realtime_compositor/COM_evaluator.hh +++ b/source/blender/compositor/realtime_compositor/COM_evaluator.hh @@ -104,9 +104,6 @@ class Evaluator { Context &context_; /* A reference to the compositor node tree. */ bNodeTree &node_tree_; - /* The derived and reference node trees representing the compositor node tree. Those are - * initialized when the node tree is compiled and freed when the evaluator resets. */ - NodeTreeRefMap node_tree_reference_map_; std::unique_ptr<DerivedNodeTree> derived_node_tree_; /* The compiled operations stream. This contains ordered pointers to the operations that were * compiled. This is initialized when the node tree is compiled and freed when the evaluator diff --git a/source/blender/compositor/realtime_compositor/COM_utilities.hh b/source/blender/compositor/realtime_compositor/COM_utilities.hh index 4bd61aab5cb..614384bd573 100644 --- a/source/blender/compositor/realtime_compositor/COM_utilities.hh +++ b/source/blender/compositor/realtime_compositor/COM_utilities.hh @@ -27,7 +27,7 @@ DSocket get_input_origin_socket(DInputSocket input); DOutputSocket get_output_linked_to_input(DInputSocket input); /* Get the result type that corresponds to the type of the given socket. */ -ResultType get_node_socket_result_type(const SocketRef *socket); +ResultType get_node_socket_result_type(const bNodeSocket *socket); /* Returns true if any of the nodes linked to the given output satisfies the given condition, and * false otherwise. */ @@ -46,7 +46,7 @@ bool is_shader_node(DNode node); bool is_node_supported(DNode node); /* Get the input descriptor of the given input socket. */ -InputDescriptor input_descriptor_from_input_socket(const InputSocketRef *socket); +InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket); /* Dispatch the given compute shader in a 2D compute space such that the number of threads in both * dimensions is as small as possible but at least covers the entirety of threads_range assuming diff --git a/source/blender/compositor/realtime_compositor/intern/compile_state.cc b/source/blender/compositor/realtime_compositor/intern/compile_state.cc index 5b485224111..97c1e47e86e 100644 --- a/source/blender/compositor/realtime_compositor/intern/compile_state.cc +++ b/source/blender/compositor/realtime_compositor/intern/compile_state.cc @@ -46,7 +46,7 @@ Result &CompileState::get_result_from_output_socket(DOutputSocket output) * reference to the result from that operation using the output identifier. */ if (node_operations_.contains(output.node())) { NodeOperation *operation = node_operations_.lookup(output.node()); - return operation->get_result(output->identifier()); + return operation->get_result(output->identifier); } /* Otherwise, the output belongs to a node that was compiled into a shader operation, so @@ -113,17 +113,17 @@ Domain CompileState::compute_shader_node_domain(DNode node) /* Go over the inputs and find the domain of the non single value input with the highest domain * priority. */ - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked, so skip * it. */ - const DOutputSocket output = get_output_linked_to_input(input); + const DOutputSocket output = get_output_linked_to_input(dinput); if (!output) { continue; } - const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input_ref); + const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input); /* If the output belongs to a node that is part of the shader compile unit, then the domain of * the input is the domain of the compile unit itself. */ diff --git a/source/blender/compositor/realtime_compositor/intern/evaluator.cc b/source/blender/compositor/realtime_compositor/intern/evaluator.cc index d358389f2e9..48457bec199 100644 --- a/source/blender/compositor/realtime_compositor/intern/evaluator.cc +++ b/source/blender/compositor/realtime_compositor/intern/evaluator.cc @@ -45,7 +45,6 @@ void Evaluator::reset() { operations_stream_.clear(); derived_node_tree_.reset(); - node_tree_reference_map_.clear(); is_compiled_ = false; } @@ -67,7 +66,7 @@ bool Evaluator::validate_node_tree() void Evaluator::compile_and_evaluate() { - derived_node_tree_ = std::make_unique<DerivedNodeTree>(node_tree_, node_tree_reference_map_); + derived_node_tree_ = std::make_unique<DerivedNodeTree>(node_tree_); if (!validate_node_tree()) { return; @@ -93,7 +92,7 @@ void Evaluator::compile_and_evaluate() void Evaluator::compile_and_evaluate_node(DNode node, CompileState &compile_state) { - NodeOperation *operation = node->typeinfo()->get_compositor_operation(context_, node); + NodeOperation *operation = node->typeinfo->get_compositor_operation(context_, node); compile_state.map_node_to_node_operation(node, operation); @@ -113,16 +112,16 @@ void Evaluator::map_node_operation_inputs_to_their_results(DNode node, NodeOperation *operation, CompileState &compile_state) { - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; - DSocket origin = get_input_origin_socket(input); + DSocket dorigin = get_input_origin_socket(dinput); /* The origin socket is an output, which means the input is linked. So map the input to the * result we get from the output. */ - if (origin->is_output()) { - Result &result = compile_state.get_result_from_output_socket(DOutputSocket(origin)); - operation->map_input_to_result(input->identifier(), &result); + if (dorigin->is_output()) { + Result &result = compile_state.get_result_from_output_socket(DOutputSocket(dorigin)); + operation->map_input_to_result(input->identifier, &result); continue; } @@ -130,8 +129,8 @@ void Evaluator::map_node_operation_inputs_to_their_results(DNode node, * origin is the input socket itself or the input is connected to an unlinked input of a group * input node and the origin is the input of the group input node. So map the input to the * result of a newly created Input Single Value Operation. */ - auto *input_operation = new InputSingleValueOperation(context_, DInputSocket(origin)); - operation->map_input_to_result(input->identifier(), &input_operation->get_result()); + auto *input_operation = new InputSingleValueOperation(context_, DInputSocket(dorigin)); + operation->map_input_to_result(input->identifier, &input_operation->get_result()); operations_stream_.append(std::unique_ptr<InputSingleValueOperation>(input_operation)); diff --git a/source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc b/source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc index 0bdd40e3636..b3cc86b5f79 100644 --- a/source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/input_single_value_operation.cc @@ -14,7 +14,7 @@ const StringRef InputSingleValueOperation::output_identifier_ = StringRef("Outpu InputSingleValueOperation::InputSingleValueOperation(Context &context, DInputSocket input_socket) : Operation(context), input_socket_(input_socket) { - const ResultType result_type = get_node_socket_result_type(input_socket_.socket_ref()); + const ResultType result_type = get_node_socket_result_type(input_socket_.bsocket()); Result result = Result(result_type, texture_pool()); /* The result of an input single value operation is guaranteed to have a single user. */ @@ -29,17 +29,19 @@ void InputSingleValueOperation::execute() Result &result = get_result(); result.allocate_single_value(); + const bNodeSocket *bsocket = input_socket_.bsocket(); + /* Set the value of the result to the default value of the input socket. */ switch (result.type()) { case ResultType::Float: - result.set_float_value(input_socket_->default_value<bNodeSocketValueFloat>()->value); + result.set_float_value(bsocket->default_value_typed<bNodeSocketValueFloat>()->value); break; case ResultType::Vector: result.set_vector_value( - float3(input_socket_->default_value<bNodeSocketValueVector>()->value)); + float3(bsocket->default_value_typed<bNodeSocketValueVector>()->value)); break; case ResultType::Color: - result.set_color_value(float4(input_socket_->default_value<bNodeSocketValueRGBA>()->value)); + result.set_color_value(float4(bsocket->default_value_typed<bNodeSocketValueRGBA>()->value)); break; } } diff --git a/source/blender/compositor/realtime_compositor/intern/node_operation.cc b/source/blender/compositor/realtime_compositor/intern/node_operation.cc index f02d0906447..1c20c967ddb 100644 --- a/source/blender/compositor/realtime_compositor/intern/node_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/node_operation.cc @@ -25,27 +25,27 @@ using namespace nodes::derived_node_tree_types; NodeOperation::NodeOperation(Context &context, DNode node) : Operation(context), node_(node) { - for (const OutputSocketRef *output : node->outputs()) { + for (const bNodeSocket *output : node->output_sockets()) { const ResultType result_type = get_node_socket_result_type(output); const Result result = Result(result_type, texture_pool()); - populate_result(output->identifier(), result); + populate_result(output->identifier, result); } - for (const InputSocketRef *input : node->inputs()) { + for (const bNodeSocket *input : node->input_sockets()) { const InputDescriptor input_descriptor = input_descriptor_from_input_socket(input); - declare_input_descriptor(input->identifier(), input_descriptor); + declare_input_descriptor(input->identifier, input_descriptor); } } void NodeOperation::compute_results_reference_counts(const Schedule &schedule) { - for (const OutputSocketRef *output_ref : node()->outputs()) { - const DOutputSocket output{node().context(), output_ref}; + for (const bNodeSocket *output : this->node()->output_sockets()) { + const DOutputSocket doutput{node().context(), output}; const int reference_count = number_of_inputs_linked_to_output_conditioned( - output, [&](DInputSocket input) { return schedule.contains(input.node()); }); + doutput, [&](DInputSocket input) { return schedule.contains(input.node()); }); - get_result(output->identifier()).set_initial_reference_count(reference_count); + get_result(doutput->identifier).set_initial_reference_count(reference_count); } } @@ -56,7 +56,7 @@ const DNode &NodeOperation::node() const const bNode &NodeOperation::bnode() const { - return *node_->bnode(); + return *node_; } bool NodeOperation::should_compute_output(StringRef identifier) diff --git a/source/blender/compositor/realtime_compositor/intern/scheduler.cc b/source/blender/compositor/realtime_compositor/intern/scheduler.cc index ce8b9330541..ac5cc55a73f 100644 --- a/source/blender/compositor/realtime_compositor/intern/scheduler.cc +++ b/source/blender/compositor/realtime_compositor/intern/scheduler.cc @@ -8,6 +8,8 @@ #include "NOD_derived_node_tree.hh" +#include "BKE_node_runtime.hh" + #include "COM_scheduler.hh" #include "COM_utilities.hh" @@ -21,22 +23,22 @@ using namespace nodes::derived_node_tree_types; * node will be returned. */ static DNode compute_output_node(DerivedNodeTree &tree) { - const NodeTreeRef &root_tree = tree.root_context().tree(); + const bNodeTree &root_tree = tree.root_context().btree(); - for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeComposite")) { - if (node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *node : root_tree.nodes_by_type("CompositorNodeComposite")) { + if (node->flag & NODE_DO_OUTPUT) { return DNode(&tree.root_context(), node); } } - for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeViewer")) { - if (node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *node : root_tree.nodes_by_type("CompositorNodeViewer")) { + if (node->flag & NODE_DO_OUTPUT) { return DNode(&tree.root_context(), node); } } - for (const NodeRef *node : root_tree.nodes_by_type("CompositorNodeSplitViewer")) { - if (node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *node : root_tree.nodes_by_type("CompositorNodeSplitViewer")) { + if (node->flag & NODE_DO_OUTPUT) { return DNode(&tree.root_context(), node); } } @@ -120,25 +122,25 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node) /* Go over the node dependencies connected to the inputs of the node and push them to the node * stack if they were not computed already. */ Set<DNode> pushed_nodes; - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked and * has no dependency node. */ - const DOutputSocket output = get_output_linked_to_input(input); - if (!output) { + const DOutputSocket doutput = get_output_linked_to_input(dinput); + if (!doutput) { continue; } /* The node dependency was already computed or pushed before, so skip it. */ - if (needed_buffers.contains(output.node()) || pushed_nodes.contains(output.node())) { + if (needed_buffers.contains(doutput.node()) || pushed_nodes.contains(doutput.node())) { continue; } /* The output node needs to be computed, push the node dependency to the node stack and * indicate that it was pushed. */ - node_stack.push(output.node()); - pushed_nodes.add_new(output.node()); + node_stack.push(doutput.node()); + pushed_nodes.add_new(doutput.node()); } /* If any of the node dependencies were pushed, that means that not all of them were computed @@ -154,26 +156,26 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node) * buffers needed to compute the most demanding of the node dependencies. */ int number_of_input_buffers = 0; int buffers_needed_by_dependencies = 0; - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked. * Unlinked inputs do not take a buffer, so skip those inputs. */ - const DOutputSocket output = get_output_linked_to_input(input); - if (!output) { + const DOutputSocket doutput = get_output_linked_to_input(dinput); + if (!doutput) { continue; } /* Since this input is linked, if the link is not between two shader nodes, it means that the * node takes a buffer through this input and so we increment the number of input buffers. */ - if (!is_shader_node(node) || !is_shader_node(output.node())) { + if (!is_shader_node(node) || !is_shader_node(doutput.node())) { number_of_input_buffers++; } /* If the number of buffers needed by the node dependency is more than the total number of * buffers needed by the dependencies, then update the latter to be the former. This is * computing the "d" in the aforementioned equation "max(n + m, d)". */ - const int buffers_needed_by_dependency = needed_buffers.lookup(output.node()); + const int buffers_needed_by_dependency = needed_buffers.lookup(doutput.node()); if (buffers_needed_by_dependency > buffers_needed_by_dependencies) { buffers_needed_by_dependencies = buffers_needed_by_dependency; } @@ -181,17 +183,18 @@ static NeededBuffers compute_number_of_needed_buffers(DNode output_node) /* Compute the number of buffers that will be computed/output by this node. */ int number_of_output_buffers = 0; - for (const OutputSocketRef *output_ref : node->outputs()) { - const DOutputSocket output{node.context(), output_ref}; + for (const bNodeSocket *output : node->output_sockets()) { + const DOutputSocket doutput{node.context(), output}; /* The output is not linked, it outputs no buffer. */ - if (output->logically_linked_sockets().is_empty()) { + if (!output->is_logically_linked()) { continue; } /* If any of the links is not between two shader nodes, it means that the node outputs * a buffer through this output and so we increment the number of output buffers. */ - if (!is_output_linked_to_node_conditioned(output, is_shader_node) || !is_shader_node(node)) { + if (!is_output_linked_to_node_conditioned(doutput, is_shader_node) || + !is_shader_node(node)) { number_of_output_buffers++; } } @@ -255,24 +258,24 @@ Schedule compute_schedule(DerivedNodeTree &tree) * want the node with the highest number of needed buffers to be schedule first, but since * those are pushed to the traversal stack, we need to push them in reverse order. */ Vector<DNode> sorted_dependency_nodes; - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked and * has no dependency node, so skip it. */ - const DOutputSocket output = get_output_linked_to_input(input); - if (!output) { + const DOutputSocket doutput = get_output_linked_to_input(dinput); + if (!doutput) { continue; } /* The dependency node was added before, so skip it. The number of dependency nodes is very * small, typically less than 3, so a linear search is okay. */ - if (sorted_dependency_nodes.contains(output.node())) { + if (sorted_dependency_nodes.contains(doutput.node())) { continue; } /* The dependency node was already schedule, so skip it. */ - if (schedule.contains(output.node())) { + if (schedule.contains(doutput.node())) { continue; } @@ -280,7 +283,7 @@ Schedule compute_schedule(DerivedNodeTree &tree) * typically less than 3, so insertion sort is okay. */ int insertion_position = 0; for (int i = 0; i < sorted_dependency_nodes.size(); i++) { - if (needed_buffers.lookup(output.node()) > + if (needed_buffers.lookup(doutput.node()) > needed_buffers.lookup(sorted_dependency_nodes[i])) { insertion_position++; } @@ -288,7 +291,7 @@ Schedule compute_schedule(DerivedNodeTree &tree) break; } } - sorted_dependency_nodes.insert(insertion_position, output.node()); + sorted_dependency_nodes.insert(insertion_position, doutput.node()); } /* Push the sorted dependency nodes to the node stack in order. */ diff --git a/source/blender/compositor/realtime_compositor/intern/shader_node.cc b/source/blender/compositor/realtime_compositor/intern/shader_node.cc index f23485cee96..9310de3cbf4 100644 --- a/source/blender/compositor/realtime_compositor/intern/shader_node.cc +++ b/source/blender/compositor/realtime_compositor/intern/shader_node.cc @@ -59,7 +59,7 @@ const DNode &ShaderNode::node() const bNode &ShaderNode::bnode() const { - return *node_->bnode(); + return const_cast<bNode &>(*node_); } static eGPUType gpu_type_from_socket_type(eNodeSocketDatatype type) @@ -77,17 +77,17 @@ static eGPUType gpu_type_from_socket_type(eNodeSocketDatatype type) } } -static void gpu_stack_vector_from_socket(float *vector, const SocketRef *socket) +static void gpu_stack_vector_from_socket(float *vector, const bNodeSocket *socket) { - switch (socket->bsocket()->type) { + switch (socket->type) { case SOCK_FLOAT: - vector[0] = socket->default_value<bNodeSocketValueFloat>()->value; + vector[0] = socket->default_value_typed<bNodeSocketValueFloat>()->value; return; case SOCK_VECTOR: - copy_v3_v3(vector, socket->default_value<bNodeSocketValueVector>()->value); + copy_v3_v3(vector, socket->default_value_typed<bNodeSocketValueVector>()->value); return; case SOCK_RGBA: - copy_v4_v4(vector, socket->default_value<bNodeSocketValueRGBA>()->value); + copy_v4_v4(vector, socket->default_value_typed<bNodeSocketValueRGBA>()->value); return; default: BLI_assert_unreachable(); @@ -101,8 +101,8 @@ static void populate_gpu_node_stack(DSocket socket, GPUNodeStack &stack) /* This will be initialized later by the GPU material compiler or the compile method. */ stack.link = nullptr; - stack.sockettype = socket->bsocket()->type; - stack.type = gpu_type_from_socket_type((eNodeSocketDatatype)socket->bsocket()->type); + stack.sockettype = socket->type; + stack.type = gpu_type_from_socket_type((eNodeSocketDatatype)socket->type); if (socket->is_input()) { const DInputSocket input(socket); @@ -117,10 +117,10 @@ static void populate_gpu_node_stack(DSocket socket, GPUNodeStack &stack) * unlinked input or an unlinked input of a group input node that the socket is linked to, * otherwise, get the value from the socket itself. */ if (origin->is_input()) { - gpu_stack_vector_from_socket(stack.vec, origin.socket_ref()); + gpu_stack_vector_from_socket(stack.vec, origin.bsocket()); } else { - gpu_stack_vector_from_socket(stack.vec, socket.socket_ref()); + gpu_stack_vector_from_socket(stack.vec, socket.bsocket()); } } else { @@ -132,10 +132,11 @@ void ShaderNode::populate_inputs() { /* Reserve a stack for each input in addition to an extra stack at the end to mark the end of the * array, as this is what the GPU module functions expect. */ - inputs_.resize(node_->inputs().size() + 1); + const int num_input_sockets = node_->input_sockets().size(); + inputs_.resize(num_input_sockets + 1); inputs_.last().end = true; - for (int i = 0; i < node_->inputs().size(); i++) { + for (int i = 0; i < num_input_sockets; i++) { populate_gpu_node_stack(node_.input(i), inputs_[i]); } } @@ -144,10 +145,11 @@ void ShaderNode::populate_outputs() { /* Reserve a stack for each output in addition to an extra stack at the end to mark the end of * the array, as this is what the GPU module functions expect. */ - outputs_.resize(node_->outputs().size() + 1); + const int num_output_sockets = node_->output_sockets().size(); + outputs_.resize(num_output_sockets + 1); outputs_.last().end = true; - for (int i = 0; i < node_->outputs().size(); i++) { + for (int i = 0; i < num_output_sockets; i++) { populate_gpu_node_stack(node_.output(i), outputs_[i]); } } diff --git a/source/blender/compositor/realtime_compositor/intern/shader_operation.cc b/source/blender/compositor/realtime_compositor/intern/shader_operation.cc index 5749d8c5f2e..8e52baf63ec 100644 --- a/source/blender/compositor/realtime_compositor/intern/shader_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/shader_operation.cc @@ -128,7 +128,7 @@ void ShaderOperation::construct_material(void *thunk, GPUMaterial *material) { ShaderOperation *operation = static_cast<ShaderOperation *>(thunk); for (DNode node : operation->compile_unit_) { - ShaderNode *shader_node = node->typeinfo()->get_compositor_shader_node(node); + ShaderNode *shader_node = node->typeinfo->get_compositor_shader_node(node); operation->shader_nodes_.add_new(node, std::unique_ptr<ShaderNode>(shader_node)); operation->link_node_inputs(node, material); @@ -141,27 +141,27 @@ void ShaderOperation::construct_material(void *thunk, GPUMaterial *material) void ShaderOperation::link_node_inputs(DNode node, GPUMaterial *material) { - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; /* Get the output linked to the input. If it is null, that means the input is unlinked. * Unlinked inputs are linked by the node compile method, so skip this here. */ - const DOutputSocket output = get_output_linked_to_input(input); - if (!output) { + const DOutputSocket doutput = get_output_linked_to_input(dinput); + if (!doutput) { continue; } /* If the origin node is part of the shader operation, then the link is internal to the GPU * material graph and is linked appropriately. */ - if (compile_unit_.contains(output.node())) { - link_node_input_internal(input, output); + if (compile_unit_.contains(doutput.node())) { + link_node_input_internal(dinput, doutput); continue; } /* Otherwise, the origin node is not part of the shader operation, then the link is external to * the GPU material graph and an input to the shader operation must be declared and linked to * the node input. */ - link_node_input_external(input, output, material); + link_node_input_external(dinput, doutput, material); } } @@ -169,10 +169,10 @@ void ShaderOperation::link_node_input_internal(DInputSocket input_socket, DOutputSocket output_socket) { ShaderNode &output_node = *shader_nodes_.lookup(output_socket.node()); - GPUNodeStack &output_stack = output_node.get_output(output_socket->identifier()); + GPUNodeStack &output_stack = output_node.get_output(output_socket->identifier); ShaderNode &input_node = *shader_nodes_.lookup(input_socket.node()); - GPUNodeStack &input_stack = input_node.get_input(input_socket->identifier()); + GPUNodeStack &input_stack = input_node.get_input(input_socket->identifier); input_stack.link = output_stack.link; } @@ -183,7 +183,7 @@ void ShaderOperation::link_node_input_external(DInputSocket input_socket, { ShaderNode &node = *shader_nodes_.lookup(input_socket.node()); - GPUNodeStack &stack = node.get_input(input_socket->identifier()); + GPUNodeStack &stack = node.get_input(input_socket->identifier); /* An input was already declared for that same output socket, so no need to declare it again. */ if (!output_to_material_attribute_map_.contains(output_socket)) { @@ -219,8 +219,8 @@ void ShaderOperation::declare_operation_input(DInputSocket input_socket, /* Declare the input descriptor for this input and prefer to declare its type to be the same as * the type of the output socket because doing type conversion in the shader is much cheaper. */ - InputDescriptor input_descriptor = input_descriptor_from_input_socket(input_socket.socket_ref()); - input_descriptor.type = get_node_socket_result_type(output_socket.socket_ref()); + InputDescriptor input_descriptor = input_descriptor_from_input_socket(input_socket.bsocket()); + input_descriptor.type = get_node_socket_result_type(output_socket.bsocket()); declare_input_descriptor(input_identifier, input_descriptor); /* Add a new GPU attribute representing an input to the GPU material. Instead of using the @@ -242,16 +242,16 @@ void ShaderOperation::declare_operation_input(DInputSocket input_socket, void ShaderOperation::populate_results_for_node(DNode node, GPUMaterial *material) { - for (const OutputSocketRef *output_ref : node->outputs()) { - const DOutputSocket output{node.context(), output_ref}; + for (const bNodeSocket *output : node->output_sockets()) { + const DOutputSocket doutput{node.context(), output}; /* If any of the nodes linked to the output are not part of the shader operation, then an * output result needs to be populated for it. */ const bool need_to_populate_result = is_output_linked_to_node_conditioned( - output, [&](DNode node) { return !compile_unit_.contains(node); }); + doutput, [&](DNode node) { return !compile_unit_.contains(node); }); if (need_to_populate_result) { - populate_operation_result(output, material); + populate_operation_result(doutput, material); } } } @@ -276,7 +276,7 @@ void ShaderOperation::populate_operation_result(DOutputSocket output_socket, GPU const unsigned int output_id = output_sockets_to_output_identifiers_map_.size(); std::string output_identifier = "output" + std::to_string(output_id); - const ResultType result_type = get_node_socket_result_type(output_socket.socket_ref()); + const ResultType result_type = get_node_socket_result_type(output_socket.bsocket()); const Result result = Result(result_type, texture_pool()); populate_result(output_identifier, result); @@ -284,7 +284,7 @@ void ShaderOperation::populate_operation_result(DOutputSocket output_socket, GPU output_sockets_to_output_identifiers_map_.add_new(output_socket, output_identifier); ShaderNode &node = *shader_nodes_.lookup(output_socket.node()); - GPUNodeLink *output_link = node.get_output(output_socket->identifier()).link; + GPUNodeLink *output_link = node.get_output(output_socket->identifier).link; /* Link the output node stack to an output storer storing in the appropriate result. The result * is identified by its index in the operation and the index is encoded as a float to be passed diff --git a/source/blender/compositor/realtime_compositor/intern/utilities.cc b/source/blender/compositor/realtime_compositor/intern/utilities.cc index 169ba70e9eb..2e1baec98a8 100644 --- a/source/blender/compositor/realtime_compositor/intern/utilities.cc +++ b/source/blender/compositor/realtime_compositor/intern/utilities.cc @@ -26,7 +26,7 @@ using TargetSocketPathInfo = DOutputSocket::TargetSocketPathInfo; DSocket get_input_origin_socket(DInputSocket input) { /* The input is unlinked. Return the socket itself. */ - if (input->logically_linked_sockets().is_empty()) { + if (!input->is_logically_linked()) { return input; } @@ -52,9 +52,9 @@ DOutputSocket get_output_linked_to_input(DInputSocket input) return DOutputSocket(origin); } -ResultType get_node_socket_result_type(const SocketRef *socket) +ResultType get_node_socket_result_type(const bNodeSocket *socket) { - switch (socket->bsocket()->type) { + switch (socket->type) { case SOCK_FLOAT: return ResultType::Float; case SOCK_VECTOR: @@ -95,21 +95,20 @@ int number_of_inputs_linked_to_output_conditioned(DOutputSocket output, bool is_shader_node(DNode node) { - return node->typeinfo()->get_compositor_shader_node; + return node->typeinfo->get_compositor_shader_node; } bool is_node_supported(DNode node) { - return node->typeinfo()->get_compositor_operation || - node->typeinfo()->get_compositor_shader_node; + return node->typeinfo->get_compositor_operation || node->typeinfo->get_compositor_shader_node; } -InputDescriptor input_descriptor_from_input_socket(const InputSocketRef *socket) +InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket) { using namespace nodes; InputDescriptor input_descriptor; input_descriptor.type = get_node_socket_result_type(socket); - const NodeDeclaration *node_declaration = socket->node().declaration(); + const NodeDeclaration *node_declaration = socket->owner_node().declaration(); /* Not every node have a declaration, in which case, we assume the default values for the rest of * the properties. */ if (!node_declaration) { diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc index 96ab9388023..9ccd7ed447b 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc @@ -62,6 +62,7 @@ void RuntimeBackup::init_from_id(ID *id) break; case ID_GD: gpencil_backup.init_from_gpencil(reinterpret_cast<bGPdata *>(id)); + break; default: break; } @@ -104,6 +105,7 @@ void RuntimeBackup::restore_to_id(ID *id) break; case ID_GD: gpencil_backup.restore_to_gpencil(reinterpret_cast<bGPdata *>(id)); + break; default: break; } diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.c b/source/blender/draw/engines/overlay/overlay_edit_uv.c index 4cfe9fcea4e..adbe5e7155e 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_uv.c +++ b/source/blender/draw/engines/overlay/overlay_edit_uv.c @@ -160,7 +160,6 @@ void OVERLAY_edit_uv_init(OVERLAY_Data *vedata) pd->edit_uv.draw_type = sima->dt_uvstretch; BLI_listbase_clear(&pd->edit_uv.totals); pd->edit_uv.total_area_ratio = 0.0f; - pd->edit_uv.total_area_ratio_inv = 0.0f; /* During engine initialization phase the `sima` isn't locked and * we are able to retrieve the needed data. @@ -280,8 +279,6 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata) DRW_shgroup_uniform_block(pd->edit_uv_stretching_grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float( pd->edit_uv_stretching_grp, "totalAreaRatio", &pd->edit_uv.total_area_ratio, 1); - DRW_shgroup_uniform_float( - pd->edit_uv_stretching_grp, "totalAreaRatioInv", &pd->edit_uv.total_area_ratio_inv, 1); } } @@ -510,7 +507,6 @@ static void edit_uv_stretching_update_ratios(OVERLAY_Data *vedata) if (total_area > FLT_EPSILON && total_area_uv > FLT_EPSILON) { pd->edit_uv.total_area_ratio = total_area / total_area_uv; - pd->edit_uv.total_area_ratio_inv = total_area_uv / total_area; } } BLI_freelistN(&pd->edit_uv.totals); diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index 7d216ca54cf..06c6ce42fd8 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -384,7 +384,6 @@ typedef struct OVERLAY_PrivateData { eSpaceImage_UVDT_Stretch draw_type; ListBase totals; float total_area_ratio; - float total_area_ratio_inv; /* stencil overlay */ struct Image *stencil_image; diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh index 58f96110887..9396a6d3f2f 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh @@ -293,7 +293,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_stretching_area) .do_static_compilation(true) .vertex_in(1, Type::FLOAT, "ratio") .push_constant(Type::FLOAT, "totalAreaRatio") - .push_constant(Type::FLOAT, "totalAreaRatioInv") .additional_info("overlay_edit_uv_stretching"); GPU_SHADER_CREATE_INFO(overlay_edit_uv_stretching_angle) diff --git a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl index bb086e8d9f5..9a3036d5940 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl @@ -55,9 +55,9 @@ float angle_normalized_v2v2(vec2 v1, vec2 v2) return (q) ? a : M_PI - a; } -float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio) +float area_ratio_to_stretch(float ratio, float tot_ratio) { - ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio; + ratio *= tot_ratio; return (ratio > 1.0f) ? (1.0f / ratio) : ratio; } @@ -74,7 +74,7 @@ void main() stretch = stretch; stretch = 1.0 - stretch * stretch; #else - float stretch = 1.0 - area_ratio_to_stretch(ratio, totalAreaRatio, totalAreaRatioInv); + float stretch = 1.0 - area_ratio_to_stretch(ratio, totalAreaRatio); #endif diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc index 1d3d6222f8f..4f0072ec657 100644 --- a/source/blender/draw/intern/draw_cache_impl_curves.cc +++ b/source/blender/draw/intern/draw_cache_impl_curves.cc @@ -397,10 +397,10 @@ static void curves_batch_cache_fill_strands_data(const Curves &curves_id, curves_id.geometry); for (const int i : IndexRange(curves.curves_num())) { - const IndexRange curve_range = curves.points_for_curve(i); + const IndexRange points = curves.points_for_curve(i); - *(uint *)GPU_vertbuf_raw_step(&data_step) = curve_range.start(); - *(ushort *)GPU_vertbuf_raw_step(&seg_step) = curve_range.size() - 1; + *(uint *)GPU_vertbuf_raw_step(&data_step) = points.start(); + *(ushort *)GPU_vertbuf_raw_step(&seg_step) = points.size() - 1; } } diff --git a/source/blender/draw/intern/draw_debug.cc b/source/blender/draw/intern/draw_debug.cc index b9d10302c1e..ab78db5d913 100644 --- a/source/blender/draw/intern/draw_debug.cc +++ b/source/blender/draw/intern/draw_debug.cc @@ -525,14 +525,14 @@ void DebugDraw::display_lines() if (gpu_draw_buf_used) { GPU_debug_group_begin("GPU"); GPU_storagebuf_bind(gpu_draw_buf_, slot); - GPU_batch_draw_indirect(batch, gpu_draw_buf_); + GPU_batch_draw_indirect(batch, gpu_draw_buf_, 0); GPU_storagebuf_unbind(gpu_draw_buf_); GPU_debug_group_end(); } GPU_debug_group_begin("CPU"); GPU_storagebuf_bind(cpu_draw_buf_, slot); - GPU_batch_draw_indirect(batch, cpu_draw_buf_); + GPU_batch_draw_indirect(batch, cpu_draw_buf_, 0); GPU_storagebuf_unbind(cpu_draw_buf_); GPU_debug_group_end(); @@ -557,14 +557,14 @@ void DebugDraw::display_prints() if (gpu_print_buf_used) { GPU_debug_group_begin("GPU"); GPU_storagebuf_bind(gpu_print_buf_, slot); - GPU_batch_draw_indirect(batch, gpu_print_buf_); + GPU_batch_draw_indirect(batch, gpu_print_buf_, 0); GPU_storagebuf_unbind(gpu_print_buf_); GPU_debug_group_end(); } GPU_debug_group_begin("CPU"); GPU_storagebuf_bind(cpu_print_buf_, slot); - GPU_batch_draw_indirect(batch, cpu_print_buf_); + GPU_batch_draw_indirect(batch, cpu_print_buf_, 0); GPU_storagebuf_unbind(cpu_print_buf_); GPU_debug_group_end(); diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 4dda0ceb2ef..0e39cc1d3b9 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -891,7 +891,7 @@ static void draw_call_indirect(DRWShadingGroup *shgroup, } GPU_batch_set_shader(batch, shgroup->shader); - GPU_batch_draw_indirect(batch, indirect_buf); + GPU_batch_draw_indirect(batch, indirect_buf, 0); } static void draw_call_batching_start(DRWCommandsState *state) diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc index febddf61e1f..9679c0523f8 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc @@ -27,7 +27,7 @@ static void extract_edituv_stretch_area_init(const MeshRenderData *mr, GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); static GPUVertFormat format = {0}; if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); } GPU_vertbuf_init_with_format(vbo, &format); @@ -37,15 +37,14 @@ static void extract_edituv_stretch_area_init(const MeshRenderData *mr, BLI_INLINE float area_ratio_get(float area, float uvarea) { if (area >= FLT_EPSILON && uvarea >= FLT_EPSILON) { - /* Tag inversion by using the sign. */ - return (area > uvarea) ? (uvarea / area) : -(area / uvarea); + return uvarea / area; } return 0.0f; } -BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio) +BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio) { - ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio; + ratio *= tot_ratio; return (ratio > 1.0f) ? (1.0f / ratio) : ratio; } @@ -97,14 +96,8 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__)); compute_area_ratio(mr, area_ratio, cache->tot_area, cache->tot_uv_area); - /* Convert in place to avoid an extra allocation */ - uint16_t *poly_stretch = (uint16_t *)area_ratio; - for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) { - poly_stretch[mp_index] = area_ratio[mp_index] * SHRT_MAX; - } - /* Copy face data for each loop. */ - uint16_t *loop_stretch = (uint16_t *)GPU_vertbuf_get_data(vbo); + float *loop_stretch = (float *)GPU_vertbuf_get_data(vbo); if (mr->extract_type == MR_EXTRACT_BMESH) { BMFace *efa; @@ -112,7 +105,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, int f, l_index = 0; BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) { for (int i = 0; i < efa->len; i++, l_index++) { - loop_stretch[l_index] = poly_stretch[f]; + loop_stretch[l_index] = area_ratio[f]; } } } @@ -121,7 +114,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, const MPoly *mp = mr->mpoly; for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { for (int i = 0; i < mp->totloop; i++, l_index++) { - loop_stretch[l_index] = poly_stretch[mp_index]; + loop_stretch[l_index] = area_ratio[mp_index]; } } } diff --git a/source/blender/editors/curves/intern/curves_add.cc b/source/blender/editors/curves/intern/curves_add.cc index 79916253207..f234a58f439 100644 --- a/source/blender/editors/curves/intern/curves_add.cc +++ b/source/blender/editors/curves/intern/curves_add.cc @@ -102,10 +102,9 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi MutableSpan<int> offsets = curves.offsets_for_write(); MutableSpan<float3> positions = curves.positions_for_write(); - - float *radius_data = (float *)CustomData_add_layer_named( - &curves.point_data, CD_PROP_FLOAT, CD_DEFAULT, nullptr, curves.point_num, "radius"); - MutableSpan<float> radii{radius_data, curves.points_num()}; + bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); + bke::SpanAttributeWriter<float> radius = attributes.lookup_or_add_for_write_only_span<float>( + "radius", ATTR_DOMAIN_POINT); for (const int i : offsets.index_range()) { offsets[i] = points_per_curve * i; @@ -114,9 +113,9 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi RandomNumberGenerator rng; for (const int i : curves.curves_range()) { - const IndexRange curve_range = curves.points_for_curve(i); - MutableSpan<float3> curve_positions = positions.slice(curve_range); - MutableSpan<float> curve_radii = radii.slice(curve_range); + const IndexRange points = curves.points_for_curve(i); + MutableSpan<float3> curve_positions = positions.slice(points); + MutableSpan<float> curve_radii = radius.span.slice(points); const float theta = 2.0f * M_PI * rng.get_float(); const float phi = saacosf(2.0f * rng.get_float() - 1.0f); @@ -135,6 +134,8 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi } } + radius.finish(); + return curves; } diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index aec22f0f3ae..2dcb7aa438f 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -305,7 +305,7 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); src_varray.materialize_to_uninitialized(new_data); attributes.remove(name); - attributes.add(name, dst_domain, dst_type, blender::bke::AttributeInitMove(new_data)); + attributes.add(name, dst_domain, dst_type, blender::bke::AttributeInitMoveArray(new_data)); break; } case ConvertAttributeMode::UVMap: { @@ -660,7 +660,7 @@ bool ED_geometry_attribute_convert(Mesh *mesh, void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); src_varray.materialize_to_uninitialized(new_data); attributes.remove(name); - attributes.add(name, new_domain, new_type, blender::bke::AttributeInitMove(new_data)); + attributes.add(name, new_domain, new_type, blender::bke::AttributeInitMoveArray(new_data)); int *active_index = BKE_id_attributes_active_index_p(&mesh->id); if (*active_index > 0) { diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 9843bd22bb6..280512a2dd3 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -4770,6 +4770,8 @@ void GPENCIL_OT_stroke_sample(wmOperatorType *ot) /* properties */ prop = RNA_def_float(ot->srna, "length", 0.1f, 0.0f, 100.0f, "Length", "", 0.0f, 100.0f); + prop = RNA_def_float( + ot->srna, "sharp_threshold", 0.1f, 0.0f, M_PI, "Sharp Threshold", "", 0.0f, M_PI); /* avoid re-using last var */ RNA_def_property_flag(prop, PROP_SKIP_SAVE); } diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc index c076845af3c..933724c9294 100644 --- a/source/blender/editors/interface/interface.cc +++ b/source/blender/editors/interface/interface.cc @@ -6754,10 +6754,11 @@ void UI_but_extra_icon_string_info_get(struct bContext *C, uiButExtraOpIcon *ext if (ui_but_extra_icon_event_operator_string(C, extra_icon, buf, sizeof(buf))) { tmp = BLI_strdup(buf); } + break; } + default: /* Other types not supported. The caller should expect that outcome, no need to message or * assert here. */ - default: break; } diff --git a/source/blender/editors/interface/interface_template_search_menu.cc b/source/blender/editors/interface/interface_template_search_menu.cc index c3021028b97..c777b7834f2 100644 --- a/source/blender/editors/interface/interface_template_search_menu.cc +++ b/source/blender/editors/interface/interface_template_search_menu.cc @@ -918,6 +918,7 @@ static void menu_search_arg_free_fn(void *data_v) WM_operator_properties_free(item->op.opptr); MEM_freeN(item->op.opptr); } + break; } case MenuSearch_Item::Type::RNA: { break; diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index ea29d07feaf..e394f8a7251 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -286,7 +286,8 @@ int ED_mesh_uv_add( is_init = true; } else { - CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, nullptr, me->totloop, name); + CustomData_add_layer_named( + &me->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, me->totloop, name); } if (active_set || layernum_dst == 0) { @@ -409,7 +410,7 @@ int ED_mesh_color_add( } else { CustomData_add_layer_named( - &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, nullptr, me->totloop, name); + &me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, me->totloop, name); } if (active_set || layernum == 0) { @@ -432,7 +433,7 @@ bool ED_mesh_color_ensure(Mesh *me, const char *name) if (!layer) { CustomData_add_layer_named( - &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, nullptr, me->totloop, name); + &me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, me->totloop, name); layer = me->ldata.layers + CustomData_get_layer_index(&me->ldata, CD_PROP_BYTE_COLOR); BKE_id_attributes_active_color_set(&me->id, layer); @@ -500,7 +501,7 @@ int ED_mesh_sculpt_color_add(Mesh *me, const char *name, const bool do_init, Rep } else { CustomData_add_layer_named( - &me->vdata, CD_PROP_COLOR, CD_DEFAULT, nullptr, me->totvert, name); + &me->vdata, CD_PROP_COLOR, CD_SET_DEFAULT, nullptr, me->totvert, name); } if (layernum == 0) { @@ -790,7 +791,7 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator me->smoothresh); } - CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, nullptr, me->totloop); + CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, me->totloop); } DEG_id_tag_update(&me->id, 0); @@ -875,11 +876,11 @@ static void mesh_add_verts(Mesh *mesh, int len) int totvert = mesh->totvert + len; CustomData vdata; - CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_DEFAULT, totvert); + CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); if (!CustomData_has_layer(&vdata, CD_MVERT)) { - CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, nullptr, totvert); + CustomData_add_layer(&vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, totvert); } CustomData_free(&mesh->vdata, mesh->totvert); @@ -913,11 +914,11 @@ static void mesh_add_edges(Mesh *mesh, int len) totedge = mesh->totedge + len; /* Update custom-data. */ - CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge); + CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) { - CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge); + CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, totedge); } CustomData_free(&mesh->edata, mesh->totedge); @@ -947,11 +948,11 @@ static void mesh_add_loops(Mesh *mesh, int len) totloop = mesh->totloop + len; /* new face count */ /* update customdata */ - CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_DEFAULT, totloop); + CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop); if (!CustomData_has_layer(&ldata, CD_MLOOP)) { - CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, nullptr, totloop); + CustomData_add_layer(&ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, totloop); } BKE_mesh_runtime_clear_cache(mesh); @@ -976,11 +977,11 @@ static void mesh_add_polys(Mesh *mesh, int len) totpoly = mesh->totpoly + len; /* new face count */ /* update customdata */ - CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_DEFAULT, totpoly); + CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly); if (!CustomData_has_layer(&pdata, CD_MPOLY)) { - CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, nullptr, totpoly); + CustomData_add_layer(&pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, totpoly); } CustomData_free(&mesh->pdata, mesh->totpoly); diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc index 7db777c2134..330560be026 100644 --- a/source/blender/editors/mesh/meshtools.cc +++ b/source/blender/editors/mesh/meshtools.cc @@ -103,7 +103,7 @@ static void join_mesh_single(Depsgraph *depsgraph, ((Mesh *)ob_dst->data)->cd_flag |= me->cd_flag; /* standard data */ - CustomData_merge(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_DEFAULT, totvert); + CustomData_merge(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert); CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert); /* vertex groups */ @@ -202,7 +202,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } if (me->totedge) { - CustomData_merge(&me->edata, edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge); + CustomData_merge(&me->edata, edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge); for (a = 0; a < me->totedge; a++, medge++) { @@ -223,7 +223,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } } - CustomData_merge(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_DEFAULT, totloop); + CustomData_merge(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop); CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop); for (a = 0; a < me->totloop; a++, mloop++) { @@ -247,7 +247,7 @@ static void join_mesh_single(Depsgraph *depsgraph, } } - CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_DEFAULT, totpoly); + CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly); CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly); blender::bke::AttributeWriter<int> material_indices = @@ -584,10 +584,10 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op) CustomData_reset(&ldata); CustomData_reset(&pdata); - mvert = (MVert *)CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, nullptr, totvert); - medge = (MEdge *)CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge); - mloop = (MLoop *)CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, nullptr, totloop); - mpoly = (MPoly *)CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, nullptr, totpoly); + mvert = (MVert *)CustomData_add_layer(&vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, totvert); + medge = (MEdge *)CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, totedge); + mloop = (MLoop *)CustomData_add_layer(&ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, totloop); + mpoly = (MPoly *)CustomData_add_layer(&pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, totpoly); vertofs = 0; edgeofs = 0; diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c index dddf5e40e87..4364375a4e3 100644 --- a/source/blender/editors/object/object_facemap_ops.c +++ b/source/blender/editors/object/object_facemap_ops.c @@ -53,7 +53,7 @@ void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum) /* if there's is no facemap layer then create one */ if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL) { - facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly); + facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_SET_DEFAULT, NULL, me->totpoly); } facemap[facenum] = fmap_nr; diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index f6e97f81cb6..085ef59ac21 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -586,9 +586,11 @@ bool ED_object_modifier_convert_psys_to_mesh(ReportList *UNUSED(reports), me->totvert = verts_num; me->totedge = edges_num; - me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, verts_num); - me->medge = (MEdge *)CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, nullptr, edges_num); - me->mface = (MFace *)CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, nullptr, 0); + me->mvert = (MVert *)CustomData_add_layer( + &me->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, verts_num); + me->medge = (MEdge *)CustomData_add_layer( + &me->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, edges_num); + me->mface = (MFace *)CustomData_add_layer(&me->fdata, CD_MFACE, CD_SET_DEFAULT, nullptr, 0); MVert *mvert = me->mvert; MEdge *medge = me->medge; @@ -2642,7 +2644,7 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, MVert *mvert = me_eval_deform->mvert; /* add vertex weights to original mesh */ - CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, nullptr, me->totvert); + CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, me->totvert); ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); Object *arm_ob = BKE_object_add(bmain, view_layer, OB_ARMATURE, nullptr); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 8f563fa388a..cfbb0a724b7 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2356,6 +2356,25 @@ static int make_override_library_exec(bContext *C, wmOperator *op) BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + /* For the time being, replace selected linked objects by their overrides in all collections. + * While this may not be the absolute best behavior in all cases, in most common one this should + * match the expected result. */ + if (user_overrides_objects_uids != NULL) { + LISTBASE_FOREACH (Collection *, coll_iter, &bmain->collections) { + if (ID_IS_LINKED(coll_iter)) { + continue; + } + LISTBASE_FOREACH (CollectionObject *, coll_ob_iter, &coll_iter->gobject) { + if (BLI_gset_haskey(user_overrides_objects_uids, + POINTER_FROM_UINT(coll_ob_iter->ob->id.session_uuid))) { + /* Tag for remapping when creating overrides. */ + coll_iter->id.tag |= LIB_TAG_DOIT; + break; + } + } + } + } + ID *id_root_override; const bool success = BKE_lib_override_library_create(bmain, scene, diff --git a/source/blender/editors/object/object_vgroup.cc b/source/blender/editors/object/object_vgroup.cc index 0e0f5bd94cc..7a61adfb95c 100644 --- a/source/blender/editors/object/object_vgroup.cc +++ b/source/blender/editors/object/object_vgroup.cc @@ -1773,7 +1773,8 @@ static void vgroup_lock_all(Object *ob, int action, int mask) continue; } break; - default:; + default: + break; } if (dg->flag & DG_LOCK_WEIGHT) { @@ -1795,7 +1796,8 @@ static void vgroup_lock_all(Object *ob, int action, int mask) continue; } break; - default:; + default: + break; } switch (action) { diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc index 1ee43d98e6f..02ae89b41e6 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc @@ -144,21 +144,20 @@ class ExtrapolateCurvesEffect : public CurvesEffect { for (const int influence_i : range) { const int curve_i = curve_indices[influence_i]; const float move_distance_cu = move_distances_cu[influence_i]; - const IndexRange curve_points = curves.points_for_curve(curve_i); + const IndexRange points = curves.points_for_curve(curve_i); - if (curve_points.size() <= 1) { + if (points.size() <= 1) { continue; } - const float3 old_last_pos_cu = positions_cu[curve_points.last()]; + const float3 old_last_pos_cu = positions_cu[points.last()]; /* Use some point within the curve rather than the end point to smooth out some random * variation. */ - const float3 direction_reference_point = - positions_cu[curve_points[curve_points.size() / 2]]; + const float3 direction_reference_point = positions_cu[points[points.size() / 2]]; const float3 direction = math::normalize(old_last_pos_cu - direction_reference_point); const float3 new_last_pos_cu = old_last_pos_cu + direction * move_distance_cu; - move_last_point_and_resample(positions_cu.slice(curve_points), new_last_pos_cu); + move_last_point_and_resample(positions_cu.slice(points), new_last_pos_cu); } }); } diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index a7aa29853e6..c1289364fb2 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -81,7 +81,7 @@ static void partialvis_update_mesh(Object *ob, bool *hide_vert = CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".hide_vert"); if (hide_vert == NULL) { hide_vert = CustomData_add_layer_named( - &me->vdata, CD_PROP_BOOL, CD_CALLOC, NULL, me->totvert, ".hide_vert"); + &me->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, me->totvert, ".hide_vert"); } SCULPT_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN); diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index 433823c8373..000b69cc2ba 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -218,7 +218,7 @@ static void SCULPT_dynamic_topology_disable_ex( /* Reset Face Sets as they are no longer valid. */ if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) { - CustomData_add_layer(&me->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, me->totpoly); + CustomData_add_layer(&me->pdata, CD_SCULPT_FACE_SETS, CD_SET_DEFAULT, NULL, me->totpoly); } ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); for (int i = 0; i < me->totpoly; i++) { diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 58d62fb2165..b0dcef61c31 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -1683,7 +1683,7 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr CustomData *cdata = attr->domain == ATTR_DOMAIN_POINT ? &me->vdata : &me->ldata; int totelem = attr->domain == ATTR_DOMAIN_POINT ? me->totvert : me->totloop; - CustomData_add_layer_named(cdata, attr->type, CD_DEFAULT, NULL, totelem, attr->name); + CustomData_add_layer_named(cdata, attr->type, CD_SET_DEFAULT, NULL, totelem, attr->name); layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain); } diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index 25ab06850f5..e8325d658ca 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -477,7 +477,7 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_RGB: ntype->draw_buttons = node_buts_rgb; break; - case SH_NODE_MIX_RGB: + case SH_NODE_MIX_RGB_LEGACY: ntype->draw_buttons = node_buts_mix_rgb; break; case SH_NODE_VALTORGB: diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index d911e53be7f..3a8bb56bc5e 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -18,6 +18,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "BKE_node_tree_update.h" #include "BKE_screen.h" @@ -46,14 +47,11 @@ #include "BLT_translation.h" #include "NOD_node_declaration.hh" -#include "NOD_node_tree_ref.hh" #include "NOD_socket_declarations.hh" #include "NOD_socket_declarations_geometry.hh" #include "node_intern.hh" /* own include */ -using namespace blender::nodes::node_tree_ref_types; - struct bNodeListItem { struct bNodeListItem *next, *prev; struct bNode *node; @@ -434,18 +432,18 @@ namespace viewer_linking { * \{ */ /* Depending on the node tree type, different socket types are supported by viewer nodes. */ -static bool socket_can_be_viewed(const OutputSocketRef &socket) +static bool socket_can_be_viewed(const bNodeSocket &socket) { - if (nodeSocketIsHidden(socket.bsocket())) { + if (nodeSocketIsHidden(&socket)) { return false; } - if (socket.idname() == "NodeSocketVirtual") { + if (STREQ(socket.idname, "NodeSocketVirtual")) { return false; } - if (socket.tree().btree()->type != NTREE_GEOMETRY) { + if (socket.owner_tree().type != NTREE_GEOMETRY) { return true; } - return ELEM(socket.typeinfo()->type, + return ELEM(socket.typeinfo->type, SOCK_GEOMETRY, SOCK_FLOAT, SOCK_VECTOR, @@ -502,15 +500,15 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree, return nullptr; } -static bool is_viewer_node(const NodeRef &node) +static bool is_viewer_node(const bNode &node) { - return ELEM(node.bnode()->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER); + return ELEM(node.type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER); } -static Vector<const NodeRef *> find_viewer_nodes(const NodeTreeRef &tree) +static Vector<const bNode *> find_viewer_nodes(const bNodeTree &tree) { - Vector<const NodeRef *> viewer_nodes; - for (const NodeRef *node : tree.nodes()) { + Vector<const bNode *> viewer_nodes; + for (const bNode *node : tree.all_nodes()) { if (is_viewer_node(*node)) { viewer_nodes.append(node); } @@ -518,20 +516,20 @@ static Vector<const NodeRef *> find_viewer_nodes(const NodeTreeRef &tree) return viewer_nodes; } -static bool is_viewer_socket_in_viewer(const InputSocketRef &socket) +static bool is_viewer_socket_in_viewer(const bNodeSocket &socket) { - const NodeRef &node = socket.node(); + const bNode &node = socket.owner_node(); BLI_assert(is_viewer_node(node)); - if (node.typeinfo()->type == GEO_NODE_VIEWER) { + if (node.typeinfo->type == GEO_NODE_VIEWER) { return true; } return socket.index() == 0; } -static bool is_linked_to_viewer(const OutputSocketRef &socket, const NodeRef &viewer_node) +static bool is_linked_to_viewer(const bNodeSocket &socket, const bNode &viewer_node) { - for (const InputSocketRef *target_socket : socket.directly_linked_sockets()) { - if (&target_socket->node() != &viewer_node) { + for (const bNodeSocket *target_socket : socket.directly_linked_sockets()) { + if (&target_socket->owner_node() != &viewer_node) { continue; } if (!target_socket->is_available()) { @@ -561,39 +559,39 @@ static void remove_links_to_unavailable_viewer_sockets(bNodeTree &btree, bNode & } } -static const NodeRef *get_existing_viewer(const NodeTreeRef &tree) +static const bNode *get_existing_viewer(const bNodeTree &tree) { - Vector<const NodeRef *> viewer_nodes = find_viewer_nodes(tree); + Vector<const bNode *> viewer_nodes = find_viewer_nodes(tree); /* Check if there is already an active viewer node that should be used. */ - for (const NodeRef *viewer_node : viewer_nodes) { - if (viewer_node->bnode()->flag & NODE_DO_OUTPUT) { + for (const bNode *viewer_node : viewer_nodes) { + if (viewer_node->flag & NODE_DO_OUTPUT) { return viewer_node; } } /* If no active but non-active viewers exist, make one active. */ if (!viewer_nodes.is_empty()) { - viewer_nodes[0]->bnode()->flag |= NODE_DO_OUTPUT; + const_cast<bNode *>(viewer_nodes[0])->flag |= NODE_DO_OUTPUT; return viewer_nodes[0]; } return nullptr; } -static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *active_viewer_node, - const NodeRef &node_to_view) +static const bNodeSocket *find_output_socket_to_be_viewed(const bNode *active_viewer_node, + const bNode &node_to_view) { /* Check if any of the output sockets is selected, which is the case when the user just clicked * on the socket. */ - for (const OutputSocketRef *output_socket : node_to_view.outputs()) { - if (output_socket->bsocket()->flag & SELECT) { + for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { + if (output_socket->flag & SELECT) { return output_socket; } } - const OutputSocketRef *last_socket_linked_to_viewer = nullptr; + const bNodeSocket *last_socket_linked_to_viewer = nullptr; if (active_viewer_node != nullptr) { - for (const OutputSocketRef *output_socket : node_to_view.outputs()) { + for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { if (!socket_can_be_viewed(*output_socket)) { continue; } @@ -604,7 +602,7 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act } if (last_socket_linked_to_viewer == nullptr) { /* If no output is connected to a viewer, use the first output that can be viewed. */ - for (const OutputSocketRef *output_socket : node_to_view.outputs()) { + for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { if (socket_can_be_viewed(*output_socket)) { return output_socket; } @@ -612,10 +610,10 @@ static const OutputSocketRef *find_output_socket_to_be_viewed(const NodeRef *act } else { /* Pick the next socket to be linked to the viewer. */ - const int tot_outputs = node_to_view.outputs().size(); + const int tot_outputs = node_to_view.output_sockets().size(); for (const int offset : IndexRange(1, tot_outputs - 1)) { const int index = (last_socket_linked_to_viewer->index() + offset) % tot_outputs; - const OutputSocketRef &output_socket = node_to_view.output(index); + const bNodeSocket &output_socket = node_to_view.output_socket(index); if (!socket_can_be_viewed(output_socket)) { continue; } @@ -682,20 +680,15 @@ static int node_link_viewer(const bContext &C, bNode &bnode_to_view) { SpaceNode &snode = *CTX_wm_space_node(&C); bNodeTree *btree = snode.edittree; + btree->ensure_topology_cache(); - const NodeTreeRef tree{btree}; - const NodeRef &node_to_view = *tree.find_node(bnode_to_view); - const NodeRef *active_viewer_node = get_existing_viewer(tree); - - const OutputSocketRef *socket_to_view = find_output_socket_to_be_viewed(active_viewer_node, - node_to_view); - if (socket_to_view == nullptr) { + bNode *active_viewer_bnode = const_cast<bNode *>(get_existing_viewer(*btree)); + bNodeSocket *bsocket_to_view = const_cast<bNodeSocket *>( + find_output_socket_to_be_viewed(active_viewer_bnode, bnode_to_view)); + if (bsocket_to_view == nullptr) { return OPERATOR_FINISHED; } - - bNodeSocket &bsocket_to_view = *socket_to_view->bsocket(); - bNode *viewer_bnode = active_viewer_node ? active_viewer_node->bnode() : nullptr; - return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view); + return link_socket_to_viewer(C, active_viewer_bnode, bnode_to_view, *bsocket_to_view); } /** \} */ @@ -2048,7 +2041,7 @@ static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketIn /* Try to get the main socket based on the socket declaration. */ nodeDeclarationEnsure(&ntree, &node); - const nodes::NodeDeclaration *node_decl = node.runtime->declaration; + const nodes::NodeDeclaration *node_decl = node.declaration(); if (node_decl != nullptr) { Span<nodes::SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() : node_decl->outputs(); diff --git a/source/blender/editors/space_outliner/outliner_collections.cc b/source/blender/editors/space_outliner/outliner_collections.cc index 23ee8a2c3f2..a76a9bddea5 100644 --- a/source/blender/editors/space_outliner/outliner_collections.cc +++ b/source/blender/editors/space_outliner/outliner_collections.cc @@ -345,8 +345,12 @@ void outliner_collection_delete( /* We first walk over and find the Collections we actually want to delete * (ignoring duplicates). */ - outliner_tree_traverse( - space_outliner, &space_outliner->tree, 0, TSE_SELECTED, collection_collect_data_to_edit, &data); + outliner_tree_traverse(space_outliner, + &space_outliner->tree, + 0, + TSE_SELECTED, + collection_collect_data_to_edit, + &data); /* Effectively delete the collections. */ GSetIterator collections_to_edit_iter; @@ -707,8 +711,12 @@ static int collection_link_exec(bContext *C, wmOperator *op) data.collections_to_edit = BLI_gset_ptr_new(__func__); /* We first walk over and find the Collections we actually want to link (ignoring duplicates). */ - outliner_tree_traverse( - space_outliner, &space_outliner->tree, 0, TSE_SELECTED, collection_collect_data_to_edit, &data); + outliner_tree_traverse(space_outliner, + &space_outliner->tree, + 0, + TSE_SELECTED, + collection_collect_data_to_edit, + &data); /* Effectively link the collections. */ GSetIterator collections_to_edit_iter; @@ -766,8 +774,12 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op)) /* We first walk over and find the Collections we actually want to instance * (ignoring duplicates). */ - outliner_tree_traverse( - space_outliner, &space_outliner->tree, 0, TSE_SELECTED, collection_collect_data_to_edit, &data); + outliner_tree_traverse(space_outliner, + &space_outliner->tree, + 0, + TSE_SELECTED, + collection_collect_data_to_edit, + &data); /* Find an active collection to add to, that doesn't give dependency cycles. */ LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer); diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index 69c88f3b874..a5fa8fb59e9 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -1276,7 +1276,7 @@ static void id_override_library_reset_fn(bContext *C, OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data); const bool do_hierarchy = data->do_hierarchy; - if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) { CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name); return; } @@ -1304,7 +1304,7 @@ static void id_override_library_clear_single_fn(bContext *C, ViewLayer *view_layer = CTX_data_view_layer(C); ID *id = tselem->id; - if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || ID_IS_LINKED(id)) { BKE_reportf(reports, RPT_WARNING, "Cannot clear embedded library override id '%s', only overrides of real " @@ -1352,8 +1352,9 @@ static void id_override_library_resync_fn(bContext *UNUSED(C), ID *id_root = tselem->id; OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data); - if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) { CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name); + return; } if (id_root->override_library->hierarchy_root != nullptr) { @@ -1401,7 +1402,7 @@ static void id_override_library_delete_hierarchy_fn(bContext *UNUSED(C), BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; - if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) { CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name); return; } diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 7c46937bed2..6365dfe26a7 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -232,7 +232,7 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain, storage = (NodeShaderAttribute *)input_attr_color->storage; BLI_strncpy(storage->name, "Color", sizeof(storage->name)); - bNode *mix_rgb_color = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX_RGB); + bNode *mix_rgb_color = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX_RGB_LEGACY); mix_rgb_color->custom1 = MA_RAMP_BLEND; // Mix mix_rgb_color->locx = 200.0f; mix_rgb_color->locy = -200.0f; @@ -246,7 +246,7 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain, storage = (NodeShaderAttribute *)input_attr_alpha->storage; BLI_strncpy(storage->name, "Alpha", sizeof(storage->name)); - bNode *mix_rgb_alpha = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX_RGB); + bNode *mix_rgb_alpha = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX_RGB_LEGACY); mix_rgb_alpha->custom1 = MA_RAMP_BLEND; // Mix mix_rgb_alpha->locx = 600.0f; mix_rgb_alpha->locy = 300.0f; @@ -577,15 +577,15 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) mesh->totcol = group->materials.size(); mesh->mvert = (MVert *)CustomData_add_layer( - &mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert); + &mesh->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, mesh->totvert); mesh->medge = (MEdge *)CustomData_add_layer( - &mesh->edata, CD_MEDGE, CD_CALLOC, nullptr, mesh->totedge); + &mesh->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, mesh->totedge); mesh->mpoly = (MPoly *)CustomData_add_layer( - &mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly); + &mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); mesh->mloop = (MLoop *)CustomData_add_layer( - &mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop); + &mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop); int *material_indices = (int *)CustomData_add_layer_named( - &mesh->pdata, CD_PROP_INT32, CD_DEFAULT, nullptr, mesh->totpoly, "material_index"); + &mesh->pdata, CD_PROP_INT32, CD_SET_DEFAULT, nullptr, mesh->totpoly, "material_index"); MVert *vertices = mesh->mvert; MEdge *edges = mesh->medge; MPoly *polys = mesh->mpoly; @@ -595,14 +595,14 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) if (hasTex) { // First UV layer CustomData_add_layer_named( - &mesh->ldata, CD_MLOOPUV, CD_CALLOC, nullptr, mesh->totloop, uvNames[0]); + &mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, mesh->totloop, uvNames[0]); CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 0); BKE_mesh_update_customdata_pointers(mesh, true); loopsuv[0] = mesh->mloopuv; // Second UV layer CustomData_add_layer_named( - &mesh->ldata, CD_MLOOPUV, CD_CALLOC, nullptr, mesh->totloop, uvNames[1]); + &mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, mesh->totloop, uvNames[1]); CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 1); BKE_mesh_update_customdata_pointers(mesh, true); loopsuv[1] = mesh->mloopuv; @@ -610,9 +610,9 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) // colors and transparency (the latter represented by grayscale colors) MLoopCol *colors = (MLoopCol *)CustomData_add_layer_named( - &mesh->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, nullptr, mesh->totloop, "Color"); + &mesh->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, mesh->totloop, "Color"); MLoopCol *transp = (MLoopCol *)CustomData_add_layer_named( - &mesh->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, nullptr, mesh->totloop, "Alpha"); + &mesh->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, mesh->totloop, "Alpha"); mesh->mloopcol = colors; mesh->mat = (Material **)MEM_mallocN(sizeof(Material *) * mesh->totcol, "MaterialList"); diff --git a/source/blender/geometry/intern/reverse_uv_sampler.cc b/source/blender/geometry/intern/reverse_uv_sampler.cc index 39fec40333c..f66e4a3ac2e 100644 --- a/source/blender/geometry/intern/reverse_uv_sampler.cc +++ b/source/blender/geometry/intern/reverse_uv_sampler.cc @@ -50,6 +50,11 @@ ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const float3 best_bary_weights; const MLoopTri *best_looptri; + /* The distance to an edge that is allowed to be inside or outside the triangle. Without this, + * the lookup can fail for floating point accuracy reasons when the uv is almost exact on an + * edge. */ + const float edge_epsilon = 0.00001f; + for (const int looptri_index : looptri_indices) { const MLoopTri &looptri = looptris_[looptri_index]; const float2 &uv_0 = uv_map_[looptri.tri[0]]; @@ -68,8 +73,12 @@ ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const const float dist = MAX3(x_dist, y_dist, z_dist); if (dist <= 0.0f && best_dist <= 0.0f) { - /* The uv sample is in multiple triangles. */ - return Result{ResultType::Multiple}; + const float worse_dist = std::max(dist, best_dist); + /* Allow ignoring multiple triangle intersections if the uv is almost exactly on an edge. */ + if (worse_dist < -edge_epsilon) { + /* The uv sample is in multiple triangles. */ + return Result{ResultType::Multiple}; + } } if (dist < best_dist) { @@ -79,8 +88,9 @@ ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const } } - /* Allow for a small epsilon in case the uv is on th edge. */ - if (best_dist < 0.00001f) { + /* Allow using the closest (but not intersecting) triangle if the uv is almost exactly on an + * edge. */ + if (best_dist < edge_epsilon) { return Result{ResultType::Ok, best_looptri, math::clamp(best_bary_weights, 0.0f, 1.0f)}; } diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index ad0dd8a030a..ae013a7dd02 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -84,6 +84,7 @@ typedef struct LineartElementLinkNode { /* For edge element link nodes, used for shadow edge matching. */ int obindex; + int global_index_offset; /** Per object value, always set, if not enabled by #ObjectLineArt, then it's set to global. */ float crease_threshold; @@ -205,6 +206,10 @@ typedef struct LineartEdgeChain { uint8_t intersection_mask; uint32_t shadow_mask_bits; + /* We need local index for correct weight transfer, line art index is global, thus + * local_index=lineart_index-index_offset. */ + uint32_t index_offset; + struct Object *object_ref; struct Object *silhouette_backdrop; } LineartEdgeChain; @@ -865,6 +870,7 @@ void MOD_lineart_chain_find_silhouette_backdrop_objects(LineartData *ld); int MOD_lineart_chain_count(const LineartEdgeChain *ec); void MOD_lineart_chain_clear_picked_flag(LineartCache *lc); +void MOD_lineart_finalize_chains(LineartData *ld); /** * This is the entry point of all line art calculations. diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c index 7c8e0c5a6f5..f32141a31eb 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c @@ -1051,6 +1051,38 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc) } } +LineartElementLinkNode *lineart_find_matching_eln_obj(ListBase *elns, struct Object *obj) +{ + LISTBASE_FOREACH (LineartElementLinkNode *, eln, elns) { + if (eln->object_ref == obj) { + return eln; + } + } + return NULL; +} + +void MOD_lineart_finalize_chains(LineartData *ld) +{ + LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) { + if (ELEM(ec->type, + LRT_EDGE_FLAG_INTERSECTION, + LRT_EDGE_FLAG_PROJECTED_SHADOW, + LRT_EDGE_FLAG_LIGHT_CONTOUR)) { + continue; + } + LineartElementLinkNode *eln = lineart_find_matching_eln_obj(&ld->geom.vertex_buffer_pointers, + ec->object_ref); + BLI_assert(eln != NULL); + if (LIKELY(eln)) { + LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) { + if (eci->index > eln->global_index_offset) { + eci->index -= eln->global_index_offset; + } + } + } + } +} + void MOD_lineart_smooth_chains(LineartData *ld, float tolerance) { LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) { diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index bde15515cb7..5bca49f632c 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -2660,6 +2660,7 @@ void lineart_main_load_geometries(Depsgraph *depsgraph, } LineartVert *v = (LineartVert *)obi->v_eln->pointer; int v_count = obi->v_eln->element_count; + obi->v_eln->global_index_offset = global_i; for (int vi = 0; vi < v_count; vi++) { v[vi].index += global_i; } @@ -5114,6 +5115,8 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph, /* At last, we need to clear flags so we don't confuse GPencil generation calls. */ MOD_lineart_chain_clear_picked_flag(lc); + + MOD_lineart_finalize_chains(ld); } lineart_mem_destroy(&lc->shadow_data_pool); diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h index 3668f1dc6d7..947586aaec4 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h @@ -133,6 +133,7 @@ void lineart_main_transform_and_add_shadow(struct LineartData *ld, struct LineartElementLinkNode *eeln); LineartElementLinkNode *lineart_find_matching_eln(struct ListBase *shadow_elns, int obindex); +LineartElementLinkNode *lineart_find_matching_eln_obj(struct ListBase *elns, struct Object *ob); LineartEdge *lineart_find_matching_edge(struct LineartElementLinkNode *shadow_eln, uint64_t edge_identifier); void lineart_register_shadow_cuts(struct LineartData *ld, diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 0c11ecb293b..c289a21421a 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -394,6 +394,7 @@ set(GLSL_SRC shaders/material/gpu_shader_material_light_path.glsl shaders/material/gpu_shader_material_mapping.glsl shaders/material/gpu_shader_material_map_range.glsl + shaders/material/gpu_shader_material_mix_color.glsl shaders/material/gpu_shader_material_mix_shader.glsl shaders/material/gpu_shader_material_noise.glsl shaders/material/gpu_shader_material_normal.glsl diff --git a/source/blender/gpu/GPU_batch.h b/source/blender/gpu/GPU_batch.h index c085b592a77..8f524f72fa1 100644 --- a/source/blender/gpu/GPU_batch.h +++ b/source/blender/gpu/GPU_batch.h @@ -164,6 +164,13 @@ void GPU_batch_program_set_builtin_with_config(GPUBatch *batch, #define GPU_batch_texture_bind(batch, name, tex) \ GPU_texture_bind(tex, GPU_shader_get_texture_binding((batch)->shader, name)); +/** + * Return indirect draw call parameters for this batch. + * NOTE: r_base_index is set to -1 if not using an index buffer. + */ +void GPU_batch_draw_parameter_get( + GPUBatch *batch, int *r_v_count, int *r_v_first, int *r_base_index, int *r_i_count); + void GPU_batch_draw(GPUBatch *batch); void GPU_batch_draw_range(GPUBatch *batch, int v_first, int v_count); /** @@ -180,7 +187,9 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi * Issue a draw call using GPU computed arguments. The argument are expected to be valid for the * type of geometry drawn (index or non-indexed). */ -void GPU_batch_draw_indirect(GPUBatch *batch, GPUStorageBuf *indirect_buf); +void GPU_batch_draw_indirect(GPUBatch *batch, GPUStorageBuf *indirect_buf, intptr_t offset); +void GPU_batch_multi_draw_indirect( + GPUBatch *batch, GPUStorageBuf *indirect_buf, int count, intptr_t offset, intptr_t stride); #if 0 /* future plans */ diff --git a/source/blender/gpu/GPU_capabilities.h b/source/blender/gpu/GPU_capabilities.h index 7fe467de402..aa01f446b9b 100644 --- a/source/blender/gpu/GPU_capabilities.h +++ b/source/blender/gpu/GPU_capabilities.h @@ -47,6 +47,7 @@ bool GPU_crappy_amd_driver(void); bool GPU_compute_shader_support(void); bool GPU_shader_storage_buffer_objects_support(void); bool GPU_shader_image_load_store_support(void); +bool GPU_shader_draw_parameters_support(void); bool GPU_mem_stats_supported(void); void GPU_mem_stats_get(int *totalmem, int *freemem); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 1ab06f3369d..51438d7909f 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -228,6 +228,7 @@ void GPU_materials_free(struct Main *bmain); struct Scene *GPU_material_scene(GPUMaterial *material); struct GPUPass *GPU_material_get_pass(GPUMaterial *material); struct GPUShader *GPU_material_get_shader(GPUMaterial *material); +const char *GPU_material_get_name(GPUMaterial *material); /** * Return can be NULL if it's a world material. */ diff --git a/source/blender/gpu/GPU_storage_buffer.h b/source/blender/gpu/GPU_storage_buffer.h index ca6a848786b..8837a7c7647 100644 --- a/source/blender/gpu/GPU_storage_buffer.h +++ b/source/blender/gpu/GPU_storage_buffer.h @@ -48,6 +48,13 @@ void GPU_storagebuf_clear(GPUStorageBuf *ssbo, void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo); /** + * Read back content of the buffer to CPU for inspection. + * Slow! Only use for inspection / debugging. + * NOTE: Not synchronized. Use appropriate barrier before reading. + */ +void GPU_storagebuf_read(GPUStorageBuf *ssbo, void *data); + +/** * \brief Copy a part of a vertex buffer to a storage buffer. * * \param ssbo: destination storage buffer diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 30e890b1591..8b54f4c9822 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -49,7 +49,12 @@ typedef enum eGPUSamplerState { * #GPU_SAMPLER_MAX is not a valid enum value, but only a limit. * It also creates a bad mask for the `NOT` operator in #ENUM_OPERATORS. */ +#ifdef __cplusplus +static constexpr eGPUSamplerState GPU_SAMPLER_MAX = eGPUSamplerState(GPU_SAMPLER_ICON + 1); +#else static const int GPU_SAMPLER_MAX = (GPU_SAMPLER_ICON + 1); +#endif + ENUM_OPERATORS(eGPUSamplerState, GPU_SAMPLER_ICON) #ifdef __cplusplus diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index 0b47a7b2952..9092ad5110c 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -220,6 +220,30 @@ void GPU_batch_set_shader(GPUBatch *batch, GPUShader *shader) /** \name Drawing / Drawcall functions * \{ */ +void GPU_batch_draw_parameter_get( + GPUBatch *gpu_batch, int *r_v_count, int *r_v_first, int *r_base_index, int *r_i_count) +{ + Batch *batch = static_cast<Batch *>(gpu_batch); + + if (batch->elem) { + *r_v_count = batch->elem_()->index_len_get(); + *r_v_first = batch->elem_()->index_start_get(); + *r_base_index = batch->elem_()->index_base_get(); + } + else { + *r_v_count = batch->verts_(0)->vertex_len; + *r_v_first = 0; + *r_base_index = -1; + } + + int i_count = (batch->inst[0]) ? batch->inst_(0)->vertex_len : 1; + /* Meh. This is to be able to use different numbers of verts in instance VBO's. */ + if (batch->inst[1] != nullptr) { + i_count = min_ii(i_count, batch->inst_(1)->vertex_len); + } + *r_i_count = i_count; +} + void GPU_batch_draw(GPUBatch *batch) { GPU_shader_bind(batch->shader); @@ -270,13 +294,23 @@ void GPU_batch_draw_advanced( batch->draw(v_first, v_count, i_first, i_count); } -void GPU_batch_draw_indirect(GPUBatch *gpu_batch, GPUStorageBuf *indirect_buf) +void GPU_batch_draw_indirect(GPUBatch *gpu_batch, GPUStorageBuf *indirect_buf, intptr_t offset) +{ + BLI_assert(Context::get()->shader != nullptr); + BLI_assert(indirect_buf != nullptr); + Batch *batch = static_cast<Batch *>(gpu_batch); + + batch->draw_indirect(indirect_buf, offset); +} + +void GPU_batch_multi_draw_indirect( + GPUBatch *gpu_batch, GPUStorageBuf *indirect_buf, int count, intptr_t offset, intptr_t stride) { BLI_assert(Context::get()->shader != nullptr); BLI_assert(indirect_buf != nullptr); Batch *batch = static_cast<Batch *>(gpu_batch); - batch->draw_indirect(indirect_buf); + batch->multi_draw_indirect(indirect_buf, count, offset, stride); } /** \} */ diff --git a/source/blender/gpu/intern/gpu_batch_private.hh b/source/blender/gpu/intern/gpu_batch_private.hh index 8ca19884fd7..59646925d68 100644 --- a/source/blender/gpu/intern/gpu_batch_private.hh +++ b/source/blender/gpu/intern/gpu_batch_private.hh @@ -29,7 +29,11 @@ class Batch : public GPUBatch { virtual ~Batch() = default; virtual void draw(int v_first, int v_count, int i_first, int i_count) = 0; - virtual void draw_indirect(GPUStorageBuf *indirect_buf) = 0; + virtual void draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) = 0; + virtual void multi_draw_indirect(GPUStorageBuf *indirect_buf, + int count, + intptr_t offset, + intptr_t stride) = 0; /* Convenience casts. */ IndexBuf *elem_() const diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc index 18748627b83..73f94ecfb1b 100644 --- a/source/blender/gpu/intern/gpu_capabilities.cc +++ b/source/blender/gpu/intern/gpu_capabilities.cc @@ -161,6 +161,11 @@ bool GPU_shader_image_load_store_support() return GCaps.shader_image_load_store_support; } +bool GPU_shader_draw_parameters_support() +{ + return GCaps.shader_draw_parameters_support; +} + int GPU_max_shader_storage_buffer_bindings() { return GCaps.max_shader_storage_buffer_bindings; diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh index a17dbe7f8e6..dadd14791e7 100644 --- a/source/blender/gpu/intern/gpu_capabilities_private.hh +++ b/source/blender/gpu/intern/gpu_capabilities_private.hh @@ -44,6 +44,7 @@ struct GPUCapabilities { bool compute_shader_support = false; bool shader_storage_buffer_objects_support = false; bool shader_image_load_store_support = false; + bool shader_draw_parameters_support = false; bool transform_feedback_support = false; /* OpenGL related workarounds. */ diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index 2e1cb6b4a22..b6194c0816f 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -356,21 +356,22 @@ void GPUCodegen::generate_resources() std::stringstream ss; /* Textures. */ + int slot = 0; LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph.textures) { if (tex->colorband) { const char *name = info.name_buffer.append_sampler_name(tex->sampler_name); - info.sampler(0, ImageType::FLOAT_1D_ARRAY, name, Frequency::BATCH); + info.sampler(slot++, ImageType::FLOAT_1D_ARRAY, name, Frequency::BATCH); } else if (tex->tiled_mapping_name[0] != '\0') { const char *name = info.name_buffer.append_sampler_name(tex->sampler_name); - info.sampler(0, ImageType::FLOAT_2D_ARRAY, name, Frequency::BATCH); + info.sampler(slot++, ImageType::FLOAT_2D_ARRAY, name, Frequency::BATCH); const char *name_mapping = info.name_buffer.append_sampler_name(tex->tiled_mapping_name); - info.sampler(0, ImageType::FLOAT_1D_ARRAY, name_mapping, Frequency::BATCH); + info.sampler(slot++, ImageType::FLOAT_1D_ARRAY, name_mapping, Frequency::BATCH); } else { const char *name = info.name_buffer.append_sampler_name(tex->sampler_name); - info.sampler(0, ImageType::FLOAT_2D, name, Frequency::BATCH); + info.sampler(slot++, ImageType::FLOAT_2D, name, Frequency::BATCH); } } @@ -383,7 +384,7 @@ void GPUCodegen::generate_resources() } ss << "};\n\n"; - info.uniform_buf(0, "NodeTree", GPU_UBO_BLOCK_NAME, Frequency::BATCH); + info.uniform_buf(1, "NodeTree", GPU_UBO_BLOCK_NAME, Frequency::BATCH); } if (!BLI_listbase_is_empty(&graph.uniform_attrs.list)) { @@ -395,7 +396,7 @@ void GPUCodegen::generate_resources() /* TODO(fclem): Use the macro for length. Currently not working for EEVEE. */ /* DRW_RESOURCE_CHUNK_LEN = 512 */ - info.uniform_buf(0, "UniformAttrs", GPU_ATTRIBUTE_UBO_BLOCK_NAME "[512]", Frequency::BATCH); + info.uniform_buf(2, "UniformAttrs", GPU_ATTRIBUTE_UBO_BLOCK_NAME "[512]", Frequency::BATCH); } info.typedef_source_generated = ss.str(); diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh index 6ce62ae852e..84903b05273 100644 --- a/source/blender/gpu/intern/gpu_index_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh @@ -70,6 +70,14 @@ class IndexBuf { * They can lead to graphical glitches on some systems. (See T96892) */ return is_empty_ ? 0 : index_len_; } + uint32_t index_start_get() const + { + return index_start_; + } + uint32_t index_base_get() const + { + return index_base_; + } /* Return size in byte of the drawable data buffer range. Actual buffer size might be bigger. */ size_t size_get() const { diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index a4842ef0e43..d9045a041b6 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -91,6 +91,8 @@ struct GPUMaterial { #ifndef NDEBUG char name[64]; +#else + char name[16]; #endif }; @@ -193,6 +195,11 @@ GPUShader *GPU_material_get_shader(GPUMaterial *material) return material->pass ? GPU_pass_shader_get(material->pass) : NULL; } +const char *GPU_material_get_name(GPUMaterial *material) +{ + return material->name; +} + Material *GPU_material_get_material(GPUMaterial *material) { return material->ma; @@ -205,12 +212,7 @@ GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material) void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs) { -#ifndef NDEBUG - const char *name = material->name; -#else - const char *name = "Material"; -#endif - material->ubo = GPU_uniformbuf_create_from_list(inputs, name); + material->ubo = GPU_uniformbuf_create_from_list(inputs, material->name); } ListBase GPU_material_attributes(GPUMaterial *material) @@ -672,11 +674,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, mat->graph.used_libraries = BLI_gset_new( BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries"); mat->refcount = 1; -#ifndef NDEBUG STRNCPY(mat->name, name); -#else - UNUSED_VARS(name); -#endif if (is_lookdev) { mat->flag |= GPU_MATFLAG_LOOKDEV_HACK; } diff --git a/source/blender/gpu/intern/gpu_storage_buffer.cc b/source/blender/gpu/intern/gpu_storage_buffer.cc index afa27da9c85..460a643089c 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer.cc +++ b/source/blender/gpu/intern/gpu_storage_buffer.cc @@ -109,4 +109,9 @@ void GPU_storagebuf_copy_sub_from_vertbuf( unwrap(ssbo)->copy_sub(unwrap(src), dst_offset, src_offset, copy_size); } +void GPU_storagebuf_read(GPUStorageBuf *ssbo, void *data) +{ + unwrap(ssbo)->read(data); +} + /** \} */ diff --git a/source/blender/gpu/intern/gpu_storage_buffer_private.hh b/source/blender/gpu/intern/gpu_storage_buffer_private.hh index 9baec0c2a77..0c96f97ad30 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_storage_buffer_private.hh @@ -44,6 +44,7 @@ class StorageBuf { eGPUDataFormat data_format, void *data) = 0; virtual void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) = 0; + virtual void read(void *data) = 0; }; /* Syntactic sugar. */ diff --git a/source/blender/gpu/metal/mtl_backend.mm b/source/blender/gpu/metal/mtl_backend.mm index 83cf3af0804..a15da4df083 100644 --- a/source/blender/gpu/metal/mtl_backend.mm +++ b/source/blender/gpu/metal/mtl_backend.mm @@ -381,6 +381,8 @@ void MTLBackend::capabilities_init(MTLContext *ctx) GCaps.shader_image_load_store_support = ([device supportsFamily:MTLGPUFamilyApple3] || MTLBackend::capabilities.supports_family_mac1 || MTLBackend::capabilities.supports_family_mac2); + /* TODO(Metal): Add support? */ + GCaps.shader_draw_parameters_support = false; GCaps.compute_shader_support = false; /* TODO(Metal): Add compute support. */ GCaps.shader_storage_buffer_objects_support = false; /* TODO(Metal): implement Storage Buffer support. */ diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 6a1577fb907..24ca8c25bc0 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -227,6 +227,7 @@ static void detect_workarounds() GLContext::unused_fb_slot_workaround = true; /* Turn off extensions. */ GCaps.shader_image_load_store_support = false; + GCaps.shader_draw_parameters_support = false; GCaps.shader_storage_buffer_objects_support = false; GLContext::base_instance_support = false; GLContext::clear_texture_support = false; @@ -271,6 +272,7 @@ static void detect_workarounds() GLContext::unused_fb_slot_workaround = true; GCaps.mip_render_workaround = true; GCaps.shader_image_load_store_support = false; + GCaps.shader_draw_parameters_support = false; GCaps.broken_amd_driver = true; } /* Compute shaders have some issues with those versions (see T94936). */ @@ -284,12 +286,14 @@ static void detect_workarounds() strstr(renderer, "AMD TAHITI"))) { GLContext::unused_fb_slot_workaround = true; GCaps.shader_image_load_store_support = false; + GCaps.shader_draw_parameters_support = false; GCaps.broken_amd_driver = true; } /* Fix slowdown on this particular driver. (see T77641) */ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) && strstr(version, "Mesa 19.3.4")) { GCaps.shader_image_load_store_support = false; + GCaps.shader_draw_parameters_support = false; GCaps.broken_amd_driver = true; } /* See T82856: AMD drivers since 20.11 running on a polaris architecture doesn't support the @@ -492,6 +496,7 @@ void GLBackend::capabilities_init() GCaps.mem_stats_support = epoxy_has_gl_extension("GL_NVX_gpu_memory_info") || epoxy_has_gl_extension("GL_ATI_meminfo"); GCaps.shader_image_load_store_support = epoxy_has_gl_extension("GL_ARB_shader_image_load_store"); + GCaps.shader_draw_parameters_support = epoxy_has_gl_extension("GL_ARB_shader_draw_parameters"); GCaps.compute_shader_support = epoxy_has_gl_extension("GL_ARB_compute_shader") && epoxy_gl_version() >= 43; if (GCaps.compute_shader_support) { diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc index 4ec86b98cbe..ff8867fe3e6 100644 --- a/source/blender/gpu/opengl/gl_batch.cc +++ b/source/blender/gpu/opengl/gl_batch.cc @@ -327,12 +327,13 @@ void GLBatch::draw(int v_first, int v_count, int i_first, int i_count) } } -void GLBatch::draw_indirect(GPUStorageBuf *indirect_buf) +void GLBatch::draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) { GL_CHECK_RESOURCES("Batch"); this->bind(0); + /* TODO(fclem): Make the barrier and binding optional if consecutive draws are issued. */ dynamic_cast<GLStorageBuf *>(unwrap(indirect_buf))->bind_as(GL_DRAW_INDIRECT_BUFFER); /* This barrier needs to be here as it only work on the currently bound indirect buffer. */ glMemoryBarrier(GL_COMMAND_BARRIER_BIT); @@ -341,10 +342,37 @@ void GLBatch::draw_indirect(GPUStorageBuf *indirect_buf) if (elem) { const GLIndexBuf *el = this->elem_(); GLenum index_type = to_gl(el->index_type_); - glDrawElementsIndirect(gl_type, index_type, (GLvoid *)nullptr); + glDrawElementsIndirect(gl_type, index_type, (GLvoid *)offset); } else { - glDrawArraysIndirect(gl_type, (GLvoid *)nullptr); + glDrawArraysIndirect(gl_type, (GLvoid *)offset); + } + /* Unbind. */ + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); +} + +void GLBatch::multi_draw_indirect(GPUStorageBuf *indirect_buf, + int count, + intptr_t offset, + intptr_t stride) +{ + GL_CHECK_RESOURCES("Batch"); + + this->bind(0); + + /* TODO(fclem): Make the barrier and binding optional if consecutive draws are issued. */ + dynamic_cast<GLStorageBuf *>(unwrap(indirect_buf))->bind_as(GL_DRAW_INDIRECT_BUFFER); + /* This barrier needs to be here as it only work on the currently bound indirect buffer. */ + glMemoryBarrier(GL_COMMAND_BARRIER_BIT); + + GLenum gl_type = to_gl(prim_type); + if (elem) { + const GLIndexBuf *el = this->elem_(); + GLenum index_type = to_gl(el->index_type_); + glMultiDrawElementsIndirect(gl_type, index_type, (GLvoid *)offset, count, stride); + } + else { + glMultiDrawArraysIndirect(gl_type, (GLvoid *)offset, count, stride); } /* Unbind. */ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh index 0d7ea7c4a9e..714aa1220be 100644 --- a/source/blender/gpu/opengl/gl_batch.hh +++ b/source/blender/gpu/opengl/gl_batch.hh @@ -91,7 +91,11 @@ class GLBatch : public Batch { public: void draw(int v_first, int v_count, int i_first, int i_count) override; - void draw_indirect(GPUStorageBuf *indirect_buf) override; + void draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) override; + void multi_draw_indirect(GPUStorageBuf *indirect_buf, + int count, + intptr_t offset, + intptr_t stride) override; void bind(int i_first); /* Convenience getters. */ diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc index 83a56edcf04..5d876308b3c 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.cc +++ b/source/blender/gpu/opengl/gl_storage_buffer.cc @@ -166,6 +166,23 @@ void GLStorageBuf::copy_sub(VertBuf *src_, uint dst_offset, uint src_offset, uin } } +void GLStorageBuf::read(void *data) +{ + if (ssbo_id_ == 0) { + this->init(); + } + + if (GLContext::direct_state_access_support) { + glGetNamedBufferSubData(ssbo_id_, 0, size_in_bytes_, data); + } + else { + /* This binds the buffer to GL_ARRAY_BUFFER and upload the data if any. */ + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_); + glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, size_in_bytes_, data); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + } +} + /** \} */ } // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_storage_buffer.hh b/source/blender/gpu/opengl/gl_storage_buffer.hh index ffe2de12451..680ce911bc7 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.hh +++ b/source/blender/gpu/opengl/gl_storage_buffer.hh @@ -35,6 +35,7 @@ class GLStorageBuf : public StorageBuf { void unbind() override; void clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) override; void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override; + void read(void *data) override; /* Special internal function to bind SSBOs to indirect argument targets. */ void bind_as(GLenum target); diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_mix_color.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_mix_color.glsl new file mode 100644 index 00000000000..933a8de9cb7 --- /dev/null +++ b/source/blender/gpu/shaders/material/gpu_shader_material_mix_color.glsl @@ -0,0 +1,537 @@ +#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl) + +void node_mix_blend(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + outcol = mix(col1, col2, fac); + outcol.a = col1.a; +} + +void node_mix_add(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outcol = mix(col1, col1 + col2, fac); + outcol.a = col1.a; +} + +void node_mix_mult(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outcol = mix(col1, col1 * col2, fac); + outcol.a = col1.a; +} + +void node_mix_screen(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + outcol = vec4(1.0) - (vec4(facm) + fac * (vec4(1.0) - col2)) * (vec4(1.0) - col1); + outcol.a = col1.a; +} + +void node_mix_overlay(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + outcol = col1; + + if (outcol.r < 0.5) { + outcol.r *= facm + 2.0 * fac * col2.r; + } + else { + outcol.r = 1.0 - (facm + 2.0 * fac * (1.0 - col2.r)) * (1.0 - outcol.r); + } + + if (outcol.g < 0.5) { + outcol.g *= facm + 2.0 * fac * col2.g; + } + else { + outcol.g = 1.0 - (facm + 2.0 * fac * (1.0 - col2.g)) * (1.0 - outcol.g); + } + + if (outcol.b < 0.5) { + outcol.b *= facm + 2.0 * fac * col2.b; + } + else { + outcol.b = 1.0 - (facm + 2.0 * fac * (1.0 - col2.b)) * (1.0 - outcol.b); + } +} + +void node_mix_sub(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outcol = mix(col1, col1 - col2, fac); + outcol.a = col1.a; +} + +/* A variant of mix_div that fallback to the first color upon zero division. */ +void node_mix_div_fallback(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + outcol = col1; + + if (col2.r != 0.0) { + outcol.r = facm * outcol.r + fac * outcol.r / col2.r; + } + if (col2.g != 0.0) { + outcol.g = facm * outcol.g + fac * outcol.g / col2.g; + } + if (col2.b != 0.0) { + outcol.b = facm * outcol.b + fac * outcol.b / col2.b; + } +} + +void node_mix_diff(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outcol = mix(col1, abs(col1 - col2), fac); + outcol.a = col1.a; +} + +void node_mix_dark(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outcol.rgb = mix(col1.rgb, min(col1.rgb, col2.rgb), fac); + outcol.a = col1.a; +} + +void node_mix_light(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + outcol.rgb = mix(col1.rgb, max(col1.rgb, col2.rgb), fac); + outcol.a = col1.a; +} + +void node_mix_dodge(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + outcol = col1; + + if (outcol.r != 0.0) { + float tmp = 1.0 - fac * col2.r; + if (tmp <= 0.0) { + outcol.r = 1.0; + } + else if ((tmp = outcol.r / tmp) > 1.0) { + outcol.r = 1.0; + } + else { + outcol.r = tmp; + } + } + if (outcol.g != 0.0) { + float tmp = 1.0 - fac * col2.g; + if (tmp <= 0.0) { + outcol.g = 1.0; + } + else if ((tmp = outcol.g / tmp) > 1.0) { + outcol.g = 1.0; + } + else { + outcol.g = tmp; + } + } + if (outcol.b != 0.0) { + float tmp = 1.0 - fac * col2.b; + if (tmp <= 0.0) { + outcol.b = 1.0; + } + else if ((tmp = outcol.b / tmp) > 1.0) { + outcol.b = 1.0; + } + else { + outcol.b = tmp; + } + } +} + +void node_mix_burn(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float tmp, facm = 1.0 - fac; + + outcol = col1; + + tmp = facm + fac * col2.r; + if (tmp <= 0.0) { + outcol.r = 0.0; + } + else if ((tmp = (1.0 - (1.0 - outcol.r) / tmp)) < 0.0) { + outcol.r = 0.0; + } + else if (tmp > 1.0) { + outcol.r = 1.0; + } + else { + outcol.r = tmp; + } + + tmp = facm + fac * col2.g; + if (tmp <= 0.0) { + outcol.g = 0.0; + } + else if ((tmp = (1.0 - (1.0 - outcol.g) / tmp)) < 0.0) { + outcol.g = 0.0; + } + else if (tmp > 1.0) { + outcol.g = 1.0; + } + else { + outcol.g = tmp; + } + + tmp = facm + fac * col2.b; + if (tmp <= 0.0) { + outcol.b = 0.0; + } + else if ((tmp = (1.0 - (1.0 - outcol.b) / tmp)) < 0.0) { + outcol.b = 0.0; + } + else if (tmp > 1.0) { + outcol.b = 1.0; + } + else { + outcol.b = tmp; + } +} + +void node_mix_hue(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + outcol = col1; + + vec4 hsv, hsv2, tmp; + rgb_to_hsv(col2, hsv2); + + if (hsv2.y != 0.0) { + rgb_to_hsv(outcol, hsv); + hsv.x = hsv2.x; + hsv_to_rgb(hsv, tmp); + + outcol = mix(outcol, tmp, fac); + outcol.a = col1.a; + } +} + +void node_mix_sat(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + outcol = col1; + + vec4 hsv, hsv2; + rgb_to_hsv(outcol, hsv); + + if (hsv.y != 0.0) { + rgb_to_hsv(col2, hsv2); + + hsv.y = facm * hsv.y + fac * hsv2.y; + hsv_to_rgb(hsv, outcol); + } +} + +void node_mix_val(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + vec4 hsv, hsv2; + rgb_to_hsv(col1, hsv); + rgb_to_hsv(col2, hsv2); + + hsv.z = facm * hsv.z + fac * hsv2.z; + hsv_to_rgb(hsv, outcol); +} + +void node_mix_color(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + outcol = col1; + + vec4 hsv, hsv2, tmp; + rgb_to_hsv(col2, hsv2); + + if (hsv2.y != 0.0) { + rgb_to_hsv(outcol, hsv); + hsv.x = hsv2.x; + hsv.y = hsv2.y; + hsv_to_rgb(hsv, tmp); + + outcol = mix(outcol, tmp, fac); + outcol.a = col1.a; + } +} + +void node_mix_soft(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + float facm = 1.0 - fac; + + vec4 one = vec4(1.0); + vec4 scr = one - (one - col2) * (one - col1); + outcol = facm * col1 + fac * ((one - col1) * col2 * col1 + col1 * scr); +} + +void node_mix_linear(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outcol = col1 + fac * (2.0 * (col2 - vec4(0.5))); +} + +void node_mix_float(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outfloat = mix(f1, f2, fac); +} + +void node_mix_vector(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + + outvec = mix(v1, v2, fac); +} + +void node_mix_vector_non_uniform(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + outvec = mix(v1, v2, facvec); +} + +void node_mix_rgba(float fac, + vec3 facvec, + float f1, + float f2, + vec3 v1, + vec3 v2, + vec4 col1, + vec4 col2, + out float outfloat, + out vec3 outvec, + out vec4 outcol) +{ + outcol = mix(col1, col2, fac); +} + +void node_mix_clamp_vector(vec3 vec, vec3 min, vec3 max, out vec3 outvec) +{ + outvec = clamp(vec, min, max); +} + +void node_mix_clamp_value(float value, float min, float max, out float outfloat) +{ + outfloat = clamp(value, min, max); +} diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index 2820a128072..9c71944fc92 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -540,7 +540,7 @@ void read_generated_coordinates(const ICompoundProperty &prop, cd_data = CustomData_get_layer(&mesh->vdata, CD_ORCO); } else { - cd_data = CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_CALLOC, nullptr, totvert); + cd_data = CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_CONSTRUCT, nullptr, totvert); } float(*orcodata)[3] = static_cast<float(*)[3]>(cd_data); diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index 2253880d5ca..16e5ee968a3 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -391,7 +391,7 @@ static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type) /* Create a new layer. */ int numloops = mesh->totloop; cd_ptr = CustomData_add_layer_named( - &mesh->ldata, cd_data_type, CD_DEFAULT, nullptr, numloops, name); + &mesh->ldata, cd_data_type, CD_SET_DEFAULT, nullptr, numloops, name); return cd_ptr; } @@ -896,7 +896,7 @@ static void read_vertex_creases(Mesh *mesh, } float *vertex_crease_data = (float *)CustomData_add_layer( - &mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert); + &mesh->vdata, CD_CREASE, CD_SET_DEFAULT, nullptr, mesh->totvert); const int totvert = mesh->totvert; for (int i = 0, v = indices->size(); i < v; ++i) { diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp index b40546dfd97..fab53908d5a 100644 --- a/source/blender/io/collada/MeshImporter.cpp +++ b/source/blender/io/collada/MeshImporter.cpp @@ -341,7 +341,8 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me) } me->totvert = pos.getFloatValues()->getCount() / stride; - me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, me->totvert); + me->mvert = (MVert *)CustomData_add_layer( + &me->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, me->totvert); MVert *mvert; int i; @@ -449,9 +450,9 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) me->totpoly = total_poly_count; me->totloop = total_loop_count; me->mpoly = (MPoly *)CustomData_add_layer( - &me->pdata, CD_MPOLY, CD_CALLOC, nullptr, me->totpoly); + &me->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, me->totpoly); me->mloop = (MLoop *)CustomData_add_layer( - &me->ldata, CD_MLOOP, CD_CALLOC, nullptr, me->totloop); + &me->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, me->totloop); unsigned int totuvset = collada_mesh->getUVCoords().getInputInfosArray().getCount(); for (int i = 0; i < totuvset; i++) { @@ -468,7 +469,7 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) COLLADAFW::String &uvname = info->mName; /* Allocate space for UV_data */ CustomData_add_layer_named( - &me->ldata, CD_MLOOPUV, CD_DEFAULT, nullptr, me->totloop, uvname.c_str()); + &me->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, me->totloop, uvname.c_str()); } /* activate the first uv map */ me->mloopuv = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, 0); @@ -481,7 +482,7 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) collada_mesh->getColors().getInputInfosArray()[i]; COLLADAFW::String colname = extract_vcolname(info->mName); CustomData_add_layer_named( - &me->ldata, CD_PROP_BYTE_COLOR, CD_DEFAULT, nullptr, me->totloop, colname.c_str()); + &me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, me->totloop, colname.c_str()); } me->mloopcol = (MLoopCol *)CustomData_get_layer_n(&me->ldata, CD_PROP_BYTE_COLOR, 0); } @@ -546,11 +547,11 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len) totedge = mesh->totedge + len; /* Update custom-data. */ - CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge); + CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge); CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) { - CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge); + CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, totedge); } CustomData_free(&mesh->edata, mesh->totedge); @@ -615,7 +616,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me) MaterialIdPrimitiveArrayMap mat_prim_map; int *material_indices = (int *)CustomData_add_layer_named( - &me->pdata, CD_PROP_INT32, CD_DEFAULT, nullptr, me->totpoly, "material_index"); + &me->pdata, CD_PROP_INT32, CD_SET_DEFAULT, nullptr, me->totpoly, "material_index"); COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives(); COLLADAFW::MeshVertexData &nor = collada_mesh->getNormals(); diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc index b9ed441f0d9..178b5b9347f 100644 --- a/source/blender/io/stl/importer/stl_import_mesh.cc +++ b/source/blender/io/stl/importer/stl_import_mesh.cc @@ -77,7 +77,7 @@ Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) mesh->totvert = verts_.size(); mesh->mvert = static_cast<MVert *>( - CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert)); + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, mesh->totvert)); for (int i = 0; i < mesh->totvert; i++) { copy_v3_v3(mesh->mvert[i].co, verts_[i]); } @@ -85,9 +85,9 @@ Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) mesh->totpoly = tris_.size(); mesh->totloop = tris_.size() * 3; mesh->mpoly = static_cast<MPoly *>( - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly)); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly)); mesh->mloop = static_cast<MLoop *>( - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop)); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CONSTRUCT, nullptr, mesh->totloop)); threading::parallel_for(tris_.index_range(), 2048, [&](IndexRange tris_range) { for (const int i : tris_range) { diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index 73a65bafc85..89a98097780 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -208,7 +208,8 @@ static void *add_customdata_cb(Mesh *mesh, const char *name, const int data_type /* Create a new layer. */ numloops = mesh->totloop; - cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, nullptr, numloops, name); + cd_ptr = CustomData_add_layer_named( + loopdata, cd_data_type, CD_SET_DEFAULT, nullptr, numloops, name); return cd_ptr; } @@ -576,7 +577,7 @@ void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTim } float *creases = static_cast<float *>( - CustomData_add_layer(&mesh->vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh->totvert)); + CustomData_add_layer(&mesh->vdata, CD_CREASE, CD_SET_DEFAULT, nullptr, mesh->totvert)); for (size_t i = 0; i < corner_indices.size(); i++) { creases[corner_indices[i]] = corner_sharpnesses[i]; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc index 4c3d52131b7..902f801ee5b 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -44,7 +44,7 @@ static const char *DEFORM_GROUP_DISABLED = "off"; * So an empty material name is written. */ static const char *MATERIAL_GROUP_DISABLED = ""; -void OBJWriter::write_vert_uv_normal_indices(FormatHandler<eFileType::OBJ> &fh, +void OBJWriter::write_vert_uv_normal_indices(FormatHandler &fh, const IndexOffsets &offsets, Span<int> vert_indices, Span<int> uv_indices, @@ -57,12 +57,12 @@ void OBJWriter::write_vert_uv_normal_indices(FormatHandler<eFileType::OBJ> &fh, const int uv_offset = offsets.uv_vertex_offset + 1; const int normal_offset = offsets.normal_offset + 1; const int n = vert_indices.size(); - fh.write<eOBJSyntaxElement::poly_element_begin>(); + fh.write_obj_poly_begin(); if (!flip) { for (int j = 0; j < n; ++j) { - fh.write<eOBJSyntaxElement::vertex_uv_normal_indices>(vert_indices[j] + vertex_offset, - uv_indices[j] + uv_offset, - normal_indices[j] + normal_offset); + fh.write_obj_poly_v_uv_normal(vert_indices[j] + vertex_offset, + uv_indices[j] + uv_offset, + normal_indices[j] + normal_offset); } } else { @@ -71,15 +71,15 @@ void OBJWriter::write_vert_uv_normal_indices(FormatHandler<eFileType::OBJ> &fh, * then go backwards. Same logic in other write_*_indices functions below. */ for (int k = 0; k < n; ++k) { int j = k == 0 ? 0 : n - k; - fh.write<eOBJSyntaxElement::vertex_uv_normal_indices>(vert_indices[j] + vertex_offset, - uv_indices[j] + uv_offset, - normal_indices[j] + normal_offset); + fh.write_obj_poly_v_uv_normal(vert_indices[j] + vertex_offset, + uv_indices[j] + uv_offset, + normal_indices[j] + normal_offset); } } - fh.write<eOBJSyntaxElement::poly_element_end>(); + fh.write_obj_poly_end(); } -void OBJWriter::write_vert_normal_indices(FormatHandler<eFileType::OBJ> &fh, +void OBJWriter::write_vert_normal_indices(FormatHandler &fh, const IndexOffsets &offsets, Span<int> vert_indices, Span<int> /*uv_indices*/, @@ -90,24 +90,24 @@ void OBJWriter::write_vert_normal_indices(FormatHandler<eFileType::OBJ> &fh, const int vertex_offset = offsets.vertex_offset + 1; const int normal_offset = offsets.normal_offset + 1; const int n = vert_indices.size(); - fh.write<eOBJSyntaxElement::poly_element_begin>(); + fh.write_obj_poly_begin(); if (!flip) { for (int j = 0; j < n; ++j) { - fh.write<eOBJSyntaxElement::vertex_normal_indices>(vert_indices[j] + vertex_offset, - normal_indices[j] + normal_offset); + fh.write_obj_poly_v_normal(vert_indices[j] + vertex_offset, + normal_indices[j] + normal_offset); } } else { for (int k = 0; k < n; ++k) { int j = k == 0 ? 0 : n - k; - fh.write<eOBJSyntaxElement::vertex_normal_indices>(vert_indices[j] + vertex_offset, - normal_indices[j] + normal_offset); + fh.write_obj_poly_v_normal(vert_indices[j] + vertex_offset, + normal_indices[j] + normal_offset); } } - fh.write<eOBJSyntaxElement::poly_element_end>(); + fh.write_obj_poly_end(); } -void OBJWriter::write_vert_uv_indices(FormatHandler<eFileType::OBJ> &fh, +void OBJWriter::write_vert_uv_indices(FormatHandler &fh, const IndexOffsets &offsets, Span<int> vert_indices, Span<int> uv_indices, @@ -118,24 +118,22 @@ void OBJWriter::write_vert_uv_indices(FormatHandler<eFileType::OBJ> &fh, const int vertex_offset = offsets.vertex_offset + 1; const int uv_offset = offsets.uv_vertex_offset + 1; const int n = vert_indices.size(); - fh.write<eOBJSyntaxElement::poly_element_begin>(); + fh.write_obj_poly_begin(); if (!flip) { for (int j = 0; j < n; ++j) { - fh.write<eOBJSyntaxElement::vertex_uv_indices>(vert_indices[j] + vertex_offset, - uv_indices[j] + uv_offset); + fh.write_obj_poly_v_uv(vert_indices[j] + vertex_offset, uv_indices[j] + uv_offset); } } else { for (int k = 0; k < n; ++k) { int j = k == 0 ? 0 : n - k; - fh.write<eOBJSyntaxElement::vertex_uv_indices>(vert_indices[j] + vertex_offset, - uv_indices[j] + uv_offset); + fh.write_obj_poly_v_uv(vert_indices[j] + vertex_offset, uv_indices[j] + uv_offset); } } - fh.write<eOBJSyntaxElement::poly_element_end>(); + fh.write_obj_poly_end(); } -void OBJWriter::write_vert_indices(FormatHandler<eFileType::OBJ> &fh, +void OBJWriter::write_vert_indices(FormatHandler &fh, const IndexOffsets &offsets, Span<int> vert_indices, Span<int> /*uv_indices*/, @@ -144,27 +142,27 @@ void OBJWriter::write_vert_indices(FormatHandler<eFileType::OBJ> &fh, { const int vertex_offset = offsets.vertex_offset + 1; const int n = vert_indices.size(); - fh.write<eOBJSyntaxElement::poly_element_begin>(); + fh.write_obj_poly_begin(); if (!flip) { for (int j = 0; j < n; ++j) { - fh.write<eOBJSyntaxElement::vertex_indices>(vert_indices[j] + vertex_offset); + fh.write_obj_poly_v(vert_indices[j] + vertex_offset); } } else { for (int k = 0; k < n; ++k) { int j = k == 0 ? 0 : n - k; - fh.write<eOBJSyntaxElement::vertex_indices>(vert_indices[j] + vertex_offset); + fh.write_obj_poly_v(vert_indices[j] + vertex_offset); } } - fh.write<eOBJSyntaxElement::poly_element_end>(); + fh.write_obj_poly_end(); } void OBJWriter::write_header() const { using namespace std::string_literals; - FormatHandler<eFileType::OBJ> fh; - fh.write<eOBJSyntaxElement::string>("# Blender "s + BKE_blender_version_string() + "\n"); - fh.write<eOBJSyntaxElement::string>("# www.blender.org\n"); + FormatHandler fh; + fh.write_string("# Blender "s + BKE_blender_version_string()); + fh.write_string("# www.blender.org"); fh.write_to_file(outfile_); } @@ -174,8 +172,8 @@ void OBJWriter::write_mtllib_name(const StringRefNull mtl_filepath) const char mtl_file_name[FILE_MAXFILE]; char mtl_dir_name[FILE_MAXDIR]; BLI_split_dirfile(mtl_filepath.data(), mtl_dir_name, mtl_file_name, FILE_MAXDIR, FILE_MAXFILE); - FormatHandler<eFileType::OBJ> fh; - fh.write<eOBJSyntaxElement::mtllib>(mtl_file_name); + FormatHandler fh; + fh.write_obj_mtllib(mtl_file_name); fh.write_to_file(outfile_); } @@ -184,18 +182,17 @@ static void spaces_to_underscores(std::string &r_name) std::replace(r_name.begin(), r_name.end(), ' ', '_'); } -void OBJWriter::write_object_name(FormatHandler<eFileType::OBJ> &fh, - const OBJMesh &obj_mesh_data) const +void OBJWriter::write_object_name(FormatHandler &fh, const OBJMesh &obj_mesh_data) const { std::string object_name = obj_mesh_data.get_object_name(); spaces_to_underscores(object_name); if (export_params_.export_object_groups) { std::string mesh_name = obj_mesh_data.get_object_mesh_name(); spaces_to_underscores(mesh_name); - fh.write<eOBJSyntaxElement::object_group>(object_name + "_" + mesh_name); + fh.write_obj_group(object_name + "_" + mesh_name); return; } - fh.write<eOBJSyntaxElement::object_name>(object_name); + fh.write_obj_object(object_name); } /* Split up large meshes into multi-threaded jobs; each job processes @@ -213,9 +210,7 @@ static int calc_chunk_count(int count) * will be written into the final /fh/ buffer at the end. */ template<typename Function> -void obj_parallel_chunked_output(FormatHandler<eFileType::OBJ> &fh, - int tot_count, - const Function &function) +void obj_parallel_chunked_output(FormatHandler &fh, int tot_count, const Function &function) { if (tot_count <= 0) { return; @@ -231,7 +226,7 @@ void obj_parallel_chunked_output(FormatHandler<eFileType::OBJ> &fh, return; } /* Give each chunk its own temporary output buffer, and process them in parallel. */ - std::vector<FormatHandler<eFileType::OBJ>> buffers(chunk_count); + std::vector<FormatHandler> buffers(chunk_count); blender::threading::parallel_for(IndexRange(chunk_count), 1, [&](IndexRange range) { for (const int r : range) { int i_start = r * chunk_size; @@ -248,7 +243,7 @@ void obj_parallel_chunked_output(FormatHandler<eFileType::OBJ> &fh, } } -void OBJWriter::write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, +void OBJWriter::write_vertex_coords(FormatHandler &fh, const OBJMesh &obj_mesh_data, bool write_colors) const { @@ -265,41 +260,40 @@ void OBJWriter::write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, colors_layer->name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f}); BLI_assert(tot_count == attribute.size()); - obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) { + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); ColorGeometry4f linear = attribute.get(i); float srgb[3]; linearrgb_to_srgb_v3_v3(srgb, linear); - buf.write<eOBJSyntaxElement::vertex_coords_color>( - vertex[0], vertex[1], vertex[2], srgb[0], srgb[1], srgb[2]); + buf.write_obj_vertex_color(vertex[0], vertex[1], vertex[2], srgb[0], srgb[1], srgb[2]); }); } else { - obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) { + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); - buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]); + buf.write_obj_vertex(vertex[0], vertex[1], vertex[2]); }); } } -void OBJWriter::write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &r_obj_mesh_data) const +void OBJWriter::write_uv_coords(FormatHandler &fh, OBJMesh &r_obj_mesh_data) const { const Vector<float2> &uv_coords = r_obj_mesh_data.get_uv_coords(); const int tot_count = uv_coords.size(); - obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) { + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { const float2 &uv_vertex = uv_coords[i]; - buf.write<eOBJSyntaxElement::uv_vertex_coords>(uv_vertex[0], uv_vertex[1]); + buf.write_obj_uv(uv_vertex[0], uv_vertex[1]); }); } -void OBJWriter::write_poly_normals(FormatHandler<eFileType::OBJ> &fh, OBJMesh &obj_mesh_data) +void OBJWriter::write_poly_normals(FormatHandler &fh, OBJMesh &obj_mesh_data) { /* Poly normals should be calculated earlier via store_normal_coords_and_indices. */ const Vector<float3> &normal_coords = obj_mesh_data.get_normal_coords(); const int tot_count = normal_coords.size(); - obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) { + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler &buf, int i) { const float3 &normal = normal_coords[i]; - buf.write<eOBJSyntaxElement::normal>(normal[0], normal[1], normal[2]); + buf.write_obj_normal(normal[0], normal[1], normal[2]); }); } @@ -334,7 +328,7 @@ static int get_smooth_group(const OBJMesh &mesh, const OBJExportParams ¶ms, return group; } -void OBJWriter::write_poly_elements(FormatHandler<eFileType::OBJ> &fh, +void OBJWriter::write_poly_elements(FormatHandler &fh, const IndexOffsets &offsets, const OBJMesh &obj_mesh_data, std::function<const char *(int)> matname_fn) @@ -346,7 +340,7 @@ void OBJWriter::write_poly_elements(FormatHandler<eFileType::OBJ> &fh, const int tot_deform_groups = obj_mesh_data.tot_deform_groups(); threading::EnumerableThreadSpecific<Vector<float>> group_weights; - obj_parallel_chunked_output(fh, tot_polygons, [&](FormatHandler<eFileType::OBJ> &buf, int idx) { + obj_parallel_chunked_output(fh, tot_polygons, [&](FormatHandler &buf, int idx) { /* Polygon order for writing into the file is not necessarily the same * as order in the mesh; it will be sorted by material indices. Remap current * and previous indices here according to the order. */ @@ -362,7 +356,7 @@ void OBJWriter::write_poly_elements(FormatHandler<eFileType::OBJ> &fh, const int prev_group = get_smooth_group(obj_mesh_data, export_params_, prev_i); const int group = get_smooth_group(obj_mesh_data, export_params_, i); if (group != prev_group) { - buf.write<eOBJSyntaxElement::smooth_group>(group); + buf.write_obj_smooth(group); } } @@ -375,9 +369,8 @@ void OBJWriter::write_poly_elements(FormatHandler<eFileType::OBJ> &fh, prev_i, local_weights); const int16_t group = obj_mesh_data.get_poly_deform_group_index(i, local_weights); if (group != prev_group) { - buf.write<eOBJSyntaxElement::object_group>( - group == NOT_FOUND ? DEFORM_GROUP_DISABLED : - obj_mesh_data.get_poly_deform_group_name(group)); + buf.write_obj_group(group == NOT_FOUND ? DEFORM_GROUP_DISABLED : + obj_mesh_data.get_poly_deform_group_name(group)); } } @@ -391,7 +384,7 @@ void OBJWriter::write_poly_elements(FormatHandler<eFileType::OBJ> &fh, const int16_t mat = std::max(0, material_indices[i]); if (mat != prev_mat) { if (mat == NOT_FOUND) { - buf.write<eOBJSyntaxElement::poly_usemtl>(MATERIAL_GROUP_DISABLED); + buf.write_obj_usemtl(MATERIAL_GROUP_DISABLED); } else { const char *mat_name = matname_fn(mat); @@ -401,9 +394,9 @@ void OBJWriter::write_poly_elements(FormatHandler<eFileType::OBJ> &fh, if (export_params_.export_material_groups) { std::string object_name = obj_mesh_data.get_object_name(); spaces_to_underscores(object_name); - fh.write<eOBJSyntaxElement::object_group>(object_name + "_" + mat_name); + fh.write_obj_group(object_name + "_" + mat_name); } - buf.write<eOBJSyntaxElement::poly_usemtl>(mat_name); + buf.write_obj_usemtl(mat_name); } } } @@ -418,7 +411,7 @@ void OBJWriter::write_poly_elements(FormatHandler<eFileType::OBJ> &fh, }); } -void OBJWriter::write_edges_indices(FormatHandler<eFileType::OBJ> &fh, +void OBJWriter::write_edges_indices(FormatHandler &fh, const IndexOffsets &offsets, const OBJMesh &obj_mesh_data) const { @@ -430,13 +423,12 @@ void OBJWriter::write_edges_indices(FormatHandler<eFileType::OBJ> &fh, if (!vertex_indices) { continue; } - fh.write<eOBJSyntaxElement::edge>((*vertex_indices)[0] + offsets.vertex_offset + 1, - (*vertex_indices)[1] + offsets.vertex_offset + 1); + fh.write_obj_edge((*vertex_indices)[0] + offsets.vertex_offset + 1, + (*vertex_indices)[1] + offsets.vertex_offset + 1); } } -void OBJWriter::write_nurbs_curve(FormatHandler<eFileType::OBJ> &fh, - const OBJCurve &obj_nurbs_data) const +void OBJWriter::write_nurbs_curve(FormatHandler &fh, const OBJCurve &obj_nurbs_data) const { const int total_splines = obj_nurbs_data.total_splines(); for (int spline_idx = 0; spline_idx < total_splines; spline_idx++) { @@ -444,15 +436,14 @@ void OBJWriter::write_nurbs_curve(FormatHandler<eFileType::OBJ> &fh, for (int vertex_idx = 0; vertex_idx < total_vertices; vertex_idx++) { const float3 vertex_coords = obj_nurbs_data.vertex_coordinates( spline_idx, vertex_idx, export_params_.scaling_factor); - fh.write<eOBJSyntaxElement::vertex_coords>( - vertex_coords[0], vertex_coords[1], vertex_coords[2]); + fh.write_obj_vertex(vertex_coords[0], vertex_coords[1], vertex_coords[2]); } const char *nurbs_name = obj_nurbs_data.get_curve_name(); const int nurbs_degree = obj_nurbs_data.get_nurbs_degree(spline_idx); - fh.write<eOBJSyntaxElement::object_group>(nurbs_name); - fh.write<eOBJSyntaxElement::cstype>(); - fh.write<eOBJSyntaxElement::nurbs_degree>(nurbs_degree); + fh.write_obj_group(nurbs_name); + fh.write_obj_cstype(); + fh.write_obj_nurbs_degree(nurbs_degree); /** * The numbers written here are indices into the vertex coordinates written * earlier, relative to the line that is going to be written. @@ -461,13 +452,13 @@ void OBJWriter::write_nurbs_curve(FormatHandler<eFileType::OBJ> &fh, * 0.0 1.0 -1 -2 -3 -4 -1 -2 -3 for a cyclic curve with 4 vertices. */ const int total_control_points = obj_nurbs_data.total_spline_control_points(spline_idx); - fh.write<eOBJSyntaxElement::curve_element_begin>(); + fh.write_obj_curve_begin(); for (int i = 0; i < total_control_points; i++) { /* "+1" to keep indices one-based, even if they're negative: i.e., -1 refers to the * last vertex coordinate, -2 second last. */ - fh.write<eOBJSyntaxElement::vertex_indices>(-((i % total_vertices) + 1)); + fh.write_obj_poly_v(-((i % total_vertices) + 1)); } - fh.write<eOBJSyntaxElement::curve_element_end>(); + fh.write_obj_curve_end(); /** * In `parm u 0 0.1 ..` line:, (total control points + 2) equidistant numbers in the @@ -478,7 +469,7 @@ void OBJWriter::write_nurbs_curve(FormatHandler<eFileType::OBJ> &fh, const short flagsu = obj_nurbs_data.get_nurbs_flagu(spline_idx); const bool cyclic = flagsu & CU_NURB_CYCLIC; const bool endpoint = !cyclic && (flagsu & CU_NURB_ENDPOINT); - fh.write<eOBJSyntaxElement::nurbs_parameter_begin>(); + fh.write_obj_nurbs_parm_begin(); for (int i = 1; i <= total_control_points + 2; i++) { float parm = 1.0f * i / (total_control_points + 2 + 1); if (endpoint) { @@ -489,11 +480,10 @@ void OBJWriter::write_nurbs_curve(FormatHandler<eFileType::OBJ> &fh, parm = 1; } } - fh.write<eOBJSyntaxElement::nurbs_parameters>(parm); + fh.write_obj_nurbs_parm(parm); } - fh.write<eOBJSyntaxElement::nurbs_parameter_end>(); - - fh.write<eOBJSyntaxElement::nurbs_group_end>(); + fh.write_obj_nurbs_parm_end(); + fh.write_obj_nurbs_group_end(); } } @@ -501,6 +491,18 @@ void OBJWriter::write_nurbs_curve(FormatHandler<eFileType::OBJ> &fh, /** \name .MTL writers. * \{ */ +static const char *tex_map_type_to_string[] = { + "map_Kd", + "map_Ks", + "map_Ns", + "map_d", + "map_refl", + "map_Ke", + "map_Bump", +}; +BLI_STATIC_ASSERT(ARRAY_SIZE(tex_map_type_to_string) == (int)MTLTexMapType::Count, + "array size mismatch"); + /** * Convert #float3 to string of space-separated numbers, with no leading or trailing space. * Only to be used in NON-performance-critical code. @@ -541,9 +543,9 @@ void MTLWriter::write_header(const char *blen_filepath) const char *blen_basename = (blen_filepath && blen_filepath[0] != '\0') ? BLI_path_basename(blen_filepath) : "None"; - fmt_handler_.write<eMTLSyntaxElement::string>("# Blender "s + BKE_blender_version_string() + - " MTL File: '" + blen_basename + "'\n"); - fmt_handler_.write<eMTLSyntaxElement::string>("# www.blender.org\n"); + fmt_handler_.write_string("# Blender "s + BKE_blender_version_string() + " MTL File: '" + + blen_basename + "'"); + fmt_handler_.write_string("# www.blender.org"); } StringRefNull MTLWriter::mtl_file_path() const @@ -556,67 +558,52 @@ void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl) /* For various material properties, we only capture information * coming from the texture, or the default value of the socket. * When the texture is present, do not emit the default value. */ - if (!mtl.tex_map_of_type(eMTLSyntaxElement::map_Ns).is_valid()) { - fmt_handler_.write<eMTLSyntaxElement::Ns>(mtl.Ns); + if (!mtl.tex_map_of_type(MTLTexMapType::Ns).is_valid()) { + fmt_handler_.write_mtl_float("Ns", mtl.Ns); } - fmt_handler_.write<eMTLSyntaxElement::Ka>(mtl.Ka.x, mtl.Ka.y, mtl.Ka.z); - if (!mtl.tex_map_of_type(eMTLSyntaxElement::map_Kd).is_valid()) { - fmt_handler_.write<eMTLSyntaxElement::Kd>(mtl.Kd.x, mtl.Kd.y, mtl.Kd.z); + fmt_handler_.write_mtl_float3("Ka", mtl.Ka.x, mtl.Ka.y, mtl.Ka.z); + if (!mtl.tex_map_of_type(MTLTexMapType::Kd).is_valid()) { + fmt_handler_.write_mtl_float3("Kd", mtl.Kd.x, mtl.Kd.y, mtl.Kd.z); } - if (!mtl.tex_map_of_type(eMTLSyntaxElement::map_Ks).is_valid()) { - fmt_handler_.write<eMTLSyntaxElement::Ks>(mtl.Ks.x, mtl.Ks.y, mtl.Ks.z); + if (!mtl.tex_map_of_type(MTLTexMapType::Ks).is_valid()) { + fmt_handler_.write_mtl_float3("Ks", mtl.Ks.x, mtl.Ks.y, mtl.Ks.z); } - if (!mtl.tex_map_of_type(eMTLSyntaxElement::map_Ke).is_valid()) { - fmt_handler_.write<eMTLSyntaxElement::Ke>(mtl.Ke.x, mtl.Ke.y, mtl.Ke.z); + if (!mtl.tex_map_of_type(MTLTexMapType::Ke).is_valid()) { + fmt_handler_.write_mtl_float3("Ke", mtl.Ke.x, mtl.Ke.y, mtl.Ke.z); } - fmt_handler_.write<eMTLSyntaxElement::Ni>(mtl.Ni); - if (!mtl.tex_map_of_type(eMTLSyntaxElement::map_d).is_valid()) { - fmt_handler_.write<eMTLSyntaxElement::d>(mtl.d); + fmt_handler_.write_mtl_float("Ni", mtl.Ni); + if (!mtl.tex_map_of_type(MTLTexMapType::d).is_valid()) { + fmt_handler_.write_mtl_float("d", mtl.d); } - fmt_handler_.write<eMTLSyntaxElement::illum>(mtl.illum); + fmt_handler_.write_mtl_illum(mtl.illum); } -void MTLWriter::write_texture_map( - const MTLMaterial &mtl_material, - const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map, - const char *blen_filedir, - const char *dest_dir, - ePathReferenceMode path_mode, - Set<std::pair<std::string, std::string>> ©_set) +void MTLWriter::write_texture_map(const MTLMaterial &mtl_material, + MTLTexMapType texture_key, + const MTLTexMap &texture_map, + const char *blen_filedir, + const char *dest_dir, + ePathReferenceMode path_mode, + Set<std::pair<std::string, std::string>> ©_set) { std::string options; /* Option strings should have their own leading spaces. */ - if (texture_map.value.translation != float3{0.0f, 0.0f, 0.0f}) { - options.append(" -o ").append(float3_to_string(texture_map.value.translation)); + if (texture_map.translation != float3{0.0f, 0.0f, 0.0f}) { + options.append(" -o ").append(float3_to_string(texture_map.translation)); } - if (texture_map.value.scale != float3{1.0f, 1.0f, 1.0f}) { - options.append(" -s ").append(float3_to_string(texture_map.value.scale)); + if (texture_map.scale != float3{1.0f, 1.0f, 1.0f}) { + options.append(" -s ").append(float3_to_string(texture_map.scale)); } - if (texture_map.key == eMTLSyntaxElement::map_Bump && mtl_material.map_Bump_strength > 0.0001f) { + if (texture_key == MTLTexMapType::bump && mtl_material.map_Bump_strength > 0.0001f) { options.append(" -bm ").append(std::to_string(mtl_material.map_Bump_strength)); } std::string path = path_reference( - texture_map.value.image_path.c_str(), blen_filedir, dest_dir, path_mode, ©_set); + texture_map.image_path.c_str(), blen_filedir, dest_dir, path_mode, ©_set); /* Always emit forward slashes for cross-platform compatibility. */ std::replace(path.begin(), path.end(), '\\', '/'); -#define SYNTAX_DISPATCH(eMTLSyntaxElement) \ - if (texture_map.key == eMTLSyntaxElement) { \ - fmt_handler_.write<eMTLSyntaxElement>(options, path.c_str()); \ - return; \ - } - - SYNTAX_DISPATCH(eMTLSyntaxElement::map_Kd); - SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ks); - SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ns); - SYNTAX_DISPATCH(eMTLSyntaxElement::map_d); - SYNTAX_DISPATCH(eMTLSyntaxElement::map_refl); - SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ke); - SYNTAX_DISPATCH(eMTLSyntaxElement::map_Bump); -#undef SYNTAX_DISPATCH - - BLI_assert(!"This map type was not written to the file."); + fmt_handler_.write_mtl_map(tex_map_type_to_string[(int)texture_key], options, path); } void MTLWriter::write_materials(const char *blen_filepath, @@ -637,14 +624,16 @@ void MTLWriter::write_materials(const char *blen_filepath, [](const MTLMaterial &a, const MTLMaterial &b) { return a.name < b.name; }); Set<std::pair<std::string, std::string>> copy_set; for (const MTLMaterial &mtlmat : mtlmaterials_) { - fmt_handler_.write<eMTLSyntaxElement::string>("\n"); - fmt_handler_.write<eMTLSyntaxElement::newmtl>(mtlmat.name); + fmt_handler_.write_string(""); + fmt_handler_.write_mtl_newmtl(mtlmat.name); write_bsdf_properties(mtlmat); - for (const auto &tex : mtlmat.texture_maps.items()) { - if (!tex.value.is_valid()) { + for (int key = 0; key < (int)MTLTexMapType::Count; key++) { + const MTLTexMap &tex = mtlmat.texture_maps[key]; + if (!tex.is_valid()) { continue; } - write_texture_map(mtlmat, tex, blen_filedir, dest_dir, path_mode, copy_set); + write_texture_map( + mtlmat, (MTLTexMapType)key, tex, blen_filedir, dest_dir, path_mode, copy_set); } } path_reference_copy(copy_set); diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh index 97c23484426..4544037fbc1 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh @@ -66,7 +66,7 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write object's name or group. */ - void write_object_name(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const; + void write_object_name(FormatHandler &fh, const OBJMesh &obj_mesh_data) const; /** * Write file name of Material Library in .OBJ file. */ @@ -74,19 +74,19 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write vertex coordinates for all vertices as "v x y z" or "v x y z r g b". */ - void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, + void write_vertex_coords(FormatHandler &fh, const OBJMesh &obj_mesh_data, bool write_colors) const; /** * Write UV vertex coordinates for all vertices as `vt u v`. * \note UV indices are stored here, but written with polygons later. */ - void write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &obj_mesh_data) const; + void write_uv_coords(FormatHandler &fh, OBJMesh &obj_mesh_data) const; /** * Write loop normals for smooth-shaded polygons, and polygon normals otherwise, as "vn x y z". * \note Normal indices ares stored here, but written with polygons later. */ - void write_poly_normals(FormatHandler<eFileType::OBJ> &fh, OBJMesh &obj_mesh_data); + void write_poly_normals(FormatHandler &fh, OBJMesh &obj_mesh_data); /** * Write polygon elements with at least vertex indices, and conditionally with UV vertex * indices and polygon normal indices. Also write groups: smooth, vertex, material. @@ -94,23 +94,23 @@ class OBJWriter : NonMovable, NonCopyable { * name used in the .obj file. * \note UV indices were stored while writing UV vertices. */ - void write_poly_elements(FormatHandler<eFileType::OBJ> &fh, + void write_poly_elements(FormatHandler &fh, const IndexOffsets &offsets, const OBJMesh &obj_mesh_data, std::function<const char *(int)> matname_fn); /** * Write loose edges of a mesh as "l v1 v2". */ - void write_edges_indices(FormatHandler<eFileType::OBJ> &fh, + void write_edges_indices(FormatHandler &fh, const IndexOffsets &offsets, const OBJMesh &obj_mesh_data) const; /** * Write a NURBS curve to the .OBJ file in parameter form. */ - void write_nurbs_curve(FormatHandler<eFileType::OBJ> &fh, const OBJCurve &obj_nurbs_data) const; + void write_nurbs_curve(FormatHandler &fh, const OBJCurve &obj_nurbs_data) const; private: - using func_vert_uv_normal_indices = void (OBJWriter::*)(FormatHandler<eFileType::OBJ> &fh, + using func_vert_uv_normal_indices = void (OBJWriter::*)(FormatHandler &fh, const IndexOffsets &offsets, Span<int> vert_indices, Span<int> uv_indices, @@ -124,7 +124,7 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write one line of polygon indices as "f v1/vt1/vn1 v2/vt2/vn2 ...". */ - void write_vert_uv_normal_indices(FormatHandler<eFileType::OBJ> &fh, + void write_vert_uv_normal_indices(FormatHandler &fh, const IndexOffsets &offsets, Span<int> vert_indices, Span<int> uv_indices, @@ -133,7 +133,7 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write one line of polygon indices as "f v1//vn1 v2//vn2 ...". */ - void write_vert_normal_indices(FormatHandler<eFileType::OBJ> &fh, + void write_vert_normal_indices(FormatHandler &fh, const IndexOffsets &offsets, Span<int> vert_indices, Span<int> /*uv_indices*/, @@ -142,7 +142,7 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write one line of polygon indices as "f v1/vt1 v2/vt2 ...". */ - void write_vert_uv_indices(FormatHandler<eFileType::OBJ> &fh, + void write_vert_uv_indices(FormatHandler &fh, const IndexOffsets &offsets, Span<int> vert_indices, Span<int> uv_indices, @@ -151,7 +151,7 @@ class OBJWriter : NonMovable, NonCopyable { /** * Write one line of polygon indices as "f v1 v2 ...". */ - void write_vert_indices(FormatHandler<eFileType::OBJ> &fh, + void write_vert_indices(FormatHandler &fh, const IndexOffsets &offsets, Span<int> vert_indices, Span<int> /*uv_indices*/, @@ -164,7 +164,7 @@ class OBJWriter : NonMovable, NonCopyable { */ class MTLWriter : NonMovable, NonCopyable { private: - FormatHandler<eFileType::MTL> fmt_handler_; + FormatHandler fmt_handler_; FILE *outfile_; std::string mtl_filepath_; Vector<MTLMaterial> mtlmaterials_; @@ -208,7 +208,8 @@ class MTLWriter : NonMovable, NonCopyable { * Write a texture map in the form "map_XX -s 1. 1. 1. -o 0. 0. 0. [-bm 1.] path/to/image". */ void write_texture_map(const MTLMaterial &mtl_material, - const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map, + MTLTexMapType texture_key, + const MTLTexMap &texture_map, const char *blen_filedir, const char *dest_dir, ePathReferenceMode mode, diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh index 5413c9969e3..cc0f7c0824c 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh @@ -23,268 +23,24 @@ namespace blender::io::obj { -enum class eFileType { - OBJ, - MTL, -}; - -enum class eOBJSyntaxElement { - vertex_coords, - vertex_coords_color, - uv_vertex_coords, - normal, - poly_element_begin, - vertex_uv_normal_indices, - vertex_normal_indices, - vertex_uv_indices, - vertex_indices, - poly_element_end, - poly_usemtl, - edge, - cstype, - nurbs_degree, - curve_element_begin, - curve_element_end, - nurbs_parameter_begin, - nurbs_parameters, - nurbs_parameter_end, - nurbs_group_end, - new_line, - mtllib, - smooth_group, - object_group, - object_name, - /* Use rarely. New line is NOT included for string. */ - string, -}; - -enum class eMTLSyntaxElement { - newmtl, - Ni, - d, - Ns, - illum, - Ka, - Kd, - Ks, - Ke, - map_Kd, - map_Ks, - map_Ns, - map_d, - map_refl, - map_Ke, - map_Bump, - /* Use rarely. New line is NOT included for string. */ - string, -}; - -template<eFileType filetype> struct FileTypeTraits; - -/* Used to prevent mixing of say OBJ file format with MTL syntax elements. */ -template<> struct FileTypeTraits<eFileType::OBJ> { - using SyntaxType = eOBJSyntaxElement; -}; - -template<> struct FileTypeTraits<eFileType::MTL> { - using SyntaxType = eMTLSyntaxElement; -}; - -struct FormattingSyntax { - /* Formatting syntax with the file format key like `newmtl %s\n`. */ - const char *fmt = nullptr; - /* Number of arguments needed by the syntax. */ - const int total_args = 0; - /* Whether types of the given arguments are accepted by the syntax above. Fail to compile by - * default. - */ - const bool are_types_valid = false; -}; - -/** - * Type dependent but always false. Use to add a `constexpr` conditional compile-time error. - */ -template<typename T> struct always_false : std::false_type { -}; - -template<typename... T> -constexpr bool is_type_float = (... && std::is_floating_point_v<std::decay_t<T>>); - -template<typename... T> -constexpr bool is_type_integral = (... && std::is_integral_v<std::decay_t<T>>); - -template<typename... T> -constexpr bool is_type_string_related = (... && std::is_constructible_v<std::string, T>); - -/* GCC (at least 9.3) while compiling the obj_exporter_tests.cc with optimizations on, - * results in "obj_export_io.hh:205:18: warning: ‘%s’ directive output truncated writing 34 bytes - * into a region of size 6" and similar warnings. Yes the output is truncated, and that is covered - * as an edge case by tests on purpose. */ -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wformat-truncation" -#endif -template<typename... T> -constexpr FormattingSyntax syntax_elem_to_formatting(const eOBJSyntaxElement key) -{ - switch (key) { - case eOBJSyntaxElement::vertex_coords: { - return {"v {:.6f} {:.6f} {:.6f}\n", 3, is_type_float<T...>}; - } - case eOBJSyntaxElement::vertex_coords_color: { - return {"v {:.6f} {:.6f} {:.6f} {:.4f} {:.4f} {:.4f}\n", 6, is_type_float<T...>}; - } - case eOBJSyntaxElement::uv_vertex_coords: { - return {"vt {:.6f} {:.6f}\n", 2, is_type_float<T...>}; - } - case eOBJSyntaxElement::normal: { - return {"vn {:.4f} {:.4f} {:.4f}\n", 3, is_type_float<T...>}; - } - case eOBJSyntaxElement::poly_element_begin: { - return {"f", 0, is_type_string_related<T...>}; - } - case eOBJSyntaxElement::vertex_uv_normal_indices: { - return {" {}/{}/{}", 3, is_type_integral<T...>}; - } - case eOBJSyntaxElement::vertex_normal_indices: { - return {" {}//{}", 2, is_type_integral<T...>}; - } - case eOBJSyntaxElement::vertex_uv_indices: { - return {" {}/{}", 2, is_type_integral<T...>}; - } - case eOBJSyntaxElement::vertex_indices: { - return {" {}", 1, is_type_integral<T...>}; - } - case eOBJSyntaxElement::poly_usemtl: { - return {"usemtl {}\n", 1, is_type_string_related<T...>}; - } - case eOBJSyntaxElement::edge: { - return {"l {} {}\n", 2, is_type_integral<T...>}; - } - case eOBJSyntaxElement::cstype: { - return {"cstype bspline\n", 0, is_type_string_related<T...>}; - } - case eOBJSyntaxElement::nurbs_degree: { - return {"deg {}\n", 1, is_type_integral<T...>}; - } - case eOBJSyntaxElement::curve_element_begin: { - return {"curv 0.0 1.0", 0, is_type_string_related<T...>}; - } - case eOBJSyntaxElement::nurbs_parameter_begin: { - return {"parm u 0.0", 0, is_type_string_related<T...>}; - } - case eOBJSyntaxElement::nurbs_parameters: { - return {" {:.6f}", 1, is_type_float<T...>}; - } - case eOBJSyntaxElement::nurbs_parameter_end: { - return {" 1.0\n", 0, is_type_string_related<T...>}; - } - case eOBJSyntaxElement::nurbs_group_end: { - return {"end\n", 0, is_type_string_related<T...>}; - } - case eOBJSyntaxElement::poly_element_end: { - ATTR_FALLTHROUGH; - } - case eOBJSyntaxElement::curve_element_end: { - ATTR_FALLTHROUGH; - } - case eOBJSyntaxElement::new_line: { - return {"\n", 0, is_type_string_related<T...>}; - } - case eOBJSyntaxElement::mtllib: { - return {"mtllib {}\n", 1, is_type_string_related<T...>}; - } - case eOBJSyntaxElement::smooth_group: { - return {"s {}\n", 1, is_type_integral<T...>}; - } - case eOBJSyntaxElement::object_group: { - return {"g {}\n", 1, is_type_string_related<T...>}; - } - case eOBJSyntaxElement::object_name: { - return {"o {}\n", 1, is_type_string_related<T...>}; - } - case eOBJSyntaxElement::string: { - return {"{}", 1, is_type_string_related<T...>}; - } - } -} - -template<typename... T> -constexpr FormattingSyntax syntax_elem_to_formatting(const eMTLSyntaxElement key) -{ - switch (key) { - case eMTLSyntaxElement::newmtl: { - return {"newmtl {}\n", 1, is_type_string_related<T...>}; - } - case eMTLSyntaxElement::Ni: { - return {"Ni {:.6f}\n", 1, is_type_float<T...>}; - } - case eMTLSyntaxElement::d: { - return {"d {:.6f}\n", 1, is_type_float<T...>}; - } - case eMTLSyntaxElement::Ns: { - return {"Ns {:.6f}\n", 1, is_type_float<T...>}; - } - case eMTLSyntaxElement::illum: { - return {"illum {}\n", 1, is_type_integral<T...>}; - } - case eMTLSyntaxElement::Ka: { - return {"Ka {:.6f} {:.6f} {:.6f}\n", 3, is_type_float<T...>}; - } - case eMTLSyntaxElement::Kd: { - return {"Kd {:.6f} {:.6f} {:.6f}\n", 3, is_type_float<T...>}; - } - case eMTLSyntaxElement::Ks: { - return {"Ks {:.6f} {:.6f} {:.6f}\n", 3, is_type_float<T...>}; - } - case eMTLSyntaxElement::Ke: { - return {"Ke {:.6f} {:.6f} {:.6f}\n", 3, is_type_float<T...>}; - } - /* NOTE: first texture map related argument, if present, will have its own leading space. */ - case eMTLSyntaxElement::map_Kd: { - return {"map_Kd{} {}\n", 2, is_type_string_related<T...>}; - } - case eMTLSyntaxElement::map_Ks: { - return {"map_Ks{} {}\n", 2, is_type_string_related<T...>}; - } - case eMTLSyntaxElement::map_Ns: { - return {"map_Ns{} {}\n", 2, is_type_string_related<T...>}; - } - case eMTLSyntaxElement::map_d: { - return {"map_d{} {}\n", 2, is_type_string_related<T...>}; - } - case eMTLSyntaxElement::map_refl: { - return {"map_refl{} {}\n", 2, is_type_string_related<T...>}; - } - case eMTLSyntaxElement::map_Ke: { - return {"map_Ke{} {}\n", 2, is_type_string_related<T...>}; - } - case eMTLSyntaxElement::map_Bump: { - return {"map_Bump{} {}\n", 2, is_type_string_related<T...>}; - } - case eMTLSyntaxElement::string: { - return {"{}", 1, is_type_string_related<T...>}; - } - } -} -#if defined(__GNUC__) && !defined(__clang__) -# pragma GCC diagnostic pop -#endif - /** - * File format and syntax agnostic file buffer writer. + * File buffer writer. * All writes are done into an internal chunked memory buffer * (list of default 64 kilobyte blocks). * Call write_fo_file once in a while to write the memory buffer(s) * into the given file. */ -template<eFileType filetype, size_t buffer_chunk_size = 64 * 1024> class FormatHandler : NonCopyable, NonMovable { private: typedef std::vector<char> VectorChar; std::vector<VectorChar> blocks_; + size_t buffer_chunk_size_; public: + FormatHandler(size_t buffer_chunk_size = 64 * 1024) : buffer_chunk_size_(buffer_chunk_size) + { + } + /* Write contents to the buffer(s) into a file, and clear the buffers. */ void write_to_file(FILE *f) { @@ -305,7 +61,7 @@ class FormatHandler : NonCopyable, NonMovable { return blocks_.size(); } - void append_from(FormatHandler<filetype, buffer_chunk_size> &v) + void append_from(FormatHandler &v) { blocks_.insert(blocks_.end(), std::make_move_iterator(v.blocks_.begin()), @@ -313,24 +69,132 @@ class FormatHandler : NonCopyable, NonMovable { v.blocks_.clear(); } - /** - * Example invocation: `writer->write<eMTLSyntaxElement::newmtl>("foo")`. - * - * \param key: Must match what the instance's filetype expects; i.e., `eMTLSyntaxElement` for - * `eFileType::MTL`. - */ - template<typename FileTypeTraits<filetype>::SyntaxType key, typename... T> - constexpr void write(T &&...args) - { - /* Get format syntax, number of arguments expected and whether types of given arguments are - * valid. - */ - constexpr FormattingSyntax fmt_nargs_valid = syntax_elem_to_formatting<T...>(key); - BLI_STATIC_ASSERT(fmt_nargs_valid.are_types_valid && - (sizeof...(T) == fmt_nargs_valid.total_args), - "Types of all arguments and the number of arguments should match what the " - "formatting specifies."); - write_impl(fmt_nargs_valid.fmt, std::forward<T>(args)...); + void write_obj_vertex(float x, float y, float z) + { + write_impl("v {:.6f} {:.6f} {:.6f}\n", x, y, z); + } + void write_obj_vertex_color(float x, float y, float z, float r, float g, float b) + { + write_impl("v {:.6f} {:.6f} {:.6f} {:.4f} {:.4f} {:.4f}\n", x, y, z, r, g, b); + } + void write_obj_uv(float x, float y) + { + write_impl("vt {:.6f} {:.6f}\n", x, y); + } + void write_obj_normal(float x, float y, float z) + { + write_impl("vn {:.4f} {:.4f} {:.4f}\n", x, y, z); + } + void write_obj_poly_begin() + { + write_impl("f"); + } + void write_obj_poly_end() + { + write_obj_newline(); + } + void write_obj_poly_v_uv_normal(int v, int uv, int n) + { + write_impl(" {}/{}/{}", v, uv, n); + } + void write_obj_poly_v_normal(int v, int n) + { + write_impl(" {}//{}", v, n); + } + void write_obj_poly_v_uv(int v, int uv) + { + write_impl(" {}/{}", v, uv); + } + void write_obj_poly_v(int v) + { + write_impl(" {}", v); + } + void write_obj_usemtl(StringRef s) + { + write_impl("usemtl {}\n", s); + } + void write_obj_mtllib(StringRef s) + { + write_impl("mtllib {}\n", s); + } + void write_obj_smooth(int s) + { + write_impl("s {}\n", s); + } + void write_obj_group(StringRef s) + { + write_impl("g {}\n", s); + } + void write_obj_object(StringRef s) + { + write_impl("o {}\n", s); + } + void write_obj_edge(int a, int b) + { + write_impl("l {} {}\n", a, b); + } + void write_obj_cstype() + { + write_impl("cstype bspline\n"); + } + void write_obj_nurbs_degree(int deg) + { + write_impl("deg {}\n", deg); + } + void write_obj_curve_begin() + { + write_impl("curv 0.0 1.0"); + } + void write_obj_curve_end() + { + write_obj_newline(); + } + void write_obj_nurbs_parm_begin() + { + write_impl("parm u 0.0"); + } + void write_obj_nurbs_parm(float v) + { + write_impl(" {:.6f}", v); + } + void write_obj_nurbs_parm_end() + { + write_impl(" 1.0\n"); + } + void write_obj_nurbs_group_end() + { + write_impl("end\n"); + } + void write_obj_newline() + { + write_impl("\n"); + } + + void write_mtl_newmtl(StringRef s) + { + write_impl("newmtl {}\n", s); + } + void write_mtl_float(const char *type, float v) + { + write_impl("{} {:.6f}\n", type, v); + } + void write_mtl_float3(const char *type, float r, float g, float b) + { + write_impl("{} {:.6f} {:.6f} {:.6f}\n", type, r, g, b); + } + void write_mtl_illum(int mode) + { + write_impl("illum {}\n", mode); + } + /* Note: options, if present, will have its own leading space. */ + void write_mtl_map(const char *type, StringRef options, StringRef value) + { + write_impl("{}{} {}\n", type, options, value); + } + + void write_string(StringRef s) + { + write_impl("{}\n", s); } private: @@ -340,7 +204,7 @@ class FormatHandler : NonCopyable, NonMovable { { if (blocks_.empty() || (blocks_.back().capacity() - blocks_.back().size() < at_least)) { VectorChar &b = blocks_.emplace_back(VectorChar()); - b.reserve(std::max(at_least, buffer_chunk_size)); + b.reserve(std::max(at_least, buffer_chunk_size_)); } } diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc index 4ed148ec64e..0b228ef8c37 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc @@ -6,6 +6,7 @@ #include "BKE_image.h" #include "BKE_node.h" +#include "BKE_node_runtime.hh" #include "BLI_map.hh" #include "BLI_math_vector.h" @@ -15,13 +16,23 @@ #include "DNA_material_types.h" #include "DNA_node_types.h" -#include "NOD_node_tree_ref.hh" - #include "obj_export_mesh.hh" #include "obj_export_mtl.hh" namespace blender::io::obj { +const char *tex_map_type_to_socket_id[] = { + "Base Color", + "Specular", + "Roughness", + "Alpha", + "Metallic", + "Emission", + "Normal", +}; +BLI_STATIC_ASSERT(ARRAY_SIZE(tex_map_type_to_socket_id) == (int)MTLTexMapType::Count, + "array size mismatch"); + /** * Copy a float property of the given type from the bNode to given buffer. */ @@ -72,25 +83,25 @@ static void copy_property_from_node(const eNodeSocketDatatype property_type, * Collect all the source sockets linked to the destination socket in a destination node. */ static void linked_sockets_to_dest_id(const bNode *dest_node, - const nodes::NodeTreeRef &node_tree, - StringRefNull dest_socket_id, - Vector<const nodes::OutputSocketRef *> &r_linked_sockets) + const bNodeTree &node_tree, + const char *dest_socket_id, + Vector<const bNodeSocket *> &r_linked_sockets) { r_linked_sockets.clear(); if (!dest_node) { return; } - Span<const nodes::NodeRef *> object_dest_nodes = node_tree.nodes_by_type(dest_node->idname); - Span<const nodes::InputSocketRef *> dest_inputs = object_dest_nodes.first()->inputs(); - const nodes::InputSocketRef *dest_socket = nullptr; - for (const nodes::InputSocketRef *curr_socket : dest_inputs) { - if (STREQ(curr_socket->bsocket()->identifier, dest_socket_id.c_str())) { + Span<const bNode *> object_dest_nodes = node_tree.nodes_by_type(dest_node->idname); + Span<const bNodeSocket *> dest_inputs = object_dest_nodes.first()->input_sockets(); + const bNodeSocket *dest_socket = nullptr; + for (const bNodeSocket *curr_socket : dest_inputs) { + if (STREQ(curr_socket->identifier, dest_socket_id)) { dest_socket = curr_socket; break; } } if (dest_socket) { - Span<const nodes::OutputSocketRef *> linked_sockets = dest_socket->directly_linked_sockets(); + Span<const bNodeSocket *> linked_sockets = dest_socket->directly_linked_sockets(); r_linked_sockets.resize(linked_sockets.size()); r_linked_sockets = linked_sockets; } @@ -99,13 +110,12 @@ static void linked_sockets_to_dest_id(const bNode *dest_node, /** * From a list of sockets, get the parent node which is of the given node type. */ -static const bNode *get_node_of_type(Span<const nodes::OutputSocketRef *> sockets_list, - const int node_type) +static const bNode *get_node_of_type(Span<const bNodeSocket *> sockets_list, const int node_type) { - for (const nodes::SocketRef *socket : sockets_list) { - const bNode *parent_node = socket->bnode(); - if (parent_node->typeinfo->type == node_type) { - return parent_node; + for (const bNodeSocket *socket : sockets_list) { + const bNode &parent_node = socket->owner_node(); + if (parent_node.typeinfo->type == node_type) { + return &parent_node; } } return nullptr; @@ -141,16 +151,16 @@ static const char *get_image_filepath(const bNode *tex_node) * We only want one that feeds directly into a Material Output node * (that is the behavior of the legacy Python exporter). */ -static const nodes::NodeRef *find_bsdf_node(const nodes::NodeTreeRef *nodetree) +static const bNode *find_bsdf_node(const bNodeTree *nodetree) { if (!nodetree) { return nullptr; } - for (const nodes::NodeRef *node : nodetree->nodes_by_type("ShaderNodeOutputMaterial")) { - const nodes::InputSocketRef *node_input_socket0 = node->inputs()[0]; - for (const nodes::OutputSocketRef *out_sock : node_input_socket0->directly_linked_sockets()) { - const nodes::NodeRef &in_node = out_sock->node(); - if (in_node.typeinfo()->type == SH_NODE_BSDF_PRINCIPLED) { + for (const bNode *node : nodetree->nodes_by_type("ShaderNodeOutputMaterial")) { + const bNodeSocket &node_input_socket0 = node->input_socket(0); + for (const bNodeSocket *out_sock : node_input_socket0.directly_linked_sockets()) { + const bNode &in_node = out_sock->owner_node(); + if (in_node.typeinfo->type == SH_NODE_BSDF_PRINCIPLED) { return &in_node; } } @@ -161,55 +171,50 @@ static const nodes::NodeRef *find_bsdf_node(const nodes::NodeTreeRef *nodetree) /** * Store properties found either in bNode or material into r_mtl_mat. */ -static void store_bsdf_properties(const nodes::NodeRef *bsdf_node, +static void store_bsdf_properties(const bNode *bsdf_node, const Material *material, MTLMaterial &r_mtl_mat) { - const bNode *bnode = nullptr; - if (bsdf_node) { - bnode = bsdf_node->bnode(); - } - /* If p-BSDF is not present, fallback to #Object.Material. */ float roughness = material->roughness; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Roughness", {&roughness, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Roughness", {&roughness, 1}); } /* Empirical approximation. Importer should use the inverse of this method. */ float spec_exponent = (1.0f - roughness); spec_exponent *= spec_exponent * 1000.0f; float specular = material->spec; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Specular", {&specular, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Specular", {&specular, 1}); } float metallic = material->metallic; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Metallic", {&metallic, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Metallic", {&metallic, 1}); } float refraction_index = 1.0f; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "IOR", {&refraction_index, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "IOR", {&refraction_index, 1}); } float dissolved = material->a; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Alpha", {&dissolved, 1}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Alpha", {&dissolved, 1}); } const bool transparent = dissolved != 1.0f; float3 diffuse_col = {material->r, material->g, material->b}; - if (bnode) { - copy_property_from_node(SOCK_RGBA, bnode, "Base Color", {diffuse_col, 3}); + if (bsdf_node) { + copy_property_from_node(SOCK_RGBA, bsdf_node, "Base Color", {diffuse_col, 3}); } float3 emission_col{0.0f}; float emission_strength = 0.0f; - if (bnode) { - copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1}); - copy_property_from_node(SOCK_RGBA, bnode, "Emission", {emission_col, 3}); + if (bsdf_node) { + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Emission Strength", {&emission_strength, 1}); + copy_property_from_node(SOCK_RGBA, bsdf_node, "Emission", {emission_col, 3}); } mul_v3_fl(emission_col, emission_strength); @@ -253,8 +258,8 @@ static void store_bsdf_properties(const nodes::NodeRef *bsdf_node, /** * Store image texture options and file-paths in `r_mtl_mat`. */ -static void store_image_textures(const nodes::NodeRef *bsdf_node, - const nodes::NodeTreeRef *node_tree, +static void store_image_textures(const bNode *bsdf_node, + const bNodeTree *node_tree, const Material *material, MTLMaterial &r_mtl_mat) { @@ -262,21 +267,20 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, /* No nodetree, no images, or no Principled BSDF node. */ return; } - const bNode *bnode = bsdf_node->bnode(); /* Normal Map Texture has two extra tasks of: * - finding a Normal Map node before finding a texture node. * - finding "Strength" property of the node for `-bm` option. */ - for (Map<const eMTLSyntaxElement, tex_map_XX>::MutableItem texture_map : - r_mtl_mat.texture_maps.items()) { - Vector<const nodes::OutputSocketRef *> linked_sockets; + for (int key = 0; key < (int)MTLTexMapType::Count; ++key) { + MTLTexMap &value = r_mtl_mat.texture_maps[key]; + Vector<const bNodeSocket *> linked_sockets; const bNode *normal_map_node{nullptr}; - if (texture_map.key == eMTLSyntaxElement::map_Bump) { + if (key == (int)MTLTexMapType::bump) { /* Find sockets linked to destination "Normal" socket in P-BSDF node. */ - linked_sockets_to_dest_id(bnode, *node_tree, "Normal", linked_sockets); + linked_sockets_to_dest_id(bsdf_node, *node_tree, "Normal", linked_sockets); /* Among the linked sockets, find Normal Map shader node. */ normal_map_node = get_node_of_type(linked_sockets, SH_NODE_NORMAL_MAP); @@ -285,16 +289,17 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, } else { /* Skip emission map if emission strength is zero. */ - if (texture_map.key == eMTLSyntaxElement::map_Ke) { + if (key == (int)MTLTexMapType::Ke) { float emission_strength = 0.0f; - copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1}); + copy_property_from_node( + SOCK_FLOAT, bsdf_node, "Emission Strength", {&emission_strength, 1}); if (emission_strength == 0.0f) { continue; } } /* Find sockets linked to the destination socket of interest, in P-BSDF node. */ linked_sockets_to_dest_id( - bnode, *node_tree, texture_map.value.dest_socket_id, linked_sockets); + bsdf_node, *node_tree, tex_map_type_to_socket_id[key], linked_sockets); } /* Among the linked sockets, find Image Texture shader node. */ @@ -317,10 +322,10 @@ static void store_image_textures(const nodes::NodeRef *bsdf_node, } /* Texture transform options. Only translation (origin offset, "-o") and scale * ("-o") are supported. */ - copy_property_from_node(SOCK_VECTOR, mapping, "Location", {texture_map.value.translation, 3}); - copy_property_from_node(SOCK_VECTOR, mapping, "Scale", {texture_map.value.scale, 3}); + copy_property_from_node(SOCK_VECTOR, mapping, "Location", {value.translation, 3}); + copy_property_from_node(SOCK_VECTOR, mapping, "Scale", {value.scale, 3}); - texture_map.value.image_path = tex_image_filepath; + value.image_path = tex_image_filepath; } } @@ -330,14 +335,14 @@ MTLMaterial mtlmaterial_for_material(const Material *material) MTLMaterial mtlmat; mtlmat.name = std::string(material->id.name + 2); std::replace(mtlmat.name.begin(), mtlmat.name.end(), ' ', '_'); - const nodes::NodeTreeRef *nodetree = nullptr; - if (material->nodetree) { - nodetree = new nodes::NodeTreeRef(material->nodetree); + const bNodeTree *nodetree = material->nodetree; + if (nodetree != nullptr) { + nodetree->ensure_topology_cache(); } - const nodes::NodeRef *bsdf_node = find_bsdf_node(nodetree); + + const bNode *bsdf_node = find_bsdf_node(nodetree); store_bsdf_properties(bsdf_node, material, mtlmat); store_image_textures(bsdf_node, nodetree, material, mtlmat); - delete nodetree; return mtlmat; } diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh index f83b3b49bf5..d8eafff107b 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh @@ -6,36 +6,23 @@ #pragma once -#include "BLI_map.hh" #include "BLI_math_vec_types.hh" #include "DNA_node_types.h" -#include "obj_export_io.hh" - -namespace blender { -template<> struct DefaultHash<io::obj::eMTLSyntaxElement> { - uint64_t operator()(const io::obj::eMTLSyntaxElement value) const - { - return static_cast<uint64_t>(value); - } -}; - -} // namespace blender +struct Material; namespace blender::io::obj { -/** - * Generic container for texture node properties. - */ -struct tex_map_XX { - tex_map_XX(StringRef to_socket_id) : dest_socket_id(to_socket_id){}; +enum class MTLTexMapType { Kd = 0, Ks, Ns, d, refl, Ke, bump, Count }; +extern const char *tex_map_type_to_socket_id[]; + +struct MTLTexMap { bool is_valid() const { return !image_path.empty(); } /* Target socket which this texture node connects to. */ - const std::string dest_socket_id; float3 translation{0.0f}; float3 scale{1.0f}; /* Only Flat and Sphere projections are supported. */ @@ -48,26 +35,13 @@ struct tex_map_XX { * Container suited for storing Material data for/from a .MTL file. */ struct MTLMaterial { - MTLMaterial() - { - texture_maps.add(eMTLSyntaxElement::map_Kd, tex_map_XX("Base Color")); - texture_maps.add(eMTLSyntaxElement::map_Ks, tex_map_XX("Specular")); - texture_maps.add(eMTLSyntaxElement::map_Ns, tex_map_XX("Roughness")); - texture_maps.add(eMTLSyntaxElement::map_d, tex_map_XX("Alpha")); - texture_maps.add(eMTLSyntaxElement::map_refl, tex_map_XX("Metallic")); - texture_maps.add(eMTLSyntaxElement::map_Ke, tex_map_XX("Emission")); - texture_maps.add(eMTLSyntaxElement::map_Bump, tex_map_XX("Normal")); - } - - const tex_map_XX &tex_map_of_type(const eMTLSyntaxElement key) const + const MTLTexMap &tex_map_of_type(MTLTexMapType key) const { - BLI_assert(texture_maps.contains(key)); - return texture_maps.lookup(key); + return texture_maps[(int)key]; } - tex_map_XX &tex_map_of_type(const eMTLSyntaxElement key) + MTLTexMap &tex_map_of_type(MTLTexMapType key) { - BLI_assert(texture_maps.contains(key)); - return texture_maps.lookup(key); + return texture_maps[(int)key]; } std::string name; @@ -81,7 +55,7 @@ struct MTLMaterial { float Ni{-1.0f}; float d{-1.0f}; int illum{-1}; - Map<const eMTLSyntaxElement, tex_map_XX> texture_maps; + MTLTexMap texture_maps[(int)MTLTexMapType::Count]; /** Only used for Normal Map node: "map_Bump". */ float map_Bump_strength{-1.0f}; }; diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc index 77d4f6268bc..76cf9066bf4 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc @@ -143,7 +143,7 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me * we have to have the output text buffer for each object, * and write them all into the file at the end. */ size_t count = exportable_as_mesh.size(); - std::vector<FormatHandler<eFileType::OBJ>> buffers(count); + std::vector<FormatHandler> buffers(count); /* Serial: gather material indices, ensure normals & edges. */ Vector<Vector<int>> mtlindices; @@ -242,7 +242,7 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me static void write_nurbs_curve_objects(const Vector<std::unique_ptr<OBJCurve>> &exportable_as_nurbs, const OBJWriter &obj_writer) { - FormatHandler<eFileType::OBJ> fh; + FormatHandler fh; /* #OBJCurve doesn't have any dynamically allocated memory, so it's fine * to wait for #blender::Vector to clean the objects up. */ for (const std::unique_ptr<OBJCurve> &obj_curve : exportable_as_nurbs) { diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc index 633f70b2e38..088784b4194 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc @@ -592,36 +592,31 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, add_default_mtl_library(); } -static eMTLSyntaxElement mtl_line_start_to_enum(const char *&p, const char *end) +static MTLTexMapType mtl_line_start_to_texture_type(const char *&p, const char *end) { if (parse_keyword(p, end, "map_Kd")) { - return eMTLSyntaxElement::map_Kd; + return MTLTexMapType::Kd; } if (parse_keyword(p, end, "map_Ks")) { - return eMTLSyntaxElement::map_Ks; + return MTLTexMapType::Ks; } if (parse_keyword(p, end, "map_Ns")) { - return eMTLSyntaxElement::map_Ns; + return MTLTexMapType::Ns; } if (parse_keyword(p, end, "map_d")) { - return eMTLSyntaxElement::map_d; + return MTLTexMapType::d; } - if (parse_keyword(p, end, "refl")) { - return eMTLSyntaxElement::map_refl; - } - if (parse_keyword(p, end, "map_refl")) { - return eMTLSyntaxElement::map_refl; + if (parse_keyword(p, end, "refl") || parse_keyword(p, end, "map_refl")) { + return MTLTexMapType::refl; } if (parse_keyword(p, end, "map_Ke")) { - return eMTLSyntaxElement::map_Ke; - } - if (parse_keyword(p, end, "bump")) { - return eMTLSyntaxElement::map_Bump; + return MTLTexMapType::Ke; } - if (parse_keyword(p, end, "map_Bump") || parse_keyword(p, end, "map_bump")) { - return eMTLSyntaxElement::map_Bump; + if (parse_keyword(p, end, "bump") || parse_keyword(p, end, "map_Bump") || + parse_keyword(p, end, "map_bump")) { + return MTLTexMapType::bump; } - return eMTLSyntaxElement::string; + return MTLTexMapType::Count; } static const std::pair<StringRef, int> unsupported_texture_options[] = { @@ -639,7 +634,7 @@ static const std::pair<StringRef, int> unsupported_texture_options[] = { static bool parse_texture_option(const char *&p, const char *end, MTLMaterial *material, - tex_map_XX &tex_map) + MTLTexMap &tex_map) { p = drop_whitespace(p, end); if (parse_keyword(p, end, "-o")) { @@ -693,13 +688,13 @@ static void parse_texture_map(const char *p, if (!is_map && !is_refl && !is_bump) { return; } - eMTLSyntaxElement key = mtl_line_start_to_enum(p, end); - if (key == eMTLSyntaxElement::string || !material->texture_maps.contains(key)) { + MTLTexMapType key = mtl_line_start_to_texture_type(p, end); + if (key == MTLTexMapType::Count) { /* No supported texture map found. */ std::cerr << "OBJ import: MTL texture map type not supported: '" << line << "'" << std::endl; return; } - tex_map_XX &tex_map = material->texture_maps.lookup(key); + MTLTexMap &tex_map = material->tex_map_of_type(key); tex_map.mtl_dir_path = mtl_dir_path; /* Parse texture map options. */ diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc index 4e6983bc0d5..7f7fda8d8f1 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc @@ -181,7 +181,7 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) const int64_t total_verts = mesh_geometry_.get_vertex_count(); if (use_vertex_groups && total_verts && mesh_geometry_.has_vertex_groups_) { mesh->dvert = static_cast<MDeformVert *>( - CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, nullptr, total_verts)); + CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, total_verts)); } bke::SpanAttributeWriter<int> material_indices = @@ -268,7 +268,7 @@ void MeshFromGeometry::create_uv_verts(Mesh *mesh) return; } MLoopUV *mluv_dst = static_cast<MLoopUV *>(CustomData_add_layer( - &mesh->ldata, CD_MLOOPUV, CD_DEFAULT, nullptr, mesh_geometry_.total_loops_)); + &mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, mesh_geometry_.total_loops_)); int tot_loop_idx = 0; for (const PolyElem &curr_face : mesh_geometry_.face_elements_) { diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc index 093cbec32fe..c28de14f2f7 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc @@ -17,8 +17,6 @@ #include "NOD_shader.h" -/* TODO: move eMTLSyntaxElement out of following file into a more neutral place */ -#include "obj_export_io.hh" #include "obj_import_mtl.hh" #include "obj_import_string_utils.hh" @@ -29,12 +27,12 @@ namespace blender::io::obj { * Only float value(s) can be set using this method. */ static void set_property_of_socket(eNodeSocketDatatype property_type, - StringRef socket_id, + const char *socket_id, Span<float> value, bNode *r_node) { BLI_assert(r_node); - bNodeSocket *socket{nodeFindSocket(r_node, SOCK_IN, socket_id.data())}; + bNodeSocket *socket{nodeFindSocket(r_node, SOCK_IN, socket_id)}; BLI_assert(socket && socket->type == property_type); switch (property_type) { case SOCK_FLOAT: { @@ -95,7 +93,7 @@ static Image *create_placeholder_image(Main *bmain, const std::string &path) return image; } -static Image *load_texture_image(Main *bmain, const tex_map_XX &tex_map, bool relative_paths) +static Image *load_texture_image(Main *bmain, const MTLTexMap &tex_map, bool relative_paths) { Image *image = nullptr; @@ -206,15 +204,15 @@ std::pair<float, float> ShaderNodetreeWrap::set_node_locations(const int pos_x) } void ShaderNodetreeWrap::link_sockets(bNode *from_node, - StringRef from_node_id, + const char *from_node_id, bNode *to_node, - StringRef to_node_id, + const char *to_node_id, const int from_node_pos_x) { std::tie(from_node->locx, from_node->locy) = set_node_locations(from_node_pos_x); std::tie(to_node->locx, to_node->locy) = set_node_locations(from_node_pos_x + 1); - bNodeSocket *from_sock{nodeFindSocket(from_node, SOCK_OUT, from_node_id.data())}; - bNodeSocket *to_sock{nodeFindSocket(to_node, SOCK_IN, to_node_id.data())}; + bNodeSocket *from_sock{nodeFindSocket(from_node, SOCK_OUT, from_node_id)}; + bNodeSocket *to_sock{nodeFindSocket(to_node, SOCK_IN, to_node_id)}; BLI_assert(from_sock && to_sock); nodeAddLink(nodetree_.get(), from_node, from_sock, to_node, to_sock); } @@ -338,7 +336,7 @@ void ShaderNodetreeWrap::set_bsdf_socket_values(Material *mat) if (emission_color.x >= 0 && emission_color.y >= 0 && emission_color.z >= 0) { set_property_of_socket(SOCK_RGBA, "Emission", {emission_color, 3}, bsdf_); } - if (mtl_mat_.tex_map_of_type(eMTLSyntaxElement::map_Ke).is_valid()) { + if (mtl_mat_.tex_map_of_type(MTLTexMapType::Ke).is_valid()) { set_property_of_socket(SOCK_FLOAT, "Emission Strength", {1.0f}, bsdf_); } set_property_of_socket(SOCK_FLOAT, "Specular", {specular}, bsdf_); @@ -359,38 +357,36 @@ void ShaderNodetreeWrap::set_bsdf_socket_values(Material *mat) void ShaderNodetreeWrap::add_image_textures(Main *bmain, Material *mat, bool relative_paths) { - for (const Map<const eMTLSyntaxElement, tex_map_XX>::Item texture_map : - mtl_mat_.texture_maps.items()) { - if (!texture_map.value.is_valid()) { + for (int key = 0; key < (int)MTLTexMapType::Count; ++key) { + const MTLTexMap &value = mtl_mat_.texture_maps[key]; + if (!value.is_valid()) { /* No Image texture node of this map type can be added to this material. */ continue; } bNode *image_texture = add_node_to_tree(SH_NODE_TEX_IMAGE); BLI_assert(image_texture); - Image *image = load_texture_image(bmain, texture_map.value, relative_paths); + Image *image = load_texture_image(bmain, value, relative_paths); if (image == nullptr) { continue; } image_texture->id = &image->id; - static_cast<NodeTexImage *>(image_texture->storage)->projection = - texture_map.value.projection_type; + static_cast<NodeTexImage *>(image_texture->storage)->projection = value.projection_type; /* Add normal map node if needed. */ bNode *normal_map = nullptr; - if (texture_map.key == eMTLSyntaxElement::map_Bump) { + if (key == (int)MTLTexMapType::bump) { normal_map = add_node_to_tree(SH_NODE_NORMAL_MAP); const float bump = std::max(0.0f, mtl_mat_.map_Bump_strength); set_property_of_socket(SOCK_FLOAT, "Strength", {bump}, normal_map); } /* Add UV mapping & coordinate nodes only if needed. */ - if (texture_map.value.translation != float3(0, 0, 0) || - texture_map.value.scale != float3(1, 1, 1)) { + if (value.translation != float3(0, 0, 0) || value.scale != float3(1, 1, 1)) { bNode *mapping = add_node_to_tree(SH_NODE_MAPPING); bNode *texture_coordinate = add_node_to_tree(SH_NODE_TEX_COORD); - set_property_of_socket(SOCK_VECTOR, "Location", {texture_map.value.translation, 3}, mapping); - set_property_of_socket(SOCK_VECTOR, "Scale", {texture_map.value.scale, 3}, mapping); + set_property_of_socket(SOCK_VECTOR, "Location", {value.translation, 3}, mapping); + set_property_of_socket(SOCK_VECTOR, "Scale", {value.scale, 3}, mapping); link_sockets(texture_coordinate, "UV", mapping, "Vector", 0); link_sockets(mapping, "Vector", image_texture, "Vector", 1); @@ -400,12 +396,12 @@ void ShaderNodetreeWrap::add_image_textures(Main *bmain, Material *mat, bool rel link_sockets(image_texture, "Color", normal_map, "Color", 2); link_sockets(normal_map, "Normal", bsdf_, "Normal", 3); } - else if (texture_map.key == eMTLSyntaxElement::map_d) { - link_sockets(image_texture, "Alpha", bsdf_, texture_map.value.dest_socket_id, 2); + else if (key == (int)MTLTexMapType::d) { + link_sockets(image_texture, "Alpha", bsdf_, tex_map_type_to_socket_id[key], 2); mat->blend_method = MA_BM_BLEND; } else { - link_sockets(image_texture, "Color", bsdf_, texture_map.value.dest_socket_id, 2); + link_sockets(image_texture, "Color", bsdf_, tex_map_type_to_socket_id[key], 2); } } } diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mtl.hh b/source/blender/io/wavefront_obj/importer/obj_import_mtl.hh index 17dd0106fea..2c51d92a2cd 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mtl.hh +++ b/source/blender/io/wavefront_obj/importer/obj_import_mtl.hh @@ -10,7 +10,6 @@ #include "BLI_map.hh" #include "BLI_math_vec_types.hh" -#include "BLI_string_ref.hh" #include "BLI_vector.hh" #include "DNA_node_types.h" @@ -75,9 +74,9 @@ class ShaderNodetreeWrap { * \param from_node_pos_x: 0 to 4 value as per nodetree arrangement. */ void link_sockets(bNode *from_node, - StringRef from_node_id, + const char *from_node_id, bNode *to_node, - StringRef to_node_id, + const char *to_node_id, const int from_node_pos_x); /** * Set values of sockets in p-BSDF node of the nodetree. diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc index f582064e0c1..0fd711bdac6 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -185,17 +185,17 @@ TEST(obj_exporter_writer, mtllib) TEST(obj_exporter_writer, format_handler_buffer_chunking) { /* Use a tiny buffer chunk size, so that the test below ends up creating several blocks. */ - FormatHandler<eFileType::OBJ, 16> h; - h.write<eOBJSyntaxElement::object_name>("abc"); - h.write<eOBJSyntaxElement::object_name>("abcd"); - h.write<eOBJSyntaxElement::object_name>("abcde"); - h.write<eOBJSyntaxElement::object_name>("abcdef"); - h.write<eOBJSyntaxElement::object_name>("012345678901234567890123456789abcd"); - h.write<eOBJSyntaxElement::object_name>("123"); - h.write<eOBJSyntaxElement::curve_element_begin>(); - h.write<eOBJSyntaxElement::new_line>(); - h.write<eOBJSyntaxElement::nurbs_parameter_begin>(); - h.write<eOBJSyntaxElement::new_line>(); + FormatHandler h(16); + h.write_obj_object("abc"); + h.write_obj_object("abcd"); + h.write_obj_object("abcde"); + h.write_obj_object("abcdef"); + h.write_obj_object("012345678901234567890123456789abcd"); + h.write_obj_object("123"); + h.write_obj_curve_begin(); + h.write_obj_newline(); + h.write_obj_nurbs_parm_begin(); + h.write_obj_newline(); size_t got_blocks = h.get_block_count(); ASSERT_EQ(got_blocks, 7); diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc index bd9360548af..35f977f41df 100644 --- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc @@ -12,7 +12,7 @@ #include "BKE_scene.h" #include "BLI_listbase.h" -#include "BLI_math_base.h" +#include "BLI_math_base.hh" #include "BLI_math_vec_types.hh" #include "BLO_readfile.h" diff --git a/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc b/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc index 08050ac34c9..41faba95b30 100644 --- a/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc @@ -58,9 +58,9 @@ class obj_mtl_parser_test : public testing::Test { EXPECT_NEAR(exp.d, got.d, tol); EXPECT_NEAR(exp.map_Bump_strength, got.map_Bump_strength, tol); EXPECT_EQ(exp.illum, got.illum); - for (const auto &it : exp.texture_maps.items()) { - const tex_map_XX &exp_tex = it.value; - const tex_map_XX &got_tex = got.texture_maps.lookup(it.key); + for (int key = 0; key < (int)MTLTexMapType::Count; key++) { + const MTLTexMap &exp_tex = exp.texture_maps[key]; + const MTLTexMap &got_tex = got.texture_maps[key]; EXPECT_STREQ(exp_tex.image_path.c_str(), got_tex.image_path.c_str()); EXPECT_V3_NEAR(exp_tex.translation, got_tex.translation, tol); EXPECT_V3_NEAR(exp_tex.scale, got_tex.scale, tol); @@ -113,8 +113,8 @@ TEST_F(obj_mtl_parser_test, string_newlines_whitespace) mat[4].Kd = {0.6f, 0.7f, 0.8f}; mat[5].name = "crlf_ending"; mat[5].Ns = 5.0f; - mat[5].tex_map_of_type(eMTLSyntaxElement::map_Kd).image_path = "sometex_d.png"; - mat[5].tex_map_of_type(eMTLSyntaxElement::map_Ks).image_path = "sometex_s_spaces_after_name.png"; + mat[5].tex_map_of_type(MTLTexMapType::Kd).image_path = "sometex_d.png"; + mat[5].tex_map_of_type(MTLTexMapType::Ks).image_path = "sometex_s_spaces_after_name.png"; check_string(text, mat, ARRAY_SIZE(mat)); } @@ -175,13 +175,13 @@ TEST_F(obj_mtl_parser_test, materials) mat[1].illum = 2; mat[1].map_Bump_strength = 1; { - tex_map_XX &kd = mat[1].tex_map_of_type(eMTLSyntaxElement::map_Kd); + MTLTexMap &kd = mat[1].tex_map_of_type(MTLTexMapType::Kd); kd.image_path = "texture.png"; - tex_map_XX &ns = mat[1].tex_map_of_type(eMTLSyntaxElement::map_Ns); + MTLTexMap &ns = mat[1].tex_map_of_type(MTLTexMapType::Ns); ns.image_path = "sometexture_Roughness.png"; - tex_map_XX &refl = mat[1].tex_map_of_type(eMTLSyntaxElement::map_refl); + MTLTexMap &refl = mat[1].tex_map_of_type(MTLTexMapType::refl); refl.image_path = "sometexture_Metallic.png"; - tex_map_XX &bump = mat[1].tex_map_of_type(eMTLSyntaxElement::map_Bump); + MTLTexMap &bump = mat[1].tex_map_of_type(MTLTexMapType::bump); bump.image_path = "sometexture_Normal.png"; } @@ -202,13 +202,13 @@ TEST_F(obj_mtl_parser_test, materials) mat[3].Ns = 800; mat[3].map_Bump_strength = 0.5f; { - tex_map_XX &kd = mat[3].tex_map_of_type(eMTLSyntaxElement::map_Kd); + MTLTexMap &kd = mat[3].tex_map_of_type(MTLTexMapType::Kd); kd.image_path = "someHatTexture_BaseColor.jpg"; - tex_map_XX &ns = mat[3].tex_map_of_type(eMTLSyntaxElement::map_Ns); + MTLTexMap &ns = mat[3].tex_map_of_type(MTLTexMapType::Ns); ns.image_path = "someHatTexture_Roughness.jpg"; - tex_map_XX &refl = mat[3].tex_map_of_type(eMTLSyntaxElement::map_refl); + MTLTexMap &refl = mat[3].tex_map_of_type(MTLTexMapType::refl); refl.image_path = "someHatTexture_Metalness.jpg"; - tex_map_XX &bump = mat[3].tex_map_of_type(eMTLSyntaxElement::map_Bump); + MTLTexMap &bump = mat[3].tex_map_of_type(MTLTexMapType::bump); bump.image_path = "someHatTexture_Normal.jpg"; } @@ -222,30 +222,30 @@ TEST_F(obj_mtl_parser_test, materials) mat[4].d = 0.5; mat[4].map_Bump_strength = 0.1f; { - tex_map_XX &kd = mat[4].tex_map_of_type(eMTLSyntaxElement::map_Kd); + MTLTexMap &kd = mat[4].tex_map_of_type(MTLTexMapType::Kd); kd.image_path = "sometex_d.png"; - tex_map_XX &ns = mat[4].tex_map_of_type(eMTLSyntaxElement::map_Ns); + MTLTexMap &ns = mat[4].tex_map_of_type(MTLTexMapType::Ns); ns.image_path = "sometex_ns.psd"; - tex_map_XX &refl = mat[4].tex_map_of_type(eMTLSyntaxElement::map_refl); + MTLTexMap &refl = mat[4].tex_map_of_type(MTLTexMapType::refl); refl.image_path = "clouds.tiff"; refl.scale = {1.5f, 2.5f, 3.5f}; refl.translation = {4.5f, 5.5f, 6.5f}; refl.projection_type = SHD_PROJ_SPHERE; - tex_map_XX &bump = mat[4].tex_map_of_type(eMTLSyntaxElement::map_Bump); + MTLTexMap &bump = mat[4].tex_map_of_type(MTLTexMapType::bump); bump.image_path = "somebump.tga"; bump.scale = {3, 4, 5}; } mat[5].name = "Parser_ScaleOffset_Test"; { - tex_map_XX &kd = mat[5].tex_map_of_type(eMTLSyntaxElement::map_Kd); + MTLTexMap &kd = mat[5].tex_map_of_type(MTLTexMapType::Kd); kd.translation = {2.5f, 0.0f, 0.0f}; kd.image_path = "OffsetOneValue.png"; - tex_map_XX &ks = mat[5].tex_map_of_type(eMTLSyntaxElement::map_Ks); + MTLTexMap &ks = mat[5].tex_map_of_type(MTLTexMapType::Ks); ks.scale = {1.5f, 2.5f, 1.0f}; ks.translation = {3.5f, 4.5f, 0.0f}; ks.image_path = "ScaleOffsetBothTwovalues.png"; - tex_map_XX &ns = mat[5].tex_map_of_type(eMTLSyntaxElement::map_Ns); + MTLTexMap &ns = mat[5].tex_map_of_type(MTLTexMapType::Ns); ns.scale = {0.5f, 1.0f, 1.0f}; ns.image_path = "1.Value.png"; } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 3477105f519..92cc35908f2 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -12,8 +12,33 @@ #include "DNA_scene_types.h" /* for #ImageFormatData */ #include "DNA_vec_types.h" /* for #rctf */ +/** Workaround to forward-declare C++ type in C header. */ #ifdef __cplusplus -extern "C" { +namespace blender { +template<typename T> class Span; +class StringRef; +class StringRefNull; +} // namespace blender +namespace blender::nodes { +class NodeDeclaration; +class SocketDeclaration; +} // namespace blender::nodes +namespace blender::bke { +class bNodeTreeRuntime; +class bNodeRuntime; +class bNodeSocketRuntime; +} // namespace blender::bke +using NodeDeclarationHandle = blender::nodes::NodeDeclaration; +using SocketDeclarationHandle = blender::nodes::SocketDeclaration; +using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime; +using bNodeRuntimeHandle = blender::bke::bNodeRuntime; +using bNodeSocketRuntimeHandle = blender::bke::bNodeSocketRuntime; +#else +typedef struct NodeDeclarationHandle NodeDeclarationHandle; +typedef struct SocketDeclarationHandle SocketDeclarationHandle; +typedef struct bNodeTreeRuntimeHandle bNodeTreeRuntimeHandle; +typedef struct bNodeRuntimeHandle bNodeRuntimeHandle; +typedef struct bNodeSocketRuntimeHandle bNodeSocketRuntimeHandle; #endif struct AnimData; @@ -30,6 +55,7 @@ struct bNodeLink; struct bNodePreview; struct bNodeTreeExec; struct bNodeType; +struct bNode; struct uiBlock; #define NODE_MAXSTR 64 @@ -65,30 +91,6 @@ typedef struct bNodeStack { #define NS_CR_FIT 4 #define NS_CR_STRETCH 5 -/** Workaround to forward-declare C++ type in C header. */ -#ifdef __cplusplus -namespace blender::nodes { -class NodeDeclaration; -class SocketDeclaration; -} // namespace blender::nodes -namespace blender::bke { -class bNodeTreeRuntime; -class bNodeRuntime; -class bNodeSocketRuntime; -} // namespace blender::bke -using NodeDeclarationHandle = blender::nodes::NodeDeclaration; -using SocketDeclarationHandle = blender::nodes::SocketDeclaration; -using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime; -using bNodeRuntimeHandle = blender::bke::bNodeRuntime; -using bNodeSocketRuntimeHandle = blender::bke::bNodeSocketRuntime; -#else -typedef struct NodeDeclarationHandle NodeDeclarationHandle; -typedef struct SocketDeclarationHandle SocketDeclarationHandle; -typedef struct bNodeTreeRuntimeHandle bNodeTreeRuntimeHandle; -typedef struct bNodeRuntimeHandle bNodeRuntimeHandle; -typedef struct bNodeSocketRuntimeHandle bNodeSocketRuntimeHandle; -#endif - typedef struct bNodeSocket { struct bNodeSocket *next, *prev; @@ -181,6 +183,49 @@ typedef struct bNodeSocket { bNodeStack ns DNA_DEPRECATED; bNodeSocketRuntimeHandle *runtime; + +#ifdef __cplusplus + bool is_available() const; + bool is_multi_input() const; + bool is_input() const; + bool is_output() const; + + /** Utility to access the value of the socket. */ + template<typename T> const T *default_value_typed() const; + + /* The following methods are only available when #bNodeTree.ensure_topology_cache has been + * called. */ + + /** Zero based index for every input and output socket. */ + int index() const; + /** Socket index in the entire node tree. Inputs and outputs share the same index space. */ + int index_in_tree() const; + /** Node this socket belongs to. */ + bNode &owner_node(); + const bNode &owner_node() const; + /** Node tree this socket belongs to. */ + const bNodeTree &owner_tree() const; + + /** Links which are incident to this socket. */ + blender::Span<bNodeLink *> directly_linked_links(); + blender::Span<const bNodeLink *> directly_linked_links() const; + /** Sockets which are connected to this socket with a link. */ + blender::Span<const bNodeSocket *> directly_linked_sockets() const; + bool is_directly_linked() const; + /** + * Sockets which are connected to this socket when reroutes and muted nodes are taken into + * account. + */ + blender::Span<const bNodeSocket *> logically_linked_sockets() const; + bool is_logically_linked() const; + + /** + * For output sockets, this is the corresponding input socket the value of which should be + * forwarded when the node is muted. + */ + const bNodeSocket *internal_link_input() const; + +#endif } bNodeSocket; /** #bNodeSocket.type & #bNodeSocketType.type */ @@ -333,6 +378,38 @@ typedef struct bNode { char iter_flag; bNodeRuntimeHandle *runtime; + +#ifdef __cplusplus + blender::StringRefNull label_or_name() const; + bool is_muted() const; + bool is_reroute() const; + bool is_frame() const; + bool is_group() const; + bool is_group_input() const; + bool is_group_output() const; + const blender::nodes::NodeDeclaration *declaration() const; + + /* The following methods are only available when #bNodeTree.ensure_topology_cache has been + * called. */ + + /** A span containing all input sockets of the node (including unavailable sockets). */ + blender::Span<bNodeSocket *> input_sockets(); + blender::Span<const bNodeSocket *> input_sockets() const; + /** A span containing all output sockets of the node (including unavailable sockets). */ + blender::Span<bNodeSocket *> output_sockets(); + blender::Span<const bNodeSocket *> output_sockets() const; + /** Utility to get an input socket by its index. */ + bNodeSocket &input_socket(int index); + const bNodeSocket &input_socket(int index) const; + /** Utility to get an output socket by its index. */ + bNodeSocket &output_socket(int index); + const bNodeSocket &output_socket(int index) const; + /** A span containing all internal links when the node is muted. */ + blender::Span<const bNodeLink *> internal_links_span() const; + /** Lookup socket of this node by its identifier. */ + const bNodeSocket &input_by_identifier(blender::StringRef identifier) const; + const bNodeSocket &output_by_identifier(blender::StringRef identifier) const; +#endif } bNode; /* node->flag */ @@ -422,6 +499,11 @@ typedef struct bNodeLink { int flag; int multi_input_socket_index; + +#ifdef __cplusplus + bool is_muted() const; +#endif + } bNodeLink; /* link->flag */ @@ -535,6 +617,50 @@ typedef struct bNodeTree { struct PreviewImage *preview; bNodeTreeRuntimeHandle *runtime; + +#ifdef __cplusplus + /** + * Update a run-time cache for the node tree based on it's current state. This makes many methods + * available which allow efficient lookup for topology information (like neighboring sockets). + */ + void ensure_topology_cache() const; + + /* The following methods are only available when #bNodeTree.ensure_topology_cache has been + * called. */ + + /** A span containing all nodes in the node tree. */ + blender::Span<bNode *> all_nodes(); + blender::Span<const bNode *> all_nodes() const; + /** A span containing all input sockets in the node tree. */ + blender::Span<bNodeSocket *> all_input_sockets(); + blender::Span<const bNodeSocket *> all_input_sockets() const; + /** A span containing all output sockets in the node tree. */ + blender::Span<bNodeSocket *> all_output_sockets(); + blender::Span<const bNodeSocket *> all_output_sockets() const; + /** A span containing all sockets in the node tree. */ + blender::Span<bNodeSocket *> all_sockets(); + blender::Span<const bNodeSocket *> all_sockets() const; + /** Efficient lookup of all nodes with a specific type. */ + blender::Span<bNode *> nodes_by_type(blender::StringRefNull type_idname); + blender::Span<const bNode *> nodes_by_type(blender::StringRefNull type_idname) const; + /** + * Cached toposort of all nodes. If there are cycles, the returned array is not actually a + * toposort. However, if a connected component does not contain a cycle, this component is sorted + * correctly. Use #has_link_cycle to check for cycles. + */ + blender::Span<const bNode *> toposort_left_to_right() const; + blender::Span<const bNode *> toposort_right_to_left() const; + /** True when there are any cycles in the node tree. */ + bool has_link_cycle() const; + /** + * True when there are nodes or sockets in the node tree that don't use a known type. This can + * happen when nodes don't exist in the current Blender version that existed in the version where + * this node tree was saved. + */ + bool has_undefined_nodes_or_sockets() const; + /** Get the active group output node. */ + const bNode *group_output_node() const; +#endif } bNodeTree; /** #NodeTree.type, index */ @@ -1475,6 +1601,17 @@ typedef struct NodeCombSepColor { int8_t mode; } NodeCombSepColor; +typedef struct NodeShaderMix { + /* eNodeSocketDatatype */ + int8_t data_type; + /* NodeShaderMixMode */ + int8_t factor_mode; + int8_t clamp_factor; + int8_t clamp_result; + int8_t blend_type; + char _pad[3]; +} NodeShaderMix; + /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 #define NODE_SCRIPT_EXTERNAL 1 @@ -1762,6 +1899,11 @@ typedef enum NodeBooleanMathOperation { NODE_BOOLEAN_MATH_NIMPLY = 8, } NodeBooleanMathOperation; +typedef enum NodeShaderMixMode { + NODE_MIX_MODE_UNIFORM = 0, + NODE_MIX_MODE_NON_UNIFORM = 1, +} NodeShaderMixMode; + typedef enum NodeCompareMode { NODE_COMPARE_MODE_ELEMENT = 0, NODE_COMPARE_MODE_LENGTH = 1, @@ -2194,7 +2336,3 @@ typedef enum NodeCombSepColorMode { NODE_COMBSEP_COLOR_HSV = 1, NODE_COMBSEP_COLOR_HSL = 2, } NodeCombSepColorMode; - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 806513009be..36abe970b31 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -506,6 +506,54 @@ static short *add_struct(int namecode) return sp; } +/* Copied from `BLI_str_startswith` string.c + * to avoid complicating the compilation process of makesdna. */ +static bool str_startswith(const char *__restrict str, const char *__restrict start) +{ + for (; *str && *start; str++, start++) { + if (*str != *start) { + return false; + } + } + + return (*start == '\0'); +} + +/** + * Check if `str` is a preprocessor string that starts with `start`. + * The `start` doesn't need the `#` prefix. + * `ifdef VALUE` will match `#ifdef VALUE` as well as `# ifdef VALUE`. + */ +static bool match_preproc_prefix(const char *__restrict str, const char *__restrict start) +{ + if (*str != '#') { + return false; + } + str++; + while (*str == ' ') { + str++; + } + return str_startswith(str, start); +} + +/** + * \return The point in `str` that starts with `start` or NULL when not found. + * + */ +static char *match_preproc_strstr(char *__restrict str, const char *__restrict start) +{ + while ((str = strchr(str, '#'))) { + str++; + while (*str == ' ') { + str++; + } + if (str_startswith(str, start)) { + return str; + } + } + return NULL; +} + static int preprocess_include(char *maindata, const int maindata_len) { /* NOTE: len + 1, last character is a dummy to prevent @@ -533,6 +581,10 @@ static int preprocess_include(char *maindata, const int maindata_len) cp++; } + /* No need for leading '#' character. */ + const char *cpp_block_start = "ifdef __cplusplus"; + const char *cpp_block_end = "endif"; + /* data from temp copy to maindata, remove comments and double spaces */ cp = temp; char *md = maindata; @@ -577,6 +629,18 @@ static int preprocess_include(char *maindata, const int maindata_len) skip_until_closing_brace = false; } } + else if (match_preproc_prefix(cp, cpp_block_start)) { + char *end_ptr = match_preproc_strstr(cp, cpp_block_end); + + if (end_ptr == NULL) { + fprintf(stderr, "Error: '%s' block must end with '%s'\n", cpp_block_start, cpp_block_end); + } + else { + const int skip_offset = end_ptr - cp + strlen(cpp_block_end); + a -= skip_offset; + cp += skip_offset; + } + } else { md[0] = cp[0]; md++; diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 6f1e3c55dbd..6979b65cfc9 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -422,7 +422,7 @@ static void rna_MeshVertex_hide_set(PointerRNA *ptr, bool value) return; } hide_vert = (bool *)CustomData_add_layer_named( - &mesh->vdata, CD_PROP_BOOL, CD_CALLOC, NULL, mesh->totvert, ".hide_vert"); + &mesh->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totvert, ".hide_vert"); } const int index = rna_MeshVertex_index_get(ptr); hide_vert[index] = value; @@ -556,7 +556,7 @@ static void rna_MeshPolygon_hide_set(PointerRNA *ptr, bool value) return; } hide_poly = (bool *)CustomData_add_layer_named( - &mesh->pdata, CD_PROP_BOOL, CD_CALLOC, NULL, mesh->totpoly, ".hide_poly"); + &mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totpoly, ".hide_poly"); } const int index = rna_MeshPolygon_index_get(ptr); hide_poly[index] = value; @@ -798,7 +798,7 @@ static void rna_MEdge_freestyle_edge_mark_set(PointerRNA *ptr, bool value) FreestyleEdge *fed = CustomData_get(&me->edata, index, CD_FREESTYLE_EDGE); if (!fed) { - fed = CustomData_add_layer(&me->edata, CD_FREESTYLE_EDGE, CD_CALLOC, NULL, me->totedge); + fed = CustomData_add_layer(&me->edata, CD_FREESTYLE_EDGE, CD_SET_DEFAULT, NULL, me->totedge); } if (value) { fed->flag |= FREESTYLE_EDGE_MARK; @@ -824,7 +824,7 @@ static void rna_MPoly_freestyle_face_mark_set(PointerRNA *ptr, bool value) FreestyleFace *ffa = CustomData_get(&me->pdata, index, CD_FREESTYLE_FACE); if (!ffa) { - ffa = CustomData_add_layer(&me->pdata, CD_FREESTYLE_FACE, CD_CALLOC, NULL, me->totpoly); + ffa = CustomData_add_layer(&me->pdata, CD_FREESTYLE_FACE, CD_SET_DEFAULT, NULL, me->totpoly); } if (value) { ffa->flag |= FREESTYLE_FACE_MARK; @@ -1307,7 +1307,7 @@ static void rna_MeshEdge_hide_set(PointerRNA *ptr, bool value) return; } hide_edge = (bool *)CustomData_add_layer_named( - &mesh->edata, CD_PROP_BOOL, CD_CALLOC, NULL, mesh->totedge, ".hide_edge"); + &mesh->edata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totedge, ".hide_edge"); } const int index = rna_MeshEdge_index_get(ptr); hide_edge[index] = value; @@ -1751,7 +1751,8 @@ static void rna_Mesh_sculpt_vertex_color_remove(struct Mesh *me, CustomDataLayer *cdl = NULL; \ int index; \ \ - CustomData_add_layer_named(&me->cdata, cd_prop_type, CD_DEFAULT, NULL, me->countvar, name); \ + CustomData_add_layer_named( \ + &me->cdata, cd_prop_type, CD_SET_DEFAULT, NULL, me->countvar, name); \ index = CustomData_get_named_layer_index(&me->cdata, cd_prop_type, name); \ \ cdl = (index == -1) ? NULL : &(me->cdata.layers[index]); \ diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 8447074a3ef..41b0d0b0bfd 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -44,7 +44,7 @@ static const char *rna_Mesh_unit_test_compare(struct Mesh *mesh, static void rna_Mesh_create_normals_split(Mesh *mesh) { if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { - CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop); + CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_SET_DEFAULT, NULL, mesh->totloop); CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } } @@ -64,7 +64,7 @@ static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char * } else { r_looptangents = CustomData_add_layer( - &mesh->ldata, CD_MLOOPTANGENT, CD_CALLOC, NULL, mesh->totloop); + &mesh->ldata, CD_MLOOPTANGENT, CD_SET_DEFAULT, NULL, mesh->totloop); CustomData_set_layer_flag(&mesh->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY); } diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 1573a1df002..6596acfaf57 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4927,6 +4927,54 @@ static void def_compare(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_sh_mix(StructRNA *srna) +{ + static const EnumPropertyItem rna_enum_mix_data_type_items[] = { + {SOCK_FLOAT, "FLOAT", 0, "Float", ""}, + {SOCK_VECTOR, "VECTOR", 0, "Vector", ""}, + {SOCK_RGBA, "RGBA", 0, "Color", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem rna_enum_mix_mode_items[] = { + {NODE_MIX_MODE_UNIFORM, "UNIFORM", 0, "Uniform", "Use a single factor for all components"}, + {NODE_MIX_MODE_NON_UNIFORM, "NON_UNIFORM", 0, "Non-Uniform", "Per component factor"}, + {0, NULL, 0, NULL, NULL}, + }; + + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeShaderMix", "storage"); + + prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_mix_data_type_items); + RNA_def_property_enum_default(prop, SOCK_FLOAT); + RNA_def_property_ui_text(prop, "Data Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "factor_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_mix_mode_items); + RNA_def_property_enum_default(prop, SOCK_FLOAT); + RNA_def_property_ui_text(prop, "Factor Mode", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "blend_type"); + RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items); + RNA_def_property_ui_text(prop, "Blending Mode", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "clamp_factor", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "clamp_factor", 1); + RNA_def_property_ui_text(prop, "Clamp Factor", "Clamp the factor to [0,1] range"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "clamp_result", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "clamp_result", 1); + RNA_def_property_ui_text(prop, "Clamp Result", "Clamp the result to [0,1] range"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_float_to_int(StructRNA *srna) { PropertyRNA *prop; @@ -10964,6 +11012,11 @@ static void rna_def_node_socket(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Linked", "True if the socket is connected"); + prop = RNA_def_property(srna, "is_unavailable", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_UNAVAIL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Unavailable", "True if the socket is unavailable"); + prop = RNA_def_property(srna, "is_multi_input", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SOCK_MULTI_INPUT); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index 6c5baabe756..8f4a675b797 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -115,7 +115,7 @@ static void deformVerts(ModifierData *md, float(*layerorco)[3]; if (!(layerorco = CustomData_get_layer(&mesh_src->vdata, CD_CLOTH_ORCO))) { layerorco = CustomData_add_layer( - &mesh_src->vdata, CD_CLOTH_ORCO, CD_CALLOC, NULL, mesh_src->totvert); + &mesh_src->vdata, CD_CLOTH_ORCO, CD_SET_DEFAULT, NULL, mesh_src->totvert); } memcpy(layerorco, kb->data, sizeof(float[3]) * verts_num); diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index d3b43176700..2908fbf5597 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -297,6 +297,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte case ID_IM: case ID_TE: { DEG_add_generic_id_relation(ctx->node, id, "Nodes Modifier"); + break; } default: { /* Purposefully don't add relations for materials. While there are material sockets, @@ -755,18 +756,18 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd) } static void initialize_group_input(NodesModifierData &nmd, - const OutputSocketRef &socket, + const bNodeSocket &socket, void *r_value) { - const bNodeSocketType &socket_type = *socket.typeinfo(); - const bNodeSocket &bsocket = *socket.bsocket(); + const bNodeSocketType &socket_type = *socket.typeinfo; + const bNodeSocket &bsocket = socket; const eNodeSocketDatatype socket_data_type = static_cast<eNodeSocketDatatype>(bsocket.type); if (nmd.settings.properties == nullptr) { socket_type.get_geometry_nodes_cpp_value(bsocket, r_value); return; } const IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties, - socket.identifier().c_str()); + socket.identifier); if (property == nullptr) { socket_type.get_geometry_nodes_cpp_value(bsocket, r_value); return; @@ -776,15 +777,15 @@ static void initialize_group_input(NodesModifierData &nmd, return; } - if (!input_has_attribute_toggle(*nmd.node_group, socket.index())) { + if (!input_has_attribute_toggle(*nmd.node_group, socket.runtime->index_in_node)) { init_socket_cpp_value_from_property(*property, socket_data_type, r_value); return; } const IDProperty *property_use_attribute = IDP_GetPropertyFromGroup( - nmd.settings.properties, (socket.identifier() + use_attribute_suffix).c_str()); + nmd.settings.properties, (socket.identifier + use_attribute_suffix).c_str()); const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup( - nmd.settings.properties, (socket.identifier() + attribute_name_suffix).c_str()); + nmd.settings.properties, (socket.identifier + attribute_name_suffix).c_str()); if (property_use_attribute == nullptr || property_attribute_name == nullptr) { init_socket_cpp_value_from_property(*property, socket_data_type, r_value); return; @@ -866,11 +867,11 @@ static void find_sockets_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadshe const DTreeContext *context = &tree.root_context(); for (SpreadsheetContextNode *node_context : nested_group_contexts) { - const NodeTreeRef &tree_ref = context->tree(); - const NodeRef *found_node = nullptr; - for (const NodeRef *node_ref : tree_ref.nodes()) { - if (node_ref->name() == node_context->node_name) { - found_node = node_ref; + const bNodeTree &btree = context->btree(); + const bNode *found_node = nullptr; + for (const bNode *bnode : btree.all_nodes()) { + if (STREQ(bnode->name, node_context->node_name)) { + found_node = bnode; break; } } @@ -883,11 +884,11 @@ static void find_sockets_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadshe } } - const NodeTreeRef &tree_ref = context->tree(); - for (const NodeRef *node_ref : tree_ref.nodes_by_type("GeometryNodeViewer")) { - if (node_ref->name() == last_context->node_name) { - const DNode viewer_node{context, node_ref}; - for (const InputSocketRef *input_socket : node_ref->inputs()) { + const bNodeTree &btree = context->btree(); + for (const bNode *bnode : btree.nodes_by_type("GeometryNodeViewer")) { + if (STREQ(bnode->name, last_context->node_name)) { + const DNode viewer_node{context, bnode}; + for (const bNodeSocket *input_socket : bnode->input_sockets()) { if (input_socket->is_available() && input_socket->is_logically_linked()) { r_sockets_to_preview.add(DSocket{context, input_socket}); } @@ -936,15 +937,15 @@ struct OutputAttributeToStore { * can be evaluated together. */ static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to_store( - const NodesModifierData &nmd, const NodeRef &output_node, Span<GMutablePointer> output_values) + const NodesModifierData &nmd, const bNode &output_node, Span<GMutablePointer> output_values) { MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain; - for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) { - if (!socket_type_has_attribute_toggle(*socket->bsocket())) { + for (const bNodeSocket *socket : output_node.input_sockets().drop_front(1).drop_back(1)) { + if (!socket_type_has_attribute_toggle(*socket)) { continue; } - const std::string prop_name = socket->identifier() + attribute_name_suffix; + const std::string prop_name = socket->identifier + attribute_name_suffix; const IDProperty *prop = IDP_GetPropertyFromGroup(nmd.settings.properties, prop_name.c_str()); if (prop == nullptr) { continue; @@ -964,7 +965,7 @@ static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to const GField field = cpp_type->as_field(value.get()); const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink( - &nmd.node_group->outputs, socket->index()); + &nmd.node_group->outputs, index); const eAttrDomain domain = (eAttrDomain)interface_socket->attribute_domain; OutputAttributeInfo output_info; output_info.field = std::move(field); @@ -1044,7 +1045,7 @@ static void store_computed_output_attributes( if (attributes.add(store.name, store.domain, blender::bke::cpp_type_to_custom_data_type(store.data.type()), - blender::bke::AttributeInitMove(store.data.data()))) { + blender::bke::AttributeInitMoveArray(store.data.data()))) { continue; } @@ -1063,7 +1064,7 @@ static void store_computed_output_attributes( static void store_output_attributes(GeometrySet &geometry, const NodesModifierData &nmd, - const NodeRef &output_node, + const bNode &output_node, Span<GMutablePointer> output_values) { /* All new attribute values have to be computed before the geometry is actually changed. This is @@ -1079,8 +1080,8 @@ static void store_output_attributes(GeometrySet &geometry, * Evaluate a node group to compute the output geometry. */ static GeometrySet compute_geometry(const DerivedNodeTree &tree, - Span<const NodeRef *> group_input_nodes, - const NodeRef &output_node, + Span<const bNode *> group_input_nodes, + const bNode &output_node, GeometrySet input_geometry_set, NodesModifierData *nmd, const ModifierEvalContext *ctx) @@ -1092,18 +1093,19 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, Map<DOutputSocket, GMutablePointer> group_inputs; const DTreeContext *root_context = &tree.root_context(); - for (const NodeRef *group_input_node : group_input_nodes) { - Span<const OutputSocketRef *> group_input_sockets = group_input_node->outputs().drop_back(1); + for (const bNode *group_input_node : group_input_nodes) { + Span<const bNodeSocket *> group_input_sockets = group_input_node->output_sockets().drop_back( + 1); if (group_input_sockets.is_empty()) { continue; } - Span<const OutputSocketRef *> remaining_input_sockets = group_input_sockets; + Span<const bNodeSocket *> remaining_input_sockets = group_input_sockets; /* If the group expects a geometry as first input, use the geometry that has been passed to * modifier. */ - const OutputSocketRef *first_input_socket = group_input_sockets[0]; - if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) { + const bNodeSocket *first_input_socket = group_input_sockets[0]; + if (first_input_socket->type == SOCK_GEOMETRY) { GeometrySet *geometry_set_in = allocator.construct<GeometrySet>(input_geometry_set).release(); group_inputs.add_new({root_context, first_input_socket}, geometry_set_in); @@ -1111,8 +1113,8 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, } /* Initialize remaining group inputs. */ - for (const OutputSocketRef *socket : remaining_input_sockets) { - const CPPType &cpp_type = *socket->typeinfo()->geometry_nodes_cpp_type; + for (const bNodeSocket *socket : remaining_input_sockets) { + const CPPType &cpp_type = *socket->typeinfo->geometry_nodes_cpp_type; void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment()); initialize_group_input(*nmd, *socket, value_in); group_inputs.add_new({root_context, socket}, {cpp_type, value_in}); @@ -1120,7 +1122,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, } Vector<DInputSocket> group_outputs; - for (const InputSocketRef *socket_ref : output_node.inputs().drop_back(1)) { + for (const bNodeSocket *socket_ref : output_node.input_sockets().drop_back(1)) { group_outputs.append({root_context, socket_ref}); } @@ -1225,8 +1227,8 @@ static void modifyGeometry(ModifierData *md, check_property_socket_sync(ctx->object, md); - NodeTreeRefMap tree_refs; - DerivedNodeTree tree{*nmd->node_group, tree_refs}; + const bNodeTree &root_tree_ref = *nmd->node_group; + DerivedNodeTree tree{root_tree_ref}; if (tree.has_link_cycles()) { BKE_modifier_set_error(ctx->object, md, "Node group has cycles"); @@ -1234,25 +1236,24 @@ static void modifyGeometry(ModifierData *md, return; } - const NodeTreeRef &root_tree_ref = tree.root_context().tree(); - Span<const NodeRef *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput"); - Span<const NodeRef *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput"); + Span<const bNode *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput"); + Span<const bNode *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput"); if (output_nodes.size() != 1) { BKE_modifier_set_error(ctx->object, md, "Node group must have a single output node"); geometry_set.clear(); return; } - const NodeRef &output_node = *output_nodes[0]; - Span<const InputSocketRef *> group_outputs = output_node.inputs().drop_back(1); + const bNode &output_node = *output_nodes[0]; + Span<const bNodeSocket *> group_outputs = output_node.input_sockets().drop_back(1); if (group_outputs.is_empty()) { BKE_modifier_set_error(ctx->object, md, "Node group must have an output socket"); geometry_set.clear(); return; } - const InputSocketRef *first_output_socket = group_outputs[0]; - if (first_output_socket->idname() != "NodeSocketGeometry") { + const bNodeSocket *first_output_socket = group_outputs[0]; + if (!STREQ(first_output_socket->idname, "NodeSocketGeometry")) { BKE_modifier_set_error(ctx->object, md, "Node group's first output must be a geometry"); geometry_set.clear(); return; @@ -1277,13 +1278,13 @@ static void modifyGeometry(ModifierData *md, * assumed that the output mesh does not have a mapping to the original mesh. */ Mesh &mesh = *geometry_set.get_mesh_for_write(); if (use_orig_index_verts) { - CustomData_add_layer(&mesh.vdata, CD_ORIGINDEX, CD_DEFAULT, nullptr, mesh.totvert); + CustomData_add_layer(&mesh.vdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh.totvert); } if (use_orig_index_edges) { - CustomData_add_layer(&mesh.edata, CD_ORIGINDEX, CD_DEFAULT, nullptr, mesh.totedge); + CustomData_add_layer(&mesh.edata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh.totedge); } if (use_orig_index_polys) { - CustomData_add_layer(&mesh.pdata, CD_ORIGINDEX, CD_DEFAULT, nullptr, mesh.totpoly); + CustomData_add_layer(&mesh.pdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh.totpoly); } } } diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 5cf4e21ea68..dd7c87ca499 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -2,6 +2,7 @@ #include "MOD_nodes_evaluator.hh" +#include "BKE_node.h" #include "BKE_type_conversions.hh" #include "NOD_geometry_exec.hh" @@ -319,9 +320,9 @@ class LockedNode : NonCopyable, NonMovable { } }; -static const CPPType *get_socket_cpp_type(const SocketRef &socket) +static const CPPType *get_socket_cpp_type(const bNodeSocket &socket) { - const bNodeSocketType *typeinfo = socket.typeinfo(); + const bNodeSocketType *typeinfo = socket.typeinfo; if (typeinfo->geometry_nodes_cpp_type == nullptr) { return nullptr; } @@ -338,24 +339,24 @@ static const CPPType *get_socket_cpp_type(const SocketRef &socket) static const CPPType *get_socket_cpp_type(const DSocket socket) { - return get_socket_cpp_type(*socket.socket_ref()); + return get_socket_cpp_type(*socket); } /** * \note This is not supposed to be a long term solution. Eventually we want that nodes can * specify more complex defaults (other than just single values) in their socket declarations. */ -static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) +static bool get_implicit_socket_input(const bNodeSocket &socket, void *r_value) { - const NodeRef &node = socket.node(); - const nodes::NodeDeclaration *node_declaration = node.declaration(); + const bNode &node = socket.owner_node(); + const nodes::NodeDeclaration *node_declaration = node.runtime->declaration; if (node_declaration == nullptr) { return false; } const nodes::SocketDeclaration &socket_declaration = *node_declaration->inputs()[socket.index()]; if (socket_declaration.input_field_type() == nodes::InputSocketFieldType::Implicit) { - const bNode &bnode = *socket.bnode(); - if (socket.typeinfo()->type == SOCK_VECTOR) { + const bNode &bnode = socket.owner_node(); + if (socket.typeinfo->type == SOCK_VECTOR) { if (bnode.type == GEO_NODE_SET_CURVE_HANDLES) { StringRef side = ((NodeGeometrySetCurveHandlePositions *)bnode.storage)->mode == GEO_NODE_CURVE_HANDLE_LEFT ? @@ -372,7 +373,7 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>("position")); return true; } - if (socket.typeinfo()->type == SOCK_INT) { + if (socket.typeinfo->type == SOCK_INT) { if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) { new (r_value) ValueOrField<int>(Field<int>(std::make_shared<bke::IDAttributeFieldInput>())); @@ -385,19 +386,19 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) return false; } -static void get_socket_value(const SocketRef &socket, void *r_value) +static void get_socket_value(const bNodeSocket &socket, void *r_value) { if (get_implicit_socket_input(socket, r_value)) { return; } - const bNodeSocketType *typeinfo = socket.typeinfo(); - typeinfo->get_geometry_nodes_cpp_value(*socket.bsocket(), r_value); + const bNodeSocketType *typeinfo = socket.typeinfo; + typeinfo->get_geometry_nodes_cpp_value(socket, r_value); } static bool node_supports_laziness(const DNode node) { - return node->typeinfo()->geometry_node_execute_supports_laziness; + return node->typeinfo->geometry_node_execute_supports_laziness; } struct NodeTaskRunState { @@ -516,9 +517,9 @@ class GeometryNodesEvaluator { node_states_.add_new({node, &node_state}); /* Push all linked origins on the stack. */ - for (const InputSocketRef *input_ref : node->inputs()) { - const DInputSocket input{node.context(), input_ref}; - input.foreach_origin_socket( + for (const bNodeSocket *input : node->input_sockets()) { + const DInputSocket dinput{node.context(), input}; + dinput.foreach_origin_socket( [&](const DSocket origin) { nodes_to_check.push(origin.node()); }); } } @@ -546,11 +547,11 @@ class GeometryNodesEvaluator { void initialize_node_state(const DNode node, NodeState &node_state, LinearAllocator<> &allocator) { /* Construct arrays of the correct size. */ - node_state.inputs = allocator.construct_array<InputState>(node->inputs().size()); - node_state.outputs = allocator.construct_array<OutputState>(node->outputs().size()); + node_state.inputs = allocator.construct_array<InputState>(node->input_sockets().size()); + node_state.outputs = allocator.construct_array<OutputState>(node->output_sockets().size()); /* Initialize input states. */ - for (const int i : node->inputs().index_range()) { + for (const int i : node->input_sockets().index_range()) { InputState &input_state = node_state.inputs[i]; const DInputSocket socket = node.input(i); if (!socket->is_available()) { @@ -567,7 +568,7 @@ class GeometryNodesEvaluator { continue; } /* Construct the correct struct that can hold the input(s). */ - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { input_state.value.multi = allocator.construct<MultiInputValue>().release(); MultiInputValue &multi_value = *input_state.value.multi; /* Count how many values should be added until the socket is complete. */ @@ -583,7 +584,7 @@ class GeometryNodesEvaluator { } } /* Initialize output states. */ - for (const int i : node->outputs().index_range()) { + for (const int i : node->output_sockets().index_range()) { OutputState &output_state = node_state.outputs[i]; const DOutputSocket socket = node.output(i); if (!socket->is_available()) { @@ -629,13 +630,13 @@ class GeometryNodesEvaluator { void destruct_node_state(const DNode node, NodeState &node_state) { /* Need to destruct stuff manually, because it's allocated by a custom allocator. */ - for (const int i : node->inputs().index_range()) { + for (const int i : node->input_sockets().index_range()) { InputState &input_state = node_state.inputs[i]; if (input_state.type == nullptr) { continue; } - const InputSocketRef &socket_ref = node->input(i); - if (socket_ref.is_multi_input_socket()) { + const bNodeSocket &bsocket = node->input_socket(i); + if (bsocket.is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; for (void *value : multi_value.values) { if (value != nullptr) { @@ -756,7 +757,7 @@ class GeometryNodesEvaluator { { /* These nodes are sometimes scheduled. We could also check for them in other places, but * it's the easiest to do it here. */ - if (node->is_group_input_node() || node->is_group_output_node()) { + if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { return; } @@ -837,7 +838,7 @@ class GeometryNodesEvaluator { /* If there are no remaining outputs, all the inputs can be destructed and/or can become * unused. This can also trigger a chain reaction where nodes to the left become finished * too. */ - for (const int i : locked_node.node->inputs().index_range()) { + for (const int i : locked_node.node->input_sockets().index_range()) { const DInputSocket socket = locked_node.node.input(i); InputState &input_state = locked_node.node_state.inputs[i]; if (input_state.usage == ValueUsage::Maybe) { @@ -883,7 +884,7 @@ class GeometryNodesEvaluator { return; } /* Nodes that don't support laziness require all inputs. */ - for (const int i : locked_node.node->inputs().index_range()) { + for (const int i : locked_node.node->input_sockets().index_range()) { InputState &input_state = locked_node.node_state.inputs[i]; if (input_state.type == nullptr) { /* Ignore unavailable/non-data sockets. */ @@ -915,7 +916,7 @@ class GeometryNodesEvaluator { continue; } - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; /* Checks if all the linked sockets have been provided already. */ if (multi_value.all_values_available()) { @@ -949,7 +950,7 @@ class GeometryNodesEvaluator { */ void execute_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state) { - const bNode &bnode = *node->bnode(); + const bNode &bnode = *node; if (node_state.has_been_executed) { if (!node_supports_laziness(node)) { @@ -978,7 +979,7 @@ class GeometryNodesEvaluator { void execute_geometry_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state) { using Clock = std::chrono::steady_clock; - const bNode &bnode = *node->bnode(); + const bNode &bnode = *node; NodeParamsProvider params_provider{*this, node, node_state, run_state}; GeoNodeExecParams params{params_provider}; @@ -1002,12 +1003,12 @@ class GeometryNodesEvaluator { bool any_input_is_field = false; Vector<const void *, 16> input_values; Vector<const ValueOrFieldCPPType *, 16> input_types; - for (const int i : node->inputs().index_range()) { - const InputSocketRef &socket_ref = node->input(i); - if (!socket_ref.is_available()) { + for (const int i : node->input_sockets().index_range()) { + const bNodeSocket &bsocket = node->input_socket(i); + if (!bsocket.is_available()) { continue; } - BLI_assert(!socket_ref.is_multi_input_socket()); + BLI_assert(!bsocket.is_multi_input()); InputState &input_state = node_state.inputs[i]; BLI_assert(input_state.was_ready_for_execution); SingleInputValue &single_value = *input_state.value.single; @@ -1055,15 +1056,15 @@ class GeometryNodesEvaluator { } int output_index = 0; - for (const int i : node->outputs().index_range()) { - const OutputSocketRef &socket_ref = node->output(i); - if (!socket_ref.is_available()) { + for (const int i : node->output_sockets().index_range()) { + const bNodeSocket &bsocket = node->output_socket(i); + if (!bsocket.is_available()) { continue; } OutputState &output_state = node_state.outputs[i]; - const DOutputSocket socket{node.context(), &socket_ref}; + const DOutputSocket socket{node.context(), &bsocket}; const ValueOrFieldCPPType *cpp_type = static_cast<const ValueOrFieldCPPType *>( - get_socket_cpp_type(socket_ref)); + get_socket_cpp_type(bsocket)); GField new_field{operation, output_index}; void *buffer = allocator.allocate(cpp_type->size(), cpp_type->alignment()); cpp_type->construct_from_field(buffer, std::move(new_field)); @@ -1091,7 +1092,7 @@ class GeometryNodesEvaluator { } Vector<GMutablePointer, 16> output_buffers; - for (const int i : node->outputs().index_range()) { + for (const int i : node->output_sockets().index_range()) { const DOutputSocket socket = node.output(i); if (!socket->is_available()) { output_buffers.append({}); @@ -1128,7 +1129,7 @@ class GeometryNodesEvaluator { void execute_unknown_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state) { LinearAllocator<> &allocator = local_allocators_.local(); - for (const OutputSocketRef *socket : node->outputs()) { + for (const bNodeSocket *socket : node->output_sockets()) { if (!socket->is_available()) { continue; } @@ -1182,8 +1183,8 @@ class GeometryNodesEvaluator { const bool supports_laziness = node_supports_laziness(locked_node.node); /* Iterating over sockets instead of the states directly, because that makes it easier to * figure out which socket is missing when one of the asserts is hit. */ - for (const OutputSocketRef *socket_ref : locked_node.node->outputs()) { - OutputState &output_state = locked_node.node_state.outputs[socket_ref->index()]; + for (const bNodeSocket *bsocket : locked_node.node->output_sockets()) { + OutputState &output_state = locked_node.node_state.outputs[bsocket->index()]; if (supports_laziness) { /* Expected that at least all required sockets have been computed. If more outputs become * required later, the node will be executed again. */ @@ -1208,7 +1209,7 @@ class GeometryNodesEvaluator { { for (const DInputSocket &socket : params_.output_sockets) { BLI_assert(socket->is_available()); - BLI_assert(!socket->is_multi_input_socket()); + BLI_assert(!socket->is_multi_input()); const DNode node = socket.node(); NodeState &node_state = this->get_node_state(node); @@ -1255,7 +1256,7 @@ class GeometryNodesEvaluator { /* Count how many values still have to be added to this input until it is "complete". */ int missing_values = 0; - if (input_socket->is_multi_input_socket()) { + if (input_socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; missing_values = multi_value.missing_values(); } @@ -1402,52 +1403,51 @@ class GeometryNodesEvaluator { Vector<DInputSocket> forward_original_value_sockets; log_original_value_sockets.append(from_socket); - from_socket.foreach_target_socket( - [&](const DInputSocket to_socket, const DOutputSocket::TargetSocketPathInfo &path_info) { - if (!this->should_forward_to_socket(to_socket)) { - return; - } - BLI_assert(to_socket == path_info.sockets.last()); - GMutablePointer current_value = value_to_forward; - for (const DSocket &next_socket : path_info.sockets) { - const DNode next_node = next_socket.node(); - const bool is_last_socket = to_socket == next_socket; - const bool do_conversion_if_necessary = is_last_socket || - next_node->is_group_output_node() || - (next_node->is_group_node() && - !next_node->is_muted()); - if (do_conversion_if_necessary) { - const CPPType &next_type = *get_socket_cpp_type(next_socket); - if (*current_value.type() != next_type) { - void *buffer = allocator.allocate(next_type.size(), next_type.alignment()); - this->convert_value(*current_value.type(), next_type, current_value.get(), buffer); - if (current_value.get() != value_to_forward.get()) { - current_value.destruct(); - } - current_value = {next_type, buffer}; - } - } - if (current_value.get() == value_to_forward.get()) { - /* Log the original value at the current socket. */ - log_original_value_sockets.append(next_socket); - } - else { - /* Multi-input sockets are logged when all values are available. */ - if (!(next_socket->is_input() && next_socket->as_input().is_multi_input_socket())) { - /* Log the converted value at the socket. */ - this->log_socket_value({next_socket}, current_value); - } + from_socket.foreach_target_socket([&](const DInputSocket to_socket, + const DOutputSocket::TargetSocketPathInfo &path_info) { + if (!this->should_forward_to_socket(to_socket)) { + return; + } + BLI_assert(to_socket == path_info.sockets.last()); + GMutablePointer current_value = value_to_forward; + for (const DSocket &next_socket : path_info.sockets) { + const DNode next_node = next_socket.node(); + const bool is_last_socket = to_socket == next_socket; + const bool do_conversion_if_necessary = is_last_socket || + next_node->type == NODE_GROUP_OUTPUT || + (next_node->is_group() && !next_node->is_muted()); + if (do_conversion_if_necessary) { + const CPPType &next_type = *get_socket_cpp_type(next_socket); + if (*current_value.type() != next_type) { + void *buffer = allocator.allocate(next_type.size(), next_type.alignment()); + this->convert_value(*current_value.type(), next_type, current_value.get(), buffer); + if (current_value.get() != value_to_forward.get()) { + current_value.destruct(); } + current_value = {next_type, buffer}; } - if (current_value.get() == value_to_forward.get()) { - /* The value has not been converted, so forward the original value. */ - forward_original_value_sockets.append(to_socket); - } - else { - /* The value has been converted. */ - this->add_value_to_input_socket(to_socket, from_socket, current_value, run_state); + } + if (current_value.get() == value_to_forward.get()) { + /* Log the original value at the current socket. */ + log_original_value_sockets.append(next_socket); + } + else { + /* Multi-input sockets are logged when all values are available. */ + if (!(next_socket->is_input() && next_socket->is_multi_input())) { + /* Log the converted value at the socket. */ + this->log_socket_value({next_socket}, current_value); } - }); + } + } + if (current_value.get() == value_to_forward.get()) { + /* The value has not been converted, so forward the original value. */ + forward_original_value_sockets.append(to_socket); + } + else { + /* The value has been converted. */ + this->add_value_to_input_socket(to_socket, from_socket, current_value, run_state); + } + }); this->log_socket_value(log_original_value_sockets, value_to_forward); this->forward_to_sockets_with_same_type( allocator, forward_original_value_sockets, value_to_forward, from_socket, run_state); @@ -1512,7 +1512,7 @@ class GeometryNodesEvaluator { InputState &input_state = node_state.inputs[socket->index()]; this->with_locked_node(node, node_state, run_state, [&](LockedNode &locked_node) { - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { /* Add a new value to the multi-input. */ MultiInputValue &multi_value = *input_state.value.multi; multi_value.add_value(origin, value.get()); @@ -1555,7 +1555,7 @@ class GeometryNodesEvaluator { UNUSED_VARS(locked_node); GMutablePointer value = this->get_value_from_socket(origin_socket, *input_state.type); - if (input_socket->is_multi_input_socket()) { + if (input_socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; multi_value.add_value(origin_socket, value.get()); if (multi_value.all_values_available()) { @@ -1580,7 +1580,7 @@ class GeometryNodesEvaluator { void destruct_input_value_if_exists(LockedNode &locked_node, const DInputSocket socket) { InputState &input_state = locked_node.node_state.inputs[socket->index()]; - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; for (void *&value : multi_value.values) { if (value != nullptr) { @@ -1605,7 +1605,7 @@ class GeometryNodesEvaluator { const CPPType &type = *get_socket_cpp_type(socket); void *buffer = allocator.allocate(type.size(), type.alignment()); - get_socket_value(*socket.socket_ref(), buffer); + get_socket_value(*socket.bsocket(), buffer); if (type == required_type) { return {type, buffer}; @@ -1762,7 +1762,7 @@ bool NodeParamsProvider::can_get_input(StringRef identifier) const return false; } - if (socket->is_multi_input_socket()) { + if (socket->is_multi_input()) { MultiInputValue &multi_value = *input_state.value.multi; return multi_value.all_values_available(); } @@ -1783,7 +1783,7 @@ GMutablePointer NodeParamsProvider::extract_input(StringRef identifier) { const DInputSocket socket = this->dnode.input_by_identifier(identifier); BLI_assert(socket); - BLI_assert(!socket->is_multi_input_socket()); + BLI_assert(!socket->is_multi_input()); BLI_assert(this->can_get_input(identifier)); InputState &input_state = node_state_.inputs[socket->index()]; @@ -1797,7 +1797,7 @@ Vector<GMutablePointer> NodeParamsProvider::extract_multi_input(StringRef identi { const DInputSocket socket = this->dnode.input_by_identifier(identifier); BLI_assert(socket); - BLI_assert(socket->is_multi_input_socket()); + BLI_assert(socket->is_multi_input()); BLI_assert(this->can_get_input(identifier)); InputState &input_state = node_state_.inputs[socket->index()]; @@ -1816,7 +1816,7 @@ GPointer NodeParamsProvider::get_input(StringRef identifier) const { const DInputSocket socket = this->dnode.input_by_identifier(identifier); BLI_assert(socket); - BLI_assert(!socket->is_multi_input_socket()); + BLI_assert(!socket->is_multi_input()); BLI_assert(this->can_get_input(identifier)); InputState &input_state = node_state_.inputs[socket->index()]; @@ -1901,7 +1901,7 @@ void NodeParamsProvider::set_default_remaining_outputs() { LinearAllocator<> &allocator = evaluator_.local_allocators_.local(); - for (const int i : this->dnode->outputs().index_range()) { + for (const int i : this->dnode->output_sockets().index_range()) { OutputState &output_state = node_state_.outputs[i]; if (output_state.has_been_computed) { continue; diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 5a92aac6cda..9e3e06fb4dc 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -562,7 +562,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, } if (clnors == NULL) { - clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, loops_num); + clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, NULL, loops_num); } MOD_get_vgroup(ob, result, enmd->defgrp_name, &dvert, &defgrp_index); diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index ea9049200cc..c84d1b56cec 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -292,7 +292,7 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig, co /* add uvs */ if (CustomData_number_of_layers(&result->ldata, CD_MLOOPUV) < MAX_MTFACE) { gogd.mloopuvs = CustomData_add_layer( - &result->ldata, CD_MLOOPUV, CD_CALLOC, NULL, polys_num * 4); + &result->ldata, CD_MLOOPUV, CD_SET_DEFAULT, NULL, polys_num * 4); if (gogd.mloopuvs) { /* unlikely to fail */ gogd.ix = 1.0 / gogd.rx; @@ -378,12 +378,16 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes const int loops_num = result->totloop; MLoop *mloops = result->mloop; MLoopCol *mloopcols = CustomData_add_layer_named( - &result->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, NULL, loops_num, omd->foamlayername); + &result->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, NULL, loops_num, omd->foamlayername); MLoopCol *mloopcols_spray = NULL; if (omd->flag & MOD_OCEAN_GENERATE_SPRAY) { - mloopcols_spray = CustomData_add_layer_named( - &result->ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, NULL, loops_num, omd->spraylayername); + mloopcols_spray = CustomData_add_layer_named(&result->ldata, + CD_PROP_BYTE_COLOR, + CD_SET_DEFAULT, + NULL, + loops_num, + omd->spraylayername); } if (mloopcols) { /* unlikely to fail */ diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 3d6a8e27b08..d8b11c0e89e 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -398,7 +398,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * medge_new = result->medge; if (!CustomData_has_layer(&result->pdata, CD_ORIGINDEX)) { - CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys); + CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, (int)maxPolys); } int *origindex = CustomData_get_layer(&result->pdata, CD_ORIGINDEX); diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 84795cdb2d9..982f5802df6 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -1888,7 +1888,7 @@ static void skin_set_orig_indices(Mesh *mesh) int *orig, totpoly; totpoly = mesh->totpoly; - orig = CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, totpoly); + orig = CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CONSTRUCT, NULL, totpoly); copy_vn_i(orig, totpoly, ORIGINDEX_NONE); } diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c index 53c6ee9a1a8..aa8c49ee0b8 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.c +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c @@ -996,7 +996,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex if (dvert == NULL) { /* Add a valid data layer! */ dvert = CustomData_add_layer( - &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, result->totvert); + &result->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, result->totvert); } /* Ultimate security check. */ if (dvert != NULL) { diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c index 64a00478ce8..29adbd70198 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c @@ -1981,7 +1981,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, if (dvert == NULL) { /* Add a valid data layer! */ dvert = CustomData_add_layer( - &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, result->totvert); + &result->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, result->totvert); } result->dvert = dvert; } diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 4646ba41a74..ccef867b752 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -124,7 +124,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, * (e.g. if a preceding modifier could not preserve it). */ if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) { CustomData_add_layer_named( - &mesh->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, mesh->totloop, umd->uvlayer_name); + &mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, NULL, mesh->totloop, umd->uvlayer_name); } /* make sure we're using an existing layer */ diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index 039497b725b..5b5d464a710 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -609,7 +609,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * * it helps when generating clnor spaces and default normals. */ const bool has_clnors = clnors != NULL; if (!clnors) { - clnors = CustomData_add_layer(&result->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, loops_num); + clnors = CustomData_add_layer( + &result->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, NULL, loops_num); } MDeformVert *dvert; diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index 2a509ddf220..d71813c7dd5 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -203,7 +203,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } else { /* Add a valid data layer! */ - dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, verts_num); + dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, verts_num); } /* Ultimate security check. */ if (!dvert) { diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index aa648eaec97..1d38333f15b 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -268,7 +268,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } else { /* Add a valid data layer! */ - dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, verts_num); + dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, verts_num); } /* Ultimate security check. */ if (!dvert) { diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index ae31fd7ff5f..ff8bd27f8d7 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -49,7 +49,6 @@ set(SRC intern/node_multi_function.cc intern/node_socket.cc intern/node_socket_declarations.cc - intern/node_tree_ref.cc intern/node_util.c intern/socket_search_link.cc @@ -63,7 +62,6 @@ set(SRC NOD_math_functions.hh NOD_multi_function.hh NOD_node_declaration.hh - NOD_node_tree_ref.hh NOD_shader.h NOD_socket.h NOD_socket_declarations.hh diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index b0799d90dcd..b3775e729da 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -5,16 +5,17 @@ /** \file * \ingroup nodes * - * DerivedNodeTree builds on top of NodeTreeRef and makes working with (nested) node groups more - * convenient and safe. It does so by pairing nodes and sockets with a context. The context - * contains information about the current "instance" of the node or socket. A node might be - * "instanced" multiple times when it is in a node group that is used multiple times. + * DerivedNodeTree makes working with (nested) node groups more convenient and safe. It does so by + * pairing nodes and sockets with a context. The context contains information about the current + * "instance" of the node or socket. A node might be "instanced" multiple times when it is in a + * node group that is used multiple times. */ #include "BLI_function_ref.hh" +#include "BLI_linear_allocator.hh" #include "BLI_vector_set.hh" -#include "NOD_node_tree_ref.hh" +#include "BKE_node_runtime.hh" namespace blender::nodes { @@ -40,20 +41,20 @@ class DTreeContext { DTreeContext *parent_context_; /* Null when this context is for the root node group. Otherwise it points to the group node in * the parent node group that contains this context. */ - const NodeRef *parent_node_; + const bNode *parent_node_; /* The current node tree. */ - const NodeTreeRef *tree_; + const bNodeTree *btree_; /* All the children contexts of this context. */ - Map<const NodeRef *, DTreeContext *> children_; + Map<const bNode *, DTreeContext *> children_; DerivedNodeTree *derived_tree_; friend DerivedNodeTree; public: - const NodeTreeRef &tree() const; + const bNodeTree &btree() const; const DTreeContext *parent_context() const; - const NodeRef *parent_node() const; - const DTreeContext *child_context(const NodeRef &node) const; + const bNode *parent_node() const; + const DTreeContext *child_context(const bNode &node) const; const DerivedNodeTree &derived_tree() const; bool is_root() const; }; @@ -65,15 +66,16 @@ class DTreeContext { class DNode { private: const DTreeContext *context_ = nullptr; - const NodeRef *node_ref_ = nullptr; + const bNode *bnode_ = nullptr; public: DNode() = default; - DNode(const DTreeContext *context, const NodeRef *node); + DNode(const DTreeContext *context, const bNode *node); const DTreeContext *context() const; - const NodeRef *node_ref() const; - const NodeRef *operator->() const; + const bNode *bnode() const; + const bNode *operator->() const; + const bNode &operator*() const; friend bool operator==(const DNode &a, const DNode &b); friend bool operator!=(const DNode &a, const DNode &b); @@ -98,17 +100,18 @@ class DNode { class DSocket { protected: const DTreeContext *context_ = nullptr; - const SocketRef *socket_ref_ = nullptr; + const bNodeSocket *bsocket_ = nullptr; public: DSocket() = default; - DSocket(const DTreeContext *context, const SocketRef *socket); + DSocket(const DTreeContext *context, const bNodeSocket *socket); DSocket(const DInputSocket &input_socket); DSocket(const DOutputSocket &output_socket); const DTreeContext *context() const; - const SocketRef *socket_ref() const; - const SocketRef *operator->() const; + const bNodeSocket *bsocket() const; + const bNodeSocket *operator->() const; + const bNodeSocket &operator*() const; friend bool operator==(const DSocket &a, const DSocket &b); friend bool operator!=(const DSocket &a, const DSocket &b); @@ -123,12 +126,9 @@ class DSocket { class DInputSocket : public DSocket { public: DInputSocket() = default; - DInputSocket(const DTreeContext *context, const InputSocketRef *socket); + DInputSocket(const DTreeContext *context, const bNodeSocket *socket); explicit DInputSocket(const DSocket &base_socket); - const InputSocketRef *socket_ref() const; - const InputSocketRef *operator->() const; - DOutputSocket get_corresponding_group_node_output() const; Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const; @@ -144,12 +144,9 @@ class DInputSocket : public DSocket { class DOutputSocket : public DSocket { public: DOutputSocket() = default; - DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket); + DOutputSocket(const DTreeContext *context, const bNodeSocket *socket); explicit DOutputSocket(const DSocket &base_socket); - const OutputSocketRef *socket_ref() const; - const OutputSocketRef *operator->() const; - DInputSocket get_corresponding_group_node_input() const; DInputSocket get_active_corresponding_group_output_socket() const; @@ -177,7 +174,7 @@ class DerivedNodeTree { private: LinearAllocator<> allocator_; DTreeContext *root_context_; - VectorSet<const NodeTreeRef *> used_node_tree_refs_; + VectorSet<const bNodeTree *> used_btrees_; public: /** @@ -186,11 +183,11 @@ class DerivedNodeTree { * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the * derived node tree. */ - DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs); + DerivedNodeTree(const bNodeTree &btree); ~DerivedNodeTree(); const DTreeContext &root_context() const; - Span<const NodeTreeRef *> used_node_tree_refs() const; + Span<const bNodeTree *> used_btrees() const; /** * \return True when there is a link cycle. Unavailable sockets are ignored. @@ -205,9 +202,8 @@ class DerivedNodeTree { private: DTreeContext &construct_context_recursively(DTreeContext *parent_context, - const NodeRef *parent_node, - bNodeTree &btree, - NodeTreeRefMap &node_tree_refs); + const bNode *parent_node, + const bNodeTree &btree); void destruct_context_recursively(DTreeContext *context); void foreach_node_in_context_recursive(const DTreeContext &context, @@ -215,7 +211,6 @@ class DerivedNodeTree { }; namespace derived_node_tree_types { -using namespace node_tree_ref_types; using nodes::DerivedNodeTree; using nodes::DInputSocket; using nodes::DNode; @@ -228,9 +223,9 @@ using nodes::DTreeContext; /** \name #DTreeContext Inline Methods * \{ */ -inline const NodeTreeRef &DTreeContext::tree() const +inline const bNodeTree &DTreeContext::btree() const { - return *tree_; + return *btree_; } inline const DTreeContext *DTreeContext::parent_context() const @@ -238,12 +233,12 @@ inline const DTreeContext *DTreeContext::parent_context() const return parent_context_; } -inline const NodeRef *DTreeContext::parent_node() const +inline const bNode *DTreeContext::parent_node() const { return parent_node_; } -inline const DTreeContext *DTreeContext::child_context(const NodeRef &node) const +inline const DTreeContext *DTreeContext::child_context(const bNode &node) const { return children_.lookup_default(&node, nullptr); } @@ -264,10 +259,10 @@ inline bool DTreeContext::is_root() const /** \name #DNode Inline Methods * \{ */ -inline DNode::DNode(const DTreeContext *context, const NodeRef *node_ref) - : context_(context), node_ref_(node_ref) +inline DNode::DNode(const DTreeContext *context, const bNode *bnode) + : context_(context), bnode_(bnode) { - BLI_assert(node_ref == nullptr || &node_ref->tree() == &context->tree()); + BLI_assert(bnode == nullptr || bnode->runtime->owner_tree == &context->btree()); } inline const DTreeContext *DNode::context() const @@ -275,14 +270,14 @@ inline const DTreeContext *DNode::context() const return context_; } -inline const NodeRef *DNode::node_ref() const +inline const bNode *DNode::bnode() const { - return node_ref_; + return bnode_; } inline bool operator==(const DNode &a, const DNode &b) { - return a.context_ == b.context_ && a.node_ref_ == b.node_ref_; + return a.context_ == b.context_ && a.bnode_ == b.bnode_; } inline bool operator!=(const DNode &a, const DNode &b) @@ -292,37 +287,43 @@ inline bool operator!=(const DNode &a, const DNode &b) inline DNode::operator bool() const { - return node_ref_ != nullptr; + return bnode_ != nullptr; +} + +inline const bNode *DNode::operator->() const +{ + return bnode_; } -inline const NodeRef *DNode::operator->() const +inline const bNode &DNode::operator*() const { - return node_ref_; + BLI_assert(bnode_ != nullptr); + return *bnode_; } inline uint64_t DNode::hash() const { - return get_default_hash_2(context_, node_ref_); + return get_default_hash_2(context_, bnode_); } inline DInputSocket DNode::input(int index) const { - return {context_, &node_ref_->input(index)}; + return {context_, &bnode_->input_socket(index)}; } inline DOutputSocket DNode::output(int index) const { - return {context_, &node_ref_->output(index)}; + return {context_, &bnode_->output_socket(index)}; } inline DInputSocket DNode::input_by_identifier(StringRef identifier) const { - return {context_, &node_ref_->input_by_identifier(identifier)}; + return {context_, &bnode_->input_by_identifier(identifier)}; } inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const { - return {context_, &node_ref_->output_by_identifier(identifier)}; + return {context_, &bnode_->output_by_identifier(identifier)}; } /** \} */ @@ -331,19 +332,20 @@ inline DOutputSocket DNode::output_by_identifier(StringRef identifier) const /** \name #DSocket Inline Methods * \{ */ -inline DSocket::DSocket(const DTreeContext *context, const SocketRef *socket_ref) - : context_(context), socket_ref_(socket_ref) +inline DSocket::DSocket(const DTreeContext *context, const bNodeSocket *bsocket) + : context_(context), bsocket_(bsocket) { - BLI_assert(socket_ref == nullptr || &socket_ref->tree() == &context->tree()); + BLI_assert(bsocket == nullptr || + bsocket->runtime->owner_node->runtime->owner_tree == &context->btree()); } inline DSocket::DSocket(const DInputSocket &input_socket) - : DSocket(input_socket.context_, input_socket.socket_ref_) + : DSocket(input_socket.context_, input_socket.bsocket_) { } inline DSocket::DSocket(const DOutputSocket &output_socket) - : DSocket(output_socket.context_, output_socket.socket_ref_) + : DSocket(output_socket.context_, output_socket.bsocket_) { } @@ -352,14 +354,14 @@ inline const DTreeContext *DSocket::context() const return context_; } -inline const SocketRef *DSocket::socket_ref() const +inline const bNodeSocket *DSocket::bsocket() const { - return socket_ref_; + return bsocket_; } inline bool operator==(const DSocket &a, const DSocket &b) { - return a.context_ == b.context_ && a.socket_ref_ == b.socket_ref_; + return a.context_ == b.context_ && a.bsocket_ == b.bsocket_; } inline bool operator!=(const DSocket &a, const DSocket &b) @@ -369,23 +371,29 @@ inline bool operator!=(const DSocket &a, const DSocket &b) inline DSocket::operator bool() const { - return socket_ref_ != nullptr; + return bsocket_ != nullptr; } -inline const SocketRef *DSocket::operator->() const +inline const bNodeSocket *DSocket::operator->() const { - return socket_ref_; + return bsocket_; +} + +inline const bNodeSocket &DSocket::operator*() const +{ + BLI_assert(bsocket_ != nullptr); + return *bsocket_; } inline uint64_t DSocket::hash() const { - return get_default_hash_2(context_, socket_ref_); + return get_default_hash_2(context_, bsocket_); } inline DNode DSocket::node() const { - BLI_assert(socket_ref_ != nullptr); - return {context_, &socket_ref_->node()}; + BLI_assert(bsocket_ != nullptr); + return {context_, bsocket_->runtime->owner_node}; } /** \} */ @@ -394,8 +402,8 @@ inline DNode DSocket::node() const /** \name #DInputSocket Inline Methods * \{ */ -inline DInputSocket::DInputSocket(const DTreeContext *context, const InputSocketRef *socket_ref) - : DSocket(context, socket_ref) +inline DInputSocket::DInputSocket(const DTreeContext *context, const bNodeSocket *bsocket) + : DSocket(context, bsocket) { } @@ -404,24 +412,14 @@ inline DInputSocket::DInputSocket(const DSocket &base_socket) : DSocket(base_soc BLI_assert(base_socket->is_input()); } -inline const InputSocketRef *DInputSocket::socket_ref() const -{ - return (const InputSocketRef *)socket_ref_; -} - -inline const InputSocketRef *DInputSocket::operator->() const -{ - return (const InputSocketRef *)socket_ref_; -} - /** \} */ /* -------------------------------------------------------------------- */ /** \name #DOutputSocket Inline Methods * \{ */ -inline DOutputSocket::DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket_ref) - : DSocket(context, socket_ref) +inline DOutputSocket::DOutputSocket(const DTreeContext *context, const bNodeSocket *bsocket) + : DSocket(context, bsocket) { } @@ -430,16 +428,6 @@ inline DOutputSocket::DOutputSocket(const DSocket &base_socket) : DSocket(base_s BLI_assert(base_socket->is_output()); } -inline const OutputSocketRef *DOutputSocket::socket_ref() const -{ - return (const OutputSocketRef *)socket_ref_; -} - -inline const OutputSocketRef *DOutputSocket::operator->() const -{ - return (const OutputSocketRef *)socket_ref_; -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -451,9 +439,9 @@ inline const DTreeContext &DerivedNodeTree::root_context() const return *root_context_; } -inline Span<const NodeTreeRef *> DerivedNodeTree::used_node_tree_refs() const +inline Span<const bNodeTree *> DerivedNodeTree::used_btrees() const { - return used_node_tree_refs_; + return used_btrees_; } /** \} */ diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index a7f5fbf1926..b5ffd3a317c 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -283,7 +283,7 @@ class GeoNodeExecParams { */ const bNode &node() const { - return *provider_->dnode->bnode(); + return *provider_->dnode; } const Object *self_object() const diff --git a/source/blender/nodes/NOD_multi_function.hh b/source/blender/nodes/NOD_multi_function.hh index b6d51578b1c..21a94d9192b 100644 --- a/source/blender/nodes/NOD_multi_function.hh +++ b/source/blender/nodes/NOD_multi_function.hh @@ -19,15 +19,15 @@ class NodeMultiFunctions; */ class NodeMultiFunctionBuilder : NonCopyable, NonMovable { private: - bNode &node_; - bNodeTree &tree_; + const bNode &node_; + const bNodeTree &tree_; std::shared_ptr<MultiFunction> owned_built_fn_; const MultiFunction *built_fn_ = nullptr; friend NodeMultiFunctions; public: - NodeMultiFunctionBuilder(bNode &node, bNodeTree &tree); + NodeMultiFunctionBuilder(const bNode &node, const bNodeTree &tree); /** * Assign a multi-function for the current node. The input and output parameters of the function @@ -42,8 +42,8 @@ class NodeMultiFunctionBuilder : NonCopyable, NonMovable { */ template<typename T, typename... Args> void construct_and_set_matching_fn(Args &&...args); - bNode &node(); - bNodeTree &tree(); + const bNode &node(); + const bNodeTree &tree(); }; /** @@ -69,17 +69,17 @@ class NodeMultiFunctions { /** \name #NodeMultiFunctionBuilder Inline Methods * \{ */ -inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(bNode &node, bNodeTree &tree) +inline NodeMultiFunctionBuilder::NodeMultiFunctionBuilder(const bNode &node, const bNodeTree &tree) : node_(node), tree_(tree) { } -inline bNode &NodeMultiFunctionBuilder::node() +inline const bNode &NodeMultiFunctionBuilder::node() { return node_; } -inline bNodeTree &NodeMultiFunctionBuilder::tree() +inline const bNodeTree &NodeMultiFunctionBuilder::tree() { return tree_; } @@ -110,7 +110,7 @@ inline void NodeMultiFunctionBuilder::construct_and_set_matching_fn(Args &&...ar inline const NodeMultiFunctions::Item &NodeMultiFunctions::try_get(const DNode &node) const { static Item empty_item; - const Item *item = map_.lookup_ptr(node->bnode()); + const Item *item = map_.lookup_ptr(node.bnode()); if (item == nullptr) { return empty_item; } diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh deleted file mode 100644 index 257aa5f4110..00000000000 --- a/source/blender/nodes/NOD_node_tree_ref.hh +++ /dev/null @@ -1,760 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -/** \file - * \ingroup nodes - * - * NodeTreeRef makes querying information about a bNodeTree more efficient. It is an immutable data - * structure. It should not be used after anymore, after the underlying node tree changed. - * - * The following queries are supported efficiently: - * - socket -> index of socket - * - socket -> directly linked sockets - * - socket -> directly linked links - * - socket -> linked sockets when skipping reroutes - * - socket -> node - * - socket/node -> rna pointer - * - node -> inputs/outputs - * - node -> tree - * - tree -> all nodes - * - tree -> all (input/output) sockets - * - idname -> nodes - * - * Every socket has an id. The id-space is shared between input and output sockets. - * When storing data per socket, it is often better to use the id as index into an array, instead - * of a hash table. - * - * Every node has an id as well. The same rule regarding hash tables applies. - * - * There is an utility to export this data structure as graph in dot format. - */ - -#include "BLI_array.hh" -#include "BLI_function_ref.hh" -#include "BLI_linear_allocator.hh" -#include "BLI_map.hh" -#include "BLI_multi_value_map.hh" -#include "BLI_string_ref.hh" -#include "BLI_timeit.hh" -#include "BLI_utility_mixins.hh" -#include "BLI_vector.hh" - -#include "BKE_node.h" -#include "BKE_node_runtime.hh" - -#include "DNA_node_types.h" - -#include "RNA_access.h" - -namespace blender::nodes { - -class SocketRef; -class InputSocketRef; -class OutputSocketRef; -class NodeRef; -class NodeTreeRef; -class LinkRef; -class InternalLinkRef; - -using SocketIndexByIdentifierMap = Map<std::string, int>; - -class SocketRef : NonCopyable, NonMovable { - protected: - NodeRef *node_; - bNodeSocket *bsocket_; - bool is_input_; - int id_; - int index_; - Vector<LinkRef *> directly_linked_links_; - - /* These sockets are linked directly, i.e. with a single link in between. */ - MutableSpan<const SocketRef *> directly_linked_sockets_; - /* These sockets are linked when reroutes, muted links and muted nodes have been taken into - * account. */ - MutableSpan<const SocketRef *> logically_linked_sockets_; - /* These are the sockets that have been skipped when searching for logically linked sockets. - * That includes for example the input and output socket of an intermediate reroute node. */ - MutableSpan<const SocketRef *> logically_linked_skipped_sockets_; - - friend NodeTreeRef; - - public: - Span<const SocketRef *> logically_linked_sockets() const; - Span<const SocketRef *> logically_linked_skipped_sockets() const; - Span<const SocketRef *> directly_linked_sockets() const; - Span<const LinkRef *> directly_linked_links() const; - - bool is_directly_linked() const; - bool is_logically_linked() const; - - const NodeRef &node() const; - const NodeTreeRef &tree() const; - - int id() const; - int index() const; - - bool is_input() const; - bool is_output() const; - - const SocketRef &as_base() const; - const InputSocketRef &as_input() const; - const OutputSocketRef &as_output() const; - - PointerRNA rna() const; - - StringRefNull idname() const; - StringRefNull name() const; - StringRefNull identifier() const; - bNodeSocketType *typeinfo() const; - - bNodeSocket *bsocket() const; - bNode *bnode() const; - bNodeTree *btree() const; - - bool is_available() const; - bool is_undefined() const; - - void *default_value() const; - template<typename T> T *default_value() const; -}; - -class InputSocketRef final : public SocketRef { - public: - friend NodeTreeRef; - - Span<const OutputSocketRef *> logically_linked_sockets() const; - Span<const OutputSocketRef *> directly_linked_sockets() const; - - bool is_multi_input_socket() const; - - private: - void foreach_logical_origin(FunctionRef<void(const OutputSocketRef &)> origin_fn, - FunctionRef<void(const SocketRef &)> skipped_fn, - bool only_follow_first_input_link, - Vector<const InputSocketRef *> &seen_sockets_stack) const; -}; - -class OutputSocketRef final : public SocketRef { - public: - friend NodeTreeRef; - - Span<const InputSocketRef *> logically_linked_sockets() const; - Span<const InputSocketRef *> directly_linked_sockets() const; - - private: - void foreach_logical_target(FunctionRef<void(const InputSocketRef &)> target_fn, - FunctionRef<void(const SocketRef &)> skipped_fn, - Vector<const OutputSocketRef *> &seen_sockets_stack) const; -}; - -class NodeRef : NonCopyable, NonMovable { - private: - NodeTreeRef *tree_; - bNode *bnode_; - int id_; - Vector<InputSocketRef *> inputs_; - Vector<OutputSocketRef *> outputs_; - Vector<InternalLinkRef *> internal_links_; - SocketIndexByIdentifierMap *input_index_by_identifier_; - SocketIndexByIdentifierMap *output_index_by_identifier_; - - friend NodeTreeRef; - - public: - const NodeTreeRef &tree() const; - - Span<const InputSocketRef *> inputs() const; - Span<const OutputSocketRef *> outputs() const; - Span<const InternalLinkRef *> internal_links() const; - Span<const SocketRef *> sockets(eNodeSocketInOut in_out) const; - - const InputSocketRef &input(int index) const; - const OutputSocketRef &output(int index) const; - - const InputSocketRef &input_by_identifier(StringRef identifier) const; - const OutputSocketRef &output_by_identifier(StringRef identifier) const; - - bool any_input_is_directly_linked() const; - bool any_output_is_directly_linked() const; - bool any_socket_is_directly_linked(eNodeSocketInOut in_out) const; - - bNode *bnode() const; - bNodeTree *btree() const; - - PointerRNA rna() const; - StringRefNull idname() const; - StringRefNull name() const; - StringRefNull label() const; - StringRefNull label_or_name() const; - bNodeType *typeinfo() const; - const NodeDeclaration *declaration() const; - - int id() const; - - bool is_reroute_node() const; - bool is_group_node() const; - bool is_group_input_node() const; - bool is_group_output_node() const; - bool is_muted() const; - bool is_frame() const; - bool is_undefined() const; - - void *storage() const; - template<typename T> T *storage() const; -}; - -class LinkRef : NonCopyable, NonMovable { - private: - OutputSocketRef *from_; - InputSocketRef *to_; - bNodeLink *blink_; - - friend NodeTreeRef; - - public: - const OutputSocketRef &from() const; - const InputSocketRef &to() const; - - bNodeLink *blink() const; - - bool is_muted() const; -}; - -class InternalLinkRef : NonCopyable, NonMovable { - private: - InputSocketRef *from_; - OutputSocketRef *to_; - bNodeLink *blink_; - - friend NodeTreeRef; - - public: - const InputSocketRef &from() const; - const OutputSocketRef &to() const; - - bNodeLink *blink() const; -}; - -class NodeTreeRef : NonCopyable, NonMovable { - private: - LinearAllocator<> allocator_; - bNodeTree *btree_; - Vector<NodeRef *> nodes_by_id_; - Vector<SocketRef *> sockets_by_id_; - Vector<InputSocketRef *> input_sockets_; - Vector<OutputSocketRef *> output_sockets_; - Vector<LinkRef *> links_; - MultiValueMap<const bNodeType *, NodeRef *> nodes_by_type_; - Vector<std::unique_ptr<SocketIndexByIdentifierMap>> owned_identifier_maps_; - const NodeRef *group_output_node_ = nullptr; - - public: - NodeTreeRef(bNodeTree *btree); - ~NodeTreeRef(); - - Span<const NodeRef *> nodes() const; - Span<const NodeRef *> nodes_by_type(StringRefNull idname) const; - Span<const NodeRef *> nodes_by_type(const bNodeType *nodetype) const; - - Span<const SocketRef *> sockets() const; - Span<const InputSocketRef *> input_sockets() const; - Span<const OutputSocketRef *> output_sockets() const; - - Span<const LinkRef *> links() const; - - const NodeRef *find_node(const bNode &bnode) const; - - /** - * This is the active group output node if there are multiple. - */ - const NodeRef *group_output_node() const; - - /** - * \return True when there is a link cycle. Unavailable sockets are ignored. - */ - bool has_link_cycles() const; - bool has_undefined_nodes_or_sockets() const; - - enum class ToposortDirection { - LeftToRight, - RightToLeft, - }; - - struct ToposortResult { - Vector<const NodeRef *> sorted_nodes; - /** - * There can't be a correct topological sort of the nodes when there is a cycle. The nodes will - * still be sorted to some degree. The caller has to decide whether it can handle non-perfect - * sorts or not. - */ - bool has_cycle = false; - }; - - /** - * Sort nodes topologically from left to right or right to left. - * In the future the result if this could be cached on #NodeTreeRef. - */ - ToposortResult toposort(ToposortDirection direction) const; - - bNodeTree *btree() const; - StringRefNull name() const; - - std::string to_dot() const; - - private: - /* Utility functions used during construction. */ - InputSocketRef &find_input_socket(Map<bNode *, NodeRef *> &node_mapping, - bNode *bnode, - bNodeSocket *bsocket); - OutputSocketRef &find_output_socket(Map<bNode *, NodeRef *> &node_mapping, - bNode *bnode, - bNodeSocket *bsocket); - - void create_linked_socket_caches(); - void create_socket_identifier_maps(); -}; - -using NodeTreeRefMap = Map<bNodeTree *, std::unique_ptr<const NodeTreeRef>>; - -const NodeTreeRef &get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree); - -namespace node_tree_ref_types { -using nodes::InputSocketRef; -using nodes::NodeRef; -using nodes::NodeTreeRef; -using nodes::NodeTreeRefMap; -using nodes::OutputSocketRef; -using nodes::SocketRef; -} // namespace node_tree_ref_types - -/* -------------------------------------------------------------------- */ -/** \name #SocketRef Inline Methods - * \{ */ - -inline Span<const SocketRef *> SocketRef::logically_linked_sockets() const -{ - return logically_linked_sockets_; -} - -inline Span<const SocketRef *> SocketRef::logically_linked_skipped_sockets() const -{ - return logically_linked_skipped_sockets_; -} - -inline Span<const SocketRef *> SocketRef::directly_linked_sockets() const -{ - return directly_linked_sockets_; -} - -inline Span<const LinkRef *> SocketRef::directly_linked_links() const -{ - return directly_linked_links_; -} - -inline bool SocketRef::is_directly_linked() const -{ - return directly_linked_sockets_.size() > 0; -} - -inline bool SocketRef::is_logically_linked() const -{ - return logically_linked_sockets_.size() > 0; -} - -inline const NodeRef &SocketRef::node() const -{ - return *node_; -} - -inline const NodeTreeRef &SocketRef::tree() const -{ - return node_->tree(); -} - -inline int SocketRef::id() const -{ - return id_; -} - -inline int SocketRef::index() const -{ - return index_; -} - -inline bool SocketRef::is_input() const -{ - return is_input_; -} - -inline bool SocketRef::is_output() const -{ - return !is_input_; -} - -inline const SocketRef &SocketRef::as_base() const -{ - return *this; -} - -inline const InputSocketRef &SocketRef::as_input() const -{ - BLI_assert(this->is_input()); - return static_cast<const InputSocketRef &>(*this); -} - -inline const OutputSocketRef &SocketRef::as_output() const -{ - BLI_assert(this->is_output()); - return static_cast<const OutputSocketRef &>(*this); -} - -inline StringRefNull SocketRef::idname() const -{ - return bsocket_->idname; -} - -inline StringRefNull SocketRef::name() const -{ - return bsocket_->name; -} - -inline StringRefNull SocketRef::identifier() const -{ - return bsocket_->identifier; -} - -inline bNodeSocketType *SocketRef::typeinfo() const -{ - return bsocket_->typeinfo; -} - -inline bNodeSocket *SocketRef::bsocket() const -{ - return bsocket_; -} - -inline bNode *SocketRef::bnode() const -{ - return node_->bnode(); -} - -inline bNodeTree *SocketRef::btree() const -{ - return node_->btree(); -} - -inline bool SocketRef::is_available() const -{ - return (bsocket_->flag & SOCK_UNAVAIL) == 0; -} - -inline bool SocketRef::is_undefined() const -{ - return bsocket_->typeinfo == &NodeSocketTypeUndefined; -} - -inline void *SocketRef::default_value() const -{ - return bsocket_->default_value; -} - -template<typename T> inline T *SocketRef::default_value() const -{ - return (T *)bsocket_->default_value; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #InputSocketRef Inline Methods - * \{ */ - -inline Span<const OutputSocketRef *> InputSocketRef::logically_linked_sockets() const -{ - return logically_linked_sockets_.as_span().cast<const OutputSocketRef *>(); -} - -inline Span<const OutputSocketRef *> InputSocketRef::directly_linked_sockets() const -{ - return directly_linked_sockets_.cast<const OutputSocketRef *>(); -} - -inline bool InputSocketRef::is_multi_input_socket() const -{ - return bsocket_->flag & SOCK_MULTI_INPUT; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #OutputSocketRef Inline Methods - * \{ */ - -inline Span<const InputSocketRef *> OutputSocketRef::logically_linked_sockets() const -{ - return logically_linked_sockets_.as_span().cast<const InputSocketRef *>(); -} - -inline Span<const InputSocketRef *> OutputSocketRef::directly_linked_sockets() const -{ - return directly_linked_sockets_.cast<const InputSocketRef *>(); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #NodeRef Inline Methods - * \{ */ - -inline const NodeTreeRef &NodeRef::tree() const -{ - return *tree_; -} - -inline Span<const InputSocketRef *> NodeRef::inputs() const -{ - return inputs_; -} - -inline Span<const OutputSocketRef *> NodeRef::outputs() const -{ - return outputs_; -} - -inline Span<const SocketRef *> NodeRef::sockets(const eNodeSocketInOut in_out) const -{ - return in_out == SOCK_IN ? inputs_.as_span().cast<const SocketRef *>() : - outputs_.as_span().cast<const SocketRef *>(); -} - -inline Span<const InternalLinkRef *> NodeRef::internal_links() const -{ - return internal_links_; -} - -inline const InputSocketRef &NodeRef::input(int index) const -{ - return *inputs_[index]; -} - -inline const OutputSocketRef &NodeRef::output(int index) const -{ - return *outputs_[index]; -} - -inline const InputSocketRef &NodeRef::input_by_identifier(StringRef identifier) const -{ - const int index = input_index_by_identifier_->lookup_as(identifier); - return this->input(index); -} - -inline const OutputSocketRef &NodeRef::output_by_identifier(StringRef identifier) const -{ - const int index = output_index_by_identifier_->lookup_as(identifier); - return this->output(index); -} - -inline bNode *NodeRef::bnode() const -{ - return bnode_; -} - -inline bNodeTree *NodeRef::btree() const -{ - return tree_->btree(); -} - -inline StringRefNull NodeRef::idname() const -{ - return bnode_->idname; -} - -inline StringRefNull NodeRef::name() const -{ - return bnode_->name; -} - -inline StringRefNull NodeRef::label() const -{ - return bnode_->label; -} - -inline StringRefNull NodeRef::label_or_name() const -{ - const StringRefNull label = this->label(); - if (!label.is_empty()) { - return label; - } - return this->name(); -} - -inline bNodeType *NodeRef::typeinfo() const -{ - return bnode_->typeinfo; -} - -/* Returns a pointer because not all nodes have declarations currently. */ -inline const NodeDeclaration *NodeRef::declaration() const -{ - nodeDeclarationEnsure(this->tree().btree(), bnode_); - return bnode_->runtime->declaration; -} - -inline int NodeRef::id() const -{ - return id_; -} - -inline bool NodeRef::is_reroute_node() const -{ - return bnode_->type == NODE_REROUTE; -} - -inline bool NodeRef::is_group_node() const -{ - return bnode_->type == NODE_GROUP || bnode_->type == NODE_CUSTOM_GROUP; -} - -inline bool NodeRef::is_group_input_node() const -{ - return bnode_->type == NODE_GROUP_INPUT; -} - -inline bool NodeRef::is_group_output_node() const -{ - return bnode_->type == NODE_GROUP_OUTPUT; -} - -inline bool NodeRef::is_frame() const -{ - return bnode_->type == NODE_FRAME; -} - -inline bool NodeRef::is_undefined() const -{ - return bnode_->typeinfo == &NodeTypeUndefined; -} - -inline bool NodeRef::is_muted() const -{ - return (bnode_->flag & NODE_MUTED) != 0; -} - -inline void *NodeRef::storage() const -{ - return bnode_->storage; -} - -template<typename T> inline T *NodeRef::storage() const -{ - return (T *)bnode_->storage; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #LinkRef Inline Methods - * \{ */ - -inline const OutputSocketRef &LinkRef::from() const -{ - return *from_; -} - -inline const InputSocketRef &LinkRef::to() const -{ - return *to_; -} - -inline bNodeLink *LinkRef::blink() const -{ - return blink_; -} - -inline bool LinkRef::is_muted() const -{ - return blink_->flag & NODE_LINK_MUTED; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #InternalLinkRef Inline Methods - * \{ */ - -inline const InputSocketRef &InternalLinkRef::from() const -{ - return *from_; -} - -inline const OutputSocketRef &InternalLinkRef::to() const -{ - return *to_; -} - -inline bNodeLink *InternalLinkRef::blink() const -{ - return blink_; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #NodeTreeRef Inline Methods - * \{ */ - -inline Span<const NodeRef *> NodeTreeRef::nodes() const -{ - return nodes_by_id_; -} - -inline Span<const NodeRef *> NodeTreeRef::nodes_by_type(StringRefNull idname) const -{ - const bNodeType *nodetype = nodeTypeFind(idname.c_str()); - return this->nodes_by_type(nodetype); -} - -inline Span<const NodeRef *> NodeTreeRef::nodes_by_type(const bNodeType *nodetype) const -{ - return nodes_by_type_.lookup(nodetype); -} - -inline Span<const SocketRef *> NodeTreeRef::sockets() const -{ - return sockets_by_id_; -} - -inline Span<const InputSocketRef *> NodeTreeRef::input_sockets() const -{ - return input_sockets_; -} - -inline Span<const OutputSocketRef *> NodeTreeRef::output_sockets() const -{ - return output_sockets_; -} - -inline Span<const LinkRef *> NodeTreeRef::links() const -{ - return links_; -} - -inline const NodeRef *NodeTreeRef::group_output_node() const -{ - return group_output_node_; -} - -inline bNodeTree *NodeTreeRef::btree() const -{ - return btree_; -} - -inline StringRefNull NodeTreeRef::name() const -{ - return btree_->id.name + 2; -} - -/** \} */ - -} // namespace blender::nodes diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 1d1310360b8..8fe77bffaad 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -26,6 +26,7 @@ void register_node_type_sh_camera(void); void register_node_type_sh_value(void); void register_node_type_sh_rgb(void); void register_node_type_sh_mix_rgb(void); +void register_node_type_sh_mix(void); void register_node_type_sh_valtorgb(void); void register_node_type_sh_rgbtobw(void); void register_node_type_sh_shadertorgb(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 786ce88152e..e6cdd462c66 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -25,7 +25,7 @@ DefNode(Node, NODE_REROUTE, 0, "REROUT DefNode(ShaderNode, SH_NODE_RGB, 0, "RGB", RGB, "RGB", "A color picker") DefNode(ShaderNode, SH_NODE_VALUE, 0, "VALUE", Value, "Value", "Used to Input numerical values to other nodes in the tree") -DefNode(ShaderNode, SH_NODE_MIX_RGB, def_mix_rgb, "MIX_RGB", MixRGB, "MixRGB", "Mix two input colors") +DefNode(ShaderNode, SH_NODE_MIX_RGB_LEGACY, def_mix_rgb, "MIX_RGB", MixRGB, "MixRGB", "Mix two input colors") DefNode(ShaderNode, SH_NODE_VALTORGB, def_colorramp, "VALTORGB", ValToRGB, "ColorRamp", "Map values to colors with the use of a gradient") DefNode(ShaderNode, SH_NODE_RGBTOBW, 0, "RGBTOBW", RGBToBW, "RGB to BW", "Convert a color's luminance to a grayscale value") DefNode(ShaderNode, SH_NODE_SHADERTORGB, 0, "SHADERTORGB", ShaderToRGB, "Shader to RGB", "Convert rendering effect (such as light and shadow) to color. Typically used for non-photorealistic rendering, to apply additional effects on the output of BSDFs.\nNote: only supported for Eevee") @@ -122,6 +122,7 @@ DefNode(ShaderNode, SH_NODE_OUTPUT_AOV, def_sh_output_aov, "OUT DefNode(ShaderNode, SH_NODE_CURVE_FLOAT, def_float_curve, "CURVE_FLOAT", FloatCurve, "Float Curve", "Map an input float to a curve and outputs a float value") DefNode(ShaderNode, SH_NODE_COMBINE_COLOR, def_sh_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "Create a color from individual components using multiple models") DefNode(ShaderNode, SH_NODE_SEPARATE_COLOR, def_sh_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "Split a color into its individual components using multiple models") +DefNode(ShaderNode, SH_NODE_MIX, def_sh_mix, "MIX", Mix, "Mix", "Mix values by a factor") DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" ) DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" ) diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc index d8852e9333f..b6bd263b150 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.cc +++ b/source/blender/nodes/composite/nodes/node_composite_image.cc @@ -457,8 +457,8 @@ class ImageOperation : public NodeOperation { update_image_frame_number(); - for (const OutputSocketRef *output : node()->outputs()) { - compute_output(output->identifier()); + for (const bNodeSocket *output : this->node()->output_sockets()) { + compute_output(output->identifier); } } @@ -488,12 +488,12 @@ class ImageOperation : public NodeOperation { /* Allocate all needed outputs as invalid. This should be called when is_valid returns false. */ void allocate_invalid() { - for (const OutputSocketRef *output : node()->outputs()) { - if (!should_compute_output(output->identifier())) { + for (const bNodeSocket *output : this->node()->output_sockets()) { + if (!should_compute_output(output->identifier)) { continue; } - Result &result = get_result(output->identifier()); + Result &result = get_result(output->identifier); result.allocate_invalid(); } } @@ -594,7 +594,7 @@ class ImageOperation : public NodeOperation { const char *get_pass_name(StringRef identifier) { DOutputSocket output = node().output_by_identifier(identifier); - return static_cast<NodeImageLayer *>(output->bsocket()->storage)->pass_name; + return static_cast<NodeImageLayer *>(output->storage)->pass_name; } /* Get the index of the pass with the given name in the selected render layer's passes list @@ -850,9 +850,9 @@ class RenderLayerOperation : public NodeOperation { alpha_result.unbind_as_image(); /* Other output passes are not supported for now, so allocate them as invalid. */ - for (const OutputSocketRef *output : node()->outputs()) { - if (output->identifier() != "Image" && output->identifier() != "Alpha") { - get_result(output->identifier()).allocate_invalid(); + for (const bNodeSocket *output : this->node()->output_sockets()) { + if (!STREQ(output->identifier, "Image") && !STREQ(output->identifier, "Alpha")) { + get_result(output->identifier).allocate_invalid(); } } } diff --git a/source/blender/nodes/composite/nodes/node_composite_normal.cc b/source/blender/nodes/composite/nodes/node_composite_normal.cc index f61ace01cfd..a1a6303e21b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_normal.cc +++ b/source/blender/nodes/composite/nodes/node_composite_normal.cc @@ -51,9 +51,12 @@ class NormalShaderNode : public ShaderNode { } /* The vector value is stored in the default value of the output socket. */ - float *get_vector_value() + const float *get_vector_value() { - return node().output_by_identifier("Normal")->default_value<bNodeSocketValueVector>()->value; + return node() + .output_by_identifier("Normal") + ->default_value_typed<bNodeSocketValueVector>() + ->value; } }; diff --git a/source/blender/nodes/function/node_function_util.hh b/source/blender/nodes/function/node_function_util.hh index fd0b6c31b1d..059b2f9bc17 100644 --- a/source/blender/nodes/function/node_function_util.hh +++ b/source/blender/nodes/function/node_function_util.hh @@ -23,4 +23,6 @@ #include "FN_multi_function_builder.hh" +#include "RNA_access.h" + void fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); diff --git a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc index 7d08d57c503..e5c89567d44 100644 --- a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc +++ b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc @@ -190,7 +190,7 @@ class MF_AlignEulerToVector : public fn::MultiFunction { static void fn_node_align_euler_to_vector_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); builder.construct_and_set_matching_fn<MF_AlignEulerToVector>(node.custom1, node.custom2); } diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc index b6d7e6c9a5f..5fc28509a49 100644 --- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc +++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc @@ -68,7 +68,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) } } -static const fn::MultiFunction *get_multi_function(bNode &bnode) +static const fn::MultiFunction *get_multi_function(const bNode &bnode) { static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle(); static fn::CustomMF_SI_SI_SO<bool, bool, bool> and_fn{ diff --git a/source/blender/nodes/function/nodes/node_fn_combine_color.cc b/source/blender/nodes/function/nodes/node_fn_combine_color.cc index c5fd3ce38a1..450cd166e78 100644 --- a/source/blender/nodes/function/nodes/node_fn_combine_color.cc +++ b/source/blender/nodes/function/nodes/node_fn_combine_color.cc @@ -49,7 +49,7 @@ static void fn_node_combine_color_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static const fn::MultiFunction *get_multi_function(bNode &bnode) +static const fn::MultiFunction *get_multi_function(const bNode &bnode) { const NodeCombSepColor &storage = node_storage(bnode); diff --git a/source/blender/nodes/function/nodes/node_fn_compare.cc b/source/blender/nodes/function/nodes/node_fn_compare.cc index e3f13dc7d6b..122d1a3c93e 100644 --- a/source/blender/nodes/function/nodes/node_fn_compare.cc +++ b/source/blender/nodes/function/nodes/node_fn_compare.cc @@ -167,7 +167,7 @@ static float component_average(float3 a) return (a.x + a.y + a.z) / 3.0f; } -static const fn::MultiFunction *get_multi_function(bNode &node) +static const fn::MultiFunction *get_multi_function(const bNode &node) { const NodeFunctionCompare *data = (NodeFunctionCompare *)node.storage; diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc index 9c9d8620a7e..aad2f532d20 100644 --- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc +++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc @@ -39,7 +39,7 @@ static void node_float_to_int_label(const bNodeTree *UNUSED(ntree), BLI_strncpy(label, IFACE_(name), maxlen); } -static const fn::MultiFunction *get_multi_function(bNode &bnode) +static const fn::MultiFunction *get_multi_function(const bNode &bnode) { static auto exec_preset = fn::CustomMF_presets::AllSpanOrSingle(); static fn::CustomMF_SI_SO<float, int> round_fn{ diff --git a/source/blender/nodes/function/nodes/node_fn_input_bool.cc b/source/blender/nodes/function/nodes/node_fn_input_bool.cc index 5ced719627f..717f4d1ac6b 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_bool.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_bool.cc @@ -22,7 +22,7 @@ static void fn_node_input_bool_layout(uiLayout *layout, bContext *UNUSED(C), Poi static void fn_node_input_bool_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputBool *node_storage = static_cast<NodeInputBool *>(bnode.storage); builder.construct_and_set_matching_fn<fn::CustomMF_Constant<bool>>(node_storage->boolean); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_color.cc b/source/blender/nodes/function/nodes/node_fn_input_color.cc index 46787f7575d..cdad1542c66 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_color.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_color.cc @@ -23,7 +23,7 @@ static void fn_node_input_color_layout(uiLayout *layout, bContext *UNUSED(C), Po static void fn_node_input_color_build_multi_function( blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputColor *node_storage = static_cast<NodeInputColor *>(bnode.storage); blender::ColorGeometry4f color = (ColorGeometry4f)node_storage->color; builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<ColorGeometry4f>>(color); diff --git a/source/blender/nodes/function/nodes/node_fn_input_int.cc b/source/blender/nodes/function/nodes/node_fn_input_int.cc index 1e5dcd5ae7a..16506b5f9b8 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_int.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_int.cc @@ -22,7 +22,7 @@ static void fn_node_input_int_layout(uiLayout *layout, bContext *UNUSED(C), Poin static void fn_node_input_int_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputInt *node_storage = static_cast<NodeInputInt *>(bnode.storage); builder.construct_and_set_matching_fn<fn::CustomMF_Constant<int>>(node_storage->integer); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_string.cc b/source/blender/nodes/function/nodes/node_fn_input_string.cc index 124a8572f78..129d19f4f04 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_string.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc @@ -20,7 +20,7 @@ static void fn_node_input_string_layout(uiLayout *layout, bContext *UNUSED(C), P static void fn_node_input_string_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputString *node_storage = static_cast<NodeInputString *>(bnode.storage); std::string string = std::string((node_storage->string) ? node_storage->string : ""); builder.construct_and_set_matching_fn<fn::CustomMF_Constant<std::string>>(std::move(string)); diff --git a/source/blender/nodes/function/nodes/node_fn_input_vector.cc b/source/blender/nodes/function/nodes/node_fn_input_vector.cc index 898c19e92f0..de894a4038d 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_vector.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_vector.cc @@ -22,7 +22,7 @@ static void fn_node_input_vector_layout(uiLayout *layout, bContext *UNUSED(C), P static void fn_node_input_vector_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); NodeInputVector *node_storage = static_cast<NodeInputVector *>(bnode.storage); float3 vector(node_storage->vector); builder.construct_and_set_matching_fn<fn::CustomMF_Constant<float3>>(vector); diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc index a4fc1a6bfd1..299c0f7a932 100644 --- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc +++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc @@ -52,7 +52,7 @@ static void fn_node_rotate_euler_layout(uiLayout *layout, bContext *UNUSED(C), P uiItemR(layout, ptr, "space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static const fn::MultiFunction *get_multi_function(bNode &bnode) +static const fn::MultiFunction *get_multi_function(const bNode &bnode) { static fn::CustomMF_SI_SI_SO<float3, float3, float3> obj_euler_rot{ "Rotate Euler by Euler/Object", [](const float3 &input, const float3 &rotation) { diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index a4af608a40e..4db4d8bb097 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -20,6 +20,8 @@ #include "NOD_socket_declarations.hh" #include "NOD_socket_declarations_geometry.hh" +#include "RNA_access.h" + #include "node_util.h" void geo_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc index 8c3e97edac0..28d979facac 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc @@ -64,12 +64,12 @@ class EndpointFieldInput final : public bke::CurvesFieldInput { devirtualize_varray2(start_size, end_size, [&](const auto &start_size, const auto &end_size) { threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange curves_range) { for (const int i : curves_range) { - const IndexRange range = curves.points_for_curve(i); + const IndexRange points = curves.points_for_curve(i); const int start = std::max(start_size[i], 0); const int end = std::max(end_size[i], 0); - selection_span.slice(range.take_front(start)).fill(true); - selection_span.slice(range.take_back(end)).fill(true); + selection_span.slice(points.take_front(start)).fill(true); + selection_span.slice(points.take_back(end)).fill(true); } }); }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_points.cc b/source/blender/nodes/geometry/nodes/node_geo_points.cc index dd32e6714f4..e0ba1f1c810 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points.cc @@ -69,10 +69,8 @@ static void node_geo_exec(GeoNodeExecParams params) Field<float3> position_field = params.extract_input<Field<float3>>("Position"); Field<float> radius_field = params.extract_input<Field<float>>("Radius"); - PointCloud *new_point_cloud = BKE_pointcloud_new_nomain(count); - GeometrySet geometry_set = GeometrySet::create_with_pointcloud(new_point_cloud); - PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>(); - MutableAttributeAccessor attributes = *points.attributes_for_write(); + PointCloud *points = BKE_pointcloud_new_nomain(count); + MutableAttributeAccessor attributes = bke::pointcloud_attributes_for_write(*points); AttributeWriter<float3> output_position = attributes.lookup_or_add_for_write<float3>( "position", ATTR_DOMAIN_POINT); AttributeWriter<float> output_radii = attributes.lookup_or_add_for_write<float>( @@ -86,7 +84,7 @@ static void node_geo_exec(GeoNodeExecParams params) output_position.finish(); output_radii.finish(); - params.set_output("Geometry", std::move(geometry_set)); + params.set_output("Geometry", GeometrySet::create_with_pointcloud(points)); } } // namespace blender::nodes::node_geo_points_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc index 9719833097e..c2d6f57ce8a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc @@ -123,7 +123,7 @@ static void try_capture_field_on_geometry(GeometryComponent &component, } } attributes.remove(name); - if (attributes.add(name, domain, data_type, bke::AttributeInitMove{buffer})) { + if (attributes.add(name, domain, data_type, bke::AttributeInitMoveArray{buffer})) { return; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index f1fb9ce5563..60c8a89a6bf 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -73,7 +73,7 @@ static void write_vertex_creases(Mesh &mesh, const VArray<float> &crease_varray) } else { crease = static_cast<float *>( - CustomData_add_layer(&mesh.vdata, CD_CREASE, CD_DEFAULT, nullptr, mesh.totvert)); + CustomData_add_layer(&mesh.vdata, CD_CREASE, CD_CONSTRUCT, nullptr, mesh.totvert)); } materialize_and_clamp_creases(crease_varray, {crease, mesh.totvert}); } diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index e589da09b16..e8e0f0fa61c 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -2,38 +2,38 @@ #include "NOD_derived_node_tree.hh" +#include "BKE_node.h" + #include "BLI_dot_export.hh" namespace blender::nodes { -DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs) +DerivedNodeTree::DerivedNodeTree(const bNodeTree &btree) { /* Construct all possible contexts immediately. This is significantly cheaper than inlining all * node groups. If it still becomes a performance issue in the future, contexts could be * constructed lazily when they are needed. */ - root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree, node_tree_refs); + root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree); } DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context, - const NodeRef *parent_node, - bNodeTree &btree, - NodeTreeRefMap &node_tree_refs) + const bNode *parent_node, + const bNodeTree &btree) { + btree.ensure_topology_cache(); DTreeContext &context = *allocator_.construct<DTreeContext>().release(); context.parent_context_ = parent_context; context.parent_node_ = parent_node; context.derived_tree_ = this; - context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree); - used_node_tree_refs_.add(context.tree_); + context.btree_ = &btree; + used_btrees_.add(context.btree_); - for (const NodeRef *node : context.tree_->nodes()) { - if (node->is_group_node()) { - bNode *bnode = node->bnode(); + for (const bNode *bnode : context.btree_->all_nodes()) { + if (bnode->is_group()) { bNodeTree *child_btree = reinterpret_cast<bNodeTree *>(bnode->id); if (child_btree != nullptr) { - DTreeContext &child = this->construct_context_recursively( - &context, node, *child_btree, node_tree_refs); - context.children_.add_new(node, &child); + DTreeContext &child = this->construct_context_recursively(&context, bnode, *child_btree); + context.children_.add_new(bnode, &child); } } } @@ -57,8 +57,8 @@ void DerivedNodeTree::destruct_context_recursively(DTreeContext *context) bool DerivedNodeTree::has_link_cycles() const { - for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { - if (tree_ref->has_link_cycles()) { + for (const bNodeTree *btree : used_btrees_) { + if (btree->has_link_cycle()) { return true; } } @@ -67,8 +67,8 @@ bool DerivedNodeTree::has_link_cycles() const bool DerivedNodeTree::has_undefined_nodes_or_sockets() const { - for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { - if (tree_ref->has_undefined_nodes_or_sockets()) { + for (const bNodeTree *btree : used_btrees_) { + if (btree->has_undefined_nodes_or_sockets()) { return true; } } @@ -83,8 +83,8 @@ void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context, FunctionRef<void(DNode)> callback) const { - for (const NodeRef *node_ref : context.tree_->nodes()) { - callback(DNode(&context, node_ref)); + for (const bNode *bnode : context.btree_->all_nodes()) { + callback(DNode(&context, bnode)); } for (const DTreeContext *child_context : context.children_.values()) { this->foreach_node_in_context_recursive(*child_context, callback); @@ -94,32 +94,32 @@ void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &cont DOutputSocket DInputSocket::get_corresponding_group_node_output() const { BLI_assert(*this); - BLI_assert(socket_ref_->node().is_group_output_node()); - BLI_assert(socket_ref_->index() < socket_ref_->node().inputs().size() - 1); + BLI_assert(bsocket_->owner_node().is_group_output()); + BLI_assert(bsocket_->index() < bsocket_->owner_node().input_sockets().size() - 1); const DTreeContext *parent_context = context_->parent_context(); - const NodeRef *parent_node = context_->parent_node(); + const bNode *parent_node = context_->parent_node(); BLI_assert(parent_context != nullptr); BLI_assert(parent_node != nullptr); - const int socket_index = socket_ref_->index(); - return {parent_context, &parent_node->output(socket_index)}; + const int socket_index = bsocket_->index(); + return {parent_context, &parent_node->output_socket(socket_index)}; } Vector<DOutputSocket> DInputSocket::get_corresponding_group_input_sockets() const { BLI_assert(*this); - BLI_assert(socket_ref_->node().is_group_node()); + BLI_assert(bsocket_->owner_node().is_group()); - const DTreeContext *child_context = context_->child_context(socket_ref_->node()); + const DTreeContext *child_context = context_->child_context(bsocket_->owner_node()); BLI_assert(child_context != nullptr); - const NodeTreeRef &child_tree = child_context->tree(); - Span<const NodeRef *> group_input_nodes = child_tree.nodes_by_type("NodeGroupInput"); - const int socket_index = socket_ref_->index(); + const bNodeTree &child_tree = child_context->btree(); + Span<const bNode *> group_input_nodes = child_tree.nodes_by_type("NodeGroupInput"); + const int socket_index = bsocket_->index(); Vector<DOutputSocket> sockets; - for (const NodeRef *group_input_node : group_input_nodes) { - sockets.append(DOutputSocket(child_context, &group_input_node->output(socket_index))); + for (const bNode *group_input_node : group_input_nodes) { + sockets.append(DOutputSocket(child_context, &group_input_node->output_socket(socket_index))); } return sockets; } @@ -127,36 +127,36 @@ Vector<DOutputSocket> DInputSocket::get_corresponding_group_input_sockets() cons DInputSocket DOutputSocket::get_corresponding_group_node_input() const { BLI_assert(*this); - BLI_assert(socket_ref_->node().is_group_input_node()); - BLI_assert(socket_ref_->index() < socket_ref_->node().outputs().size() - 1); + BLI_assert(bsocket_->owner_node().is_group_input()); + BLI_assert(bsocket_->index() < bsocket_->owner_node().output_sockets().size() - 1); const DTreeContext *parent_context = context_->parent_context(); - const NodeRef *parent_node = context_->parent_node(); + const bNode *parent_node = context_->parent_node(); BLI_assert(parent_context != nullptr); BLI_assert(parent_node != nullptr); - const int socket_index = socket_ref_->index(); - return {parent_context, &parent_node->input(socket_index)}; + const int socket_index = bsocket_->index(); + return {parent_context, &parent_node->input_socket(socket_index)}; } DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const { BLI_assert(*this); - BLI_assert(socket_ref_->node().is_group_node()); + BLI_assert(bsocket_->owner_node().is_group()); - const DTreeContext *child_context = context_->child_context(socket_ref_->node()); + const DTreeContext *child_context = context_->child_context(bsocket_->owner_node()); if (child_context == nullptr) { /* Can happen when the group node references a non-existent group (e.g. when the group is * linked but the original file is not found). */ return {}; } - const NodeTreeRef &child_tree = child_context->tree(); - Span<const NodeRef *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput"); - const int socket_index = socket_ref_->index(); - for (const NodeRef *group_output_node : group_output_nodes) { - if (group_output_node->bnode()->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) { - return {child_context, &group_output_node->input(socket_index)}; + const bNodeTree &child_tree = child_context->btree(); + Span<const bNode *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput"); + const int socket_index = bsocket_->index(); + for (const bNode *group_output_node : group_output_nodes) { + if (group_output_node->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) { + return {child_context, &group_output_node->input_socket(socket_index)}; } } return {}; @@ -165,11 +165,11 @@ DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) const { BLI_assert(*this); - for (const OutputSocketRef *linked_socket : socket_ref_->as_input().logically_linked_sockets()) { - const NodeRef &linked_node = linked_socket->node(); + for (const bNodeSocket *linked_socket : bsocket_->logically_linked_sockets()) { + const bNode &linked_node = linked_socket->owner_node(); DOutputSocket linked_dsocket{context_, linked_socket}; - if (linked_node.is_group_input_node()) { + if (linked_node.is_group_input()) { if (context_->is_root()) { /* This is a group input in the root node group. */ origin_fn(linked_dsocket); @@ -187,7 +187,7 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) c } } } - else if (linked_node.is_group_node()) { + else if (linked_node.is_group()) { DInputSocket socket_in_group = linked_dsocket.get_active_corresponding_group_output_socket(); if (socket_in_group) { if (socket_in_group->is_logically_linked()) { @@ -217,16 +217,16 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn) const void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, TargetSocketPathInfo &path_info) const { - for (const LinkRef *link : socket_ref_->as_output().directly_linked_links()) { + for (const bNodeLink *link : bsocket_->directly_linked_links()) { if (link->is_muted()) { continue; } - const DInputSocket &linked_socket{context_, &link->to()}; + const DInputSocket &linked_socket{context_, link->tosock}; if (!linked_socket->is_available()) { continue; } const DNode linked_node = linked_socket.node(); - if (linked_node->is_reroute_node()) { + if (linked_node->is_reroute()) { const DInputSocket reroute_input = linked_socket; const DOutputSocket reroute_output = linked_node.output(0); path_info.sockets.append(reroute_input); @@ -236,18 +236,18 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, path_info.sockets.pop_last(); } else if (linked_node->is_muted()) { - for (const InternalLinkRef *internal_link : linked_node->internal_links()) { - if (&internal_link->from() != linked_socket.socket_ref()) { + for (const bNodeLink *internal_link : linked_node->internal_links_span()) { + if (internal_link->fromsock != linked_socket.bsocket()) { continue; } /* The internal link only forwards the first incoming link. */ - if (linked_socket->is_multi_input_socket()) { + if (linked_socket->is_multi_input()) { if (linked_socket->directly_linked_links()[0] != link) { continue; } } const DInputSocket mute_input = linked_socket; - const DOutputSocket mute_output{context_, &internal_link->to()}; + const DOutputSocket mute_output{context_, internal_link->tosock}; path_info.sockets.append(mute_input); path_info.sockets.append(mute_output); mute_output.foreach_target_socket(target_fn, path_info); @@ -255,8 +255,8 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, path_info.sockets.pop_last(); } } - else if (linked_node->is_group_output_node()) { - if (linked_node.node_ref() != context_->tree().group_output_node()) { + else if (linked_node->is_group_output()) { + if (linked_node.bnode() != context_->btree().group_output_node()) { continue; } if (context_->is_root()) { @@ -276,7 +276,7 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, path_info.sockets.pop_last(); } } - else if (linked_node->is_group_node()) { + else if (linked_node->is_group()) { /* Follow the links within the nested node group. */ path_info.sockets.append(linked_socket); const Vector<DOutputSocket> sockets_in_group = @@ -310,7 +310,8 @@ static dot::Cluster *get_dot_cluster_for_context( } dot::Cluster *parent_cluster = get_dot_cluster_for_context( digraph, parent_context, dot_clusters); - std::string cluster_name = context->tree().name() + " / " + context->parent_node()->name(); + std::string cluster_name = StringRef(context->btree().id.name + 2) + " / " + + context->parent_node()->name; dot::Cluster &cluster = digraph.new_cluster(cluster_name); cluster.set_parent_cluster(parent_cluster); return &cluster; @@ -328,11 +329,11 @@ std::string DerivedNodeTree::to_dot() const this->foreach_node([&](DNode node) { /* Ignore nodes that should not show up in the final output. */ - if (node->is_muted() || node->is_group_node() || node->is_reroute_node() || node->is_frame()) { + if (node->is_muted() || node->is_group() || node->is_reroute() || node->is_frame()) { return; } if (!node.context()->is_root()) { - if (node->is_group_input_node() || node->is_group_output_node()) { + if (node->is_group_input() || node->is_group_output()) { return; } } @@ -345,22 +346,22 @@ std::string DerivedNodeTree::to_dot() const Vector<std::string> input_names; Vector<std::string> output_names; - for (const InputSocketRef *socket : node->inputs()) { + for (const bNodeSocket *socket : node->input_sockets()) { if (socket->is_available()) { - input_names.append(socket->name()); + input_names.append(socket->name); } } - for (const OutputSocketRef *socket : node->outputs()) { + for (const bNodeSocket *socket : node->output_sockets()) { if (socket->is_available()) { - output_names.append(socket->name()); + output_names.append(socket->name); } } dot::NodeWithSocketsRef dot_node_with_sockets = dot::NodeWithSocketsRef( - dot_node, node->name(), input_names, output_names); + dot_node, node->name, input_names, output_names); int input_index = 0; - for (const InputSocketRef *socket : node->inputs()) { + for (const bNodeSocket *socket : node->input_sockets()) { if (socket->is_available()) { dot_input_sockets.add_new(DInputSocket{node.context(), socket}, dot_node_with_sockets.input(input_index)); @@ -368,7 +369,7 @@ std::string DerivedNodeTree::to_dot() const } } int output_index = 0; - for (const OutputSocketRef *socket : node->outputs()) { + for (const bNodeSocket *socket : node->output_sockets()) { if (socket->is_available()) { dot_output_sockets.add_new(DOutputSocket{node.context(), socket}, dot_node_with_sockets.output(output_index)); @@ -392,7 +393,7 @@ std::string DerivedNodeTree::to_dot() const } } dot::Node &dot_node = *dot_floating_inputs.lookup_or_add_cb(from_socket, [&]() { - dot::Node &dot_node = digraph.new_node(from_socket->name()); + dot::Node &dot_node = digraph.new_node(from_socket->name); dot_node.set_background_color("white"); dot_node.set_shape(dot::Attr_shape::Ellipse); dot_node.set_parent_cluster( diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index 55930dcb1ee..89bfa5834e8 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -89,17 +89,17 @@ TreeLog &ModifierLog::lookup_or_add_tree_log(LogByTreeContext &log_by_tree_conte destruct_ptr<TreeLog> owned_tree_log = allocator_.construct<TreeLog>(); tree_log = owned_tree_log.get(); log_by_tree_context.add_new(&tree_context, tree_log); - parent_log.child_logs_.add_new(tree_context.parent_node()->name(), std::move(owned_tree_log)); + parent_log.child_logs_.add_new(tree_context.parent_node()->name, std::move(owned_tree_log)); return *tree_log; } NodeLog &ModifierLog::lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node) { TreeLog &tree_log = this->lookup_or_add_tree_log(log_by_tree_context, *node.context()); - NodeLog &node_log = *tree_log.node_logs_.lookup_or_add_cb(node->name(), [&]() { + NodeLog &node_log = *tree_log.node_logs_.lookup_or_add_cb(node->name, [&]() { destruct_ptr<NodeLog> node_log = allocator_.construct<NodeLog>(); - node_log->input_logs_.resize(node->inputs().size()); - node_log->output_logs_.resize(node->outputs().size()); + node_log->input_logs_.resize(node->input_sockets().size()); + node_log->output_logs_.resize(node->output_sockets().size()); return node_log; }); return node_log; diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index c6ebc22c43c..953dce035c2 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -38,7 +38,7 @@ void GeoNodeExecParams::check_input_geometry_set(StringRef identifier, const GeometrySet &geometry_set) const { const SocketDeclaration &decl = - *provider_->dnode->input_by_identifier(identifier).bsocket()->runtime->declaration; + *provider_->dnode->input_by_identifier(identifier).runtime->declaration; const decl::Geometry *geo_decl = dynamic_cast<const decl::Geometry *>(&decl); if (geo_decl == nullptr) { return; @@ -118,9 +118,9 @@ void GeoNodeExecParams::check_output_geometry_set(const GeometrySet &geometry_se const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const { - for (const InputSocketRef *socket : provider_->dnode->inputs()) { - if (socket->is_available() && socket->name() == name) { - return socket->bsocket(); + for (const bNodeSocket *socket : provider_->dnode->runtime->inputs) { + if (socket->is_available() && socket->name == name) { + return socket; } } @@ -140,10 +140,10 @@ void GeoNodeExecParams::set_default_remaining_outputs() void GeoNodeExecParams::check_input_access(StringRef identifier, const CPPType *requested_type) const { - bNodeSocket *found_socket = nullptr; - for (const InputSocketRef *socket : provider_->dnode->inputs()) { - if (socket->identifier() == identifier) { - found_socket = socket->bsocket(); + const bNodeSocket *found_socket = nullptr; + for (const bNodeSocket *socket : provider_->dnode->input_sockets()) { + if (socket->identifier == identifier) { + found_socket = socket; break; } } @@ -151,9 +151,9 @@ void GeoNodeExecParams::check_input_access(StringRef identifier, if (found_socket == nullptr) { std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const InputSocketRef *socket : provider_->dnode->inputs()) { + for (const bNodeSocket *socket : provider_->dnode->input_sockets()) { if (socket->is_available()) { - std::cout << "'" << socket->identifier() << "', "; + std::cout << "'" << socket->identifier << "', "; } } std::cout << "\n"; @@ -182,10 +182,10 @@ void GeoNodeExecParams::check_input_access(StringRef identifier, void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType &value_type) const { - bNodeSocket *found_socket = nullptr; - for (const OutputSocketRef *socket : provider_->dnode->outputs()) { - if (socket->identifier() == identifier) { - found_socket = socket->bsocket(); + const bNodeSocket *found_socket = nullptr; + for (const bNodeSocket *socket : provider_->dnode->output_sockets()) { + if (socket->identifier == identifier) { + found_socket = socket; break; } } @@ -193,9 +193,9 @@ void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType if (found_socket == nullptr) { std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const OutputSocketRef *socket : provider_->dnode->outputs()) { - if (socket->is_available()) { - std::cout << "'" << socket->identifier() << "', "; + for (const bNodeSocket *socket : provider_->dnode->output_sockets()) { + if (!(socket->flag & SOCK_UNAVAIL)) { + std::cout << "'" << socket->identifier << "', "; } } std::cout << "\n"; diff --git a/source/blender/nodes/intern/node_multi_function.cc b/source/blender/nodes/intern/node_multi_function.cc index 13bfdfbfac1..1f8397923e9 100644 --- a/source/blender/nodes/intern/node_multi_function.cc +++ b/source/blender/nodes/intern/node_multi_function.cc @@ -2,14 +2,14 @@ #include "NOD_multi_function.hh" +#include "BKE_node.h" + namespace blender::nodes { NodeMultiFunctions::NodeMultiFunctions(const DerivedNodeTree &tree) { - for (const NodeTreeRef *tree_ref : tree.used_node_tree_refs()) { - bNodeTree *btree = tree_ref->btree(); - for (const NodeRef *node : tree_ref->nodes()) { - bNode *bnode = node->bnode(); + for (const bNodeTree *btree : tree.used_btrees()) { + for (const bNode *bnode : btree->all_nodes()) { if (bnode->typeinfo->build_multi_function == nullptr) { continue; } diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc deleted file mode 100644 index 05e7fe33776..00000000000 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ /dev/null @@ -1,679 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#include <mutex> - -#include "NOD_node_tree_ref.hh" - -#include "BLI_dot_export.hh" -#include "BLI_stack.hh" - -#include "RNA_prototypes.h" - -namespace blender::nodes { - -NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) -{ - Map<bNode *, NodeRef *> node_mapping; - - LISTBASE_FOREACH (bNode *, bnode, &btree->nodes) { - NodeRef &node = *allocator_.construct<NodeRef>().release(); - - node.tree_ = this; - node.bnode_ = bnode; - node.id_ = nodes_by_id_.append_and_get_index(&node); - - LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->inputs) { - InputSocketRef &socket = *allocator_.construct<InputSocketRef>().release(); - socket.node_ = &node; - socket.index_ = node.inputs_.append_and_get_index(&socket); - socket.is_input_ = true; - socket.bsocket_ = bsocket; - socket.id_ = sockets_by_id_.append_and_get_index(&socket); - } - - LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->outputs) { - OutputSocketRef &socket = *allocator_.construct<OutputSocketRef>().release(); - socket.node_ = &node; - socket.index_ = node.outputs_.append_and_get_index(&socket); - socket.is_input_ = false; - socket.bsocket_ = bsocket; - socket.id_ = sockets_by_id_.append_and_get_index(&socket); - } - - LISTBASE_FOREACH (bNodeLink *, blink, &bnode->internal_links) { - InternalLinkRef &internal_link = *allocator_.construct<InternalLinkRef>().release(); - internal_link.blink_ = blink; - for (InputSocketRef *socket_ref : node.inputs_) { - if (socket_ref->bsocket_ == blink->fromsock) { - internal_link.from_ = socket_ref; - break; - } - } - for (OutputSocketRef *socket_ref : node.outputs_) { - if (socket_ref->bsocket_ == blink->tosock) { - internal_link.to_ = socket_ref; - break; - } - } - BLI_assert(internal_link.from_ != nullptr); - BLI_assert(internal_link.to_ != nullptr); - node.internal_links_.append(&internal_link); - } - - input_sockets_.extend(node.inputs_.as_span()); - output_sockets_.extend(node.outputs_.as_span()); - - node_mapping.add_new(bnode, &node); - } - - LISTBASE_FOREACH (bNodeLink *, blink, &btree->links) { - OutputSocketRef &from_socket = this->find_output_socket( - node_mapping, blink->fromnode, blink->fromsock); - InputSocketRef &to_socket = this->find_input_socket( - node_mapping, blink->tonode, blink->tosock); - - LinkRef &link = *allocator_.construct<LinkRef>().release(); - link.from_ = &from_socket; - link.to_ = &to_socket; - link.blink_ = blink; - - links_.append(&link); - - from_socket.directly_linked_links_.append(&link); - to_socket.directly_linked_links_.append(&link); - } - - for (InputSocketRef *input_socket : input_sockets_) { - if (input_socket->is_multi_input_socket()) { - std::sort(input_socket->directly_linked_links_.begin(), - input_socket->directly_linked_links_.end(), - [&](const LinkRef *a, const LinkRef *b) -> bool { - int index_a = a->blink()->multi_input_socket_index; - int index_b = b->blink()->multi_input_socket_index; - return index_a > index_b; - }); - } - } - - this->create_socket_identifier_maps(); - this->create_linked_socket_caches(); - - for (NodeRef *node : nodes_by_id_) { - const bNodeType *nodetype = node->bnode_->typeinfo; - nodes_by_type_.add(nodetype, node); - } - - const Span<const NodeRef *> group_output_nodes = this->nodes_by_type("NodeGroupOutput"); - if (group_output_nodes.is_empty()) { - group_output_node_ = nullptr; - } - else if (group_output_nodes.size() == 1) { - group_output_node_ = group_output_nodes.first(); - } - else { - for (const NodeRef *group_output : group_output_nodes) { - if (group_output->bnode_->flag & NODE_DO_OUTPUT) { - group_output_node_ = group_output; - break; - } - } - } -} - -NodeTreeRef::~NodeTreeRef() -{ - /* The destructor has to be called manually, because these types are allocated in a linear - * allocator. */ - for (NodeRef *node : nodes_by_id_) { - node->~NodeRef(); - } - for (InputSocketRef *socket : input_sockets_) { - socket->~InputSocketRef(); - } - for (OutputSocketRef *socket : output_sockets_) { - socket->~OutputSocketRef(); - } - for (LinkRef *link : links_) { - link->~LinkRef(); - } -} - -InputSocketRef &NodeTreeRef::find_input_socket(Map<bNode *, NodeRef *> &node_mapping, - bNode *bnode, - bNodeSocket *bsocket) -{ - NodeRef *node = node_mapping.lookup(bnode); - for (InputSocketRef *socket : node->inputs_) { - if (socket->bsocket_ == bsocket) { - return *socket; - } - } - BLI_assert_unreachable(); - return *node->inputs_[0]; -} - -OutputSocketRef &NodeTreeRef::find_output_socket(Map<bNode *, NodeRef *> &node_mapping, - bNode *bnode, - bNodeSocket *bsocket) -{ - NodeRef *node = node_mapping.lookup(bnode); - for (OutputSocketRef *socket : node->outputs_) { - if (socket->bsocket_ == bsocket) { - return *socket; - } - } - BLI_assert_unreachable(); - return *node->outputs_[0]; -} - -void NodeTreeRef::create_linked_socket_caches() -{ - for (InputSocketRef *socket : input_sockets_) { - /* Find directly linked socket based on incident links. */ - Vector<const SocketRef *> directly_linked_sockets; - for (LinkRef *link : socket->directly_linked_links_) { - directly_linked_sockets.append(link->from_); - } - socket->directly_linked_sockets_ = allocator_.construct_array_copy( - directly_linked_sockets.as_span()); - - /* Find logically linked sockets. */ - Vector<const SocketRef *> logically_linked_sockets; - Vector<const SocketRef *> logically_linked_skipped_sockets; - Vector<const InputSocketRef *> seen_sockets_stack; - socket->foreach_logical_origin( - [&](const OutputSocketRef &origin) { logically_linked_sockets.append(&origin); }, - [&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); }, - false, - seen_sockets_stack); - if (logically_linked_sockets == directly_linked_sockets) { - socket->logically_linked_sockets_ = socket->directly_linked_sockets_; - } - else { - socket->logically_linked_sockets_ = allocator_.construct_array_copy( - logically_linked_sockets.as_span()); - } - socket->logically_linked_skipped_sockets_ = allocator_.construct_array_copy( - logically_linked_skipped_sockets.as_span()); - } - - for (OutputSocketRef *socket : output_sockets_) { - /* Find directly linked socket based on incident links. */ - Vector<const SocketRef *> directly_linked_sockets; - for (LinkRef *link : socket->directly_linked_links_) { - directly_linked_sockets.append(link->to_); - } - socket->directly_linked_sockets_ = allocator_.construct_array_copy( - directly_linked_sockets.as_span()); - - /* Find logically linked sockets. */ - Vector<const SocketRef *> logically_linked_sockets; - Vector<const SocketRef *> logically_linked_skipped_sockets; - Vector<const OutputSocketRef *> handled_sockets; - socket->foreach_logical_target( - [&](const InputSocketRef &target) { logically_linked_sockets.append(&target); }, - [&](const SocketRef &socket) { logically_linked_skipped_sockets.append(&socket); }, - handled_sockets); - if (logically_linked_sockets == directly_linked_sockets) { - socket->logically_linked_sockets_ = socket->directly_linked_sockets_; - } - else { - socket->logically_linked_sockets_ = allocator_.construct_array_copy( - logically_linked_sockets.as_span()); - } - socket->logically_linked_skipped_sockets_ = allocator_.construct_array_copy( - logically_linked_skipped_sockets.as_span()); - } -} - -void InputSocketRef::foreach_logical_origin( - FunctionRef<void(const OutputSocketRef &)> origin_fn, - FunctionRef<void(const SocketRef &)> skipped_fn, - bool only_follow_first_input_link, - Vector<const InputSocketRef *> &seen_sockets_stack) const -{ - /* Protect against loops. */ - if (seen_sockets_stack.contains(this)) { - return; - } - seen_sockets_stack.append(this); - - Span<const LinkRef *> links_to_check = this->directly_linked_links(); - if (only_follow_first_input_link) { - links_to_check = links_to_check.take_front(1); - } - for (const LinkRef *link : links_to_check) { - if (link->is_muted()) { - continue; - } - const OutputSocketRef &origin = link->from(); - const NodeRef &origin_node = origin.node(); - if (!origin.is_available()) { - /* Non available sockets are ignored. */ - } - else if (origin_node.is_reroute_node()) { - const InputSocketRef &reroute_input = origin_node.input(0); - const OutputSocketRef &reroute_output = origin_node.output(0); - skipped_fn.call_safe(reroute_input); - skipped_fn.call_safe(reroute_output); - reroute_input.foreach_logical_origin(origin_fn, skipped_fn, false, seen_sockets_stack); - } - else if (origin_node.is_muted()) { - for (const InternalLinkRef *internal_link : origin_node.internal_links()) { - if (&internal_link->to() == &origin) { - const InputSocketRef &mute_input = internal_link->from(); - skipped_fn.call_safe(origin); - skipped_fn.call_safe(mute_input); - mute_input.foreach_logical_origin(origin_fn, skipped_fn, true, seen_sockets_stack); - } - } - } - else { - origin_fn(origin); - } - } - - seen_sockets_stack.pop_last(); -} - -void OutputSocketRef::foreach_logical_target( - FunctionRef<void(const InputSocketRef &)> target_fn, - FunctionRef<void(const SocketRef &)> skipped_fn, - Vector<const OutputSocketRef *> &seen_sockets_stack) const -{ - /* Protect against loops. */ - if (seen_sockets_stack.contains(this)) { - return; - } - seen_sockets_stack.append(this); - - for (const LinkRef *link : this->directly_linked_links()) { - if (link->is_muted()) { - continue; - } - const InputSocketRef &target = link->to(); - const NodeRef &target_node = target.node(); - if (!target.is_available()) { - /* Non available sockets are ignored. */ - } - else if (target_node.is_reroute_node()) { - const OutputSocketRef &reroute_output = target_node.output(0); - skipped_fn.call_safe(target); - skipped_fn.call_safe(reroute_output); - reroute_output.foreach_logical_target(target_fn, skipped_fn, seen_sockets_stack); - } - else if (target_node.is_muted()) { - skipped_fn.call_safe(target); - for (const InternalLinkRef *internal_link : target_node.internal_links()) { - if (&internal_link->from() == &target) { - /* The internal link only forwards the first incoming link. */ - if (target.is_multi_input_socket()) { - if (target.directly_linked_links()[0] != link) { - continue; - } - } - const OutputSocketRef &mute_output = internal_link->to(); - skipped_fn.call_safe(target); - skipped_fn.call_safe(mute_output); - mute_output.foreach_logical_target(target_fn, skipped_fn, seen_sockets_stack); - } - } - } - else { - target_fn(target); - } - } - - seen_sockets_stack.pop_last(); -} - -namespace { -struct SocketByIdentifierMap { - SocketIndexByIdentifierMap *map = nullptr; - std::unique_ptr<SocketIndexByIdentifierMap> owned_map; -}; -} // namespace - -static std::unique_ptr<SocketIndexByIdentifierMap> create_identifier_map(const ListBase &sockets) -{ - std::unique_ptr<SocketIndexByIdentifierMap> map = std::make_unique<SocketIndexByIdentifierMap>(); - int index; - LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &sockets, index) { - map->add_new(socket->identifier, index); - } - return map; -} - -/* This function is not threadsafe. */ -static SocketByIdentifierMap get_or_create_identifier_map( - const bNode &node, const ListBase &sockets, const bNodeSocketTemplate *sockets_template) -{ - SocketByIdentifierMap map; - if (sockets_template == nullptr) { - if (BLI_listbase_is_empty(&sockets)) { - static SocketIndexByIdentifierMap empty_map; - map.map = &empty_map; - } - else if (node.type == NODE_REROUTE) { - if (&node.inputs == &sockets) { - static SocketIndexByIdentifierMap reroute_input_map = [] { - SocketIndexByIdentifierMap map; - map.add_new("Input", 0); - return map; - }(); - map.map = &reroute_input_map; - } - else { - static SocketIndexByIdentifierMap reroute_output_map = [] { - SocketIndexByIdentifierMap map; - map.add_new("Output", 0); - return map; - }(); - map.map = &reroute_output_map; - } - } - else { - /* The node has a dynamic amount of sockets. Therefore we need to create a new map. */ - map.owned_map = create_identifier_map(sockets); - map.map = &*map.owned_map; - } - } - else { - /* Cache only one map for nodes that have the same sockets. */ - static Map<const bNodeSocketTemplate *, std::unique_ptr<SocketIndexByIdentifierMap>> maps; - map.map = &*maps.lookup_or_add_cb(sockets_template, - [&]() { return create_identifier_map(sockets); }); - } - return map; -} - -void NodeTreeRef::create_socket_identifier_maps() -{ - /* `get_or_create_identifier_map` is not threadsafe, therefore we have to hold a lock here. */ - static std::mutex mutex; - std::lock_guard lock{mutex}; - - for (NodeRef *node : nodes_by_id_) { - bNode &bnode = *node->bnode_; - SocketByIdentifierMap inputs_map = get_or_create_identifier_map( - bnode, bnode.inputs, bnode.typeinfo->inputs); - SocketByIdentifierMap outputs_map = get_or_create_identifier_map( - bnode, bnode.outputs, bnode.typeinfo->outputs); - node->input_index_by_identifier_ = inputs_map.map; - node->output_index_by_identifier_ = outputs_map.map; - if (inputs_map.owned_map) { - owned_identifier_maps_.append(std::move(inputs_map.owned_map)); - } - if (outputs_map.owned_map) { - owned_identifier_maps_.append(std::move(outputs_map.owned_map)); - } - } -} - -static bool has_link_cycles_recursive(const NodeRef &node, - MutableSpan<bool> visited, - MutableSpan<bool> is_in_stack) -{ - const int node_id = node.id(); - if (is_in_stack[node_id]) { - return true; - } - if (visited[node_id]) { - return false; - } - - visited[node_id] = true; - is_in_stack[node_id] = true; - - for (const OutputSocketRef *from_socket : node.outputs()) { - if (!from_socket->is_available()) { - continue; - } - for (const InputSocketRef *to_socket : from_socket->directly_linked_sockets()) { - if (!to_socket->is_available()) { - continue; - } - const NodeRef &to_node = to_socket->node(); - if (has_link_cycles_recursive(to_node, visited, is_in_stack)) { - return true; - } - } - } - - is_in_stack[node_id] = false; - return false; -} - -bool NodeTreeRef::has_link_cycles() const -{ - const int node_amount = nodes_by_id_.size(); - Array<bool> visited(node_amount, false); - Array<bool> is_in_stack(node_amount, false); - - for (const NodeRef *node : nodes_by_id_) { - if (has_link_cycles_recursive(*node, visited, is_in_stack)) { - return true; - } - } - return false; -} - -bool NodeTreeRef::has_undefined_nodes_or_sockets() const -{ - for (const NodeRef *node : nodes_by_id_) { - if (node->is_undefined()) { - return true; - } - } - for (const SocketRef *socket : sockets_by_id_) { - if (socket->is_undefined()) { - return true; - } - } - return false; -} - -bool NodeRef::any_input_is_directly_linked() const -{ - for (const SocketRef *socket : inputs_) { - if (!socket->directly_linked_sockets().is_empty()) { - return true; - } - } - return false; -} - -bool NodeRef::any_output_is_directly_linked() const -{ - for (const SocketRef *socket : outputs_) { - if (!socket->directly_linked_sockets().is_empty()) { - return true; - } - } - return false; -} - -bool NodeRef::any_socket_is_directly_linked(eNodeSocketInOut in_out) const -{ - if (in_out == SOCK_IN) { - return this->any_input_is_directly_linked(); - } - return this->any_output_is_directly_linked(); -} - -struct ToposortNodeState { - bool is_done = false; - bool is_in_stack = false; -}; - -static void toposort_from_start_node(const NodeTreeRef::ToposortDirection direction, - const NodeRef &start_node, - MutableSpan<ToposortNodeState> node_states, - NodeTreeRef::ToposortResult &result) -{ - struct Item { - const NodeRef *node; - /* Index of the next socket that is checked in the depth-first search. */ - int socket_index = 0; - /* Link index in the next socket that is checked in the depth-first search. */ - int link_index = 0; - }; - - /* Do a depth-first search to sort nodes topologically. */ - Stack<Item, 64> nodes_to_check; - nodes_to_check.push({&start_node}); - node_states[start_node.id()].is_in_stack = true; - while (!nodes_to_check.is_empty()) { - Item &item = nodes_to_check.peek(); - const NodeRef &node = *item.node; - const Span<const SocketRef *> sockets = node.sockets( - direction == NodeTreeRef::ToposortDirection::LeftToRight ? SOCK_IN : SOCK_OUT); - - while (true) { - if (item.socket_index == sockets.size()) { - /* All sockets have already been visited. */ - break; - } - const SocketRef &socket = *sockets[item.socket_index]; - const Span<const SocketRef *> linked_sockets = socket.directly_linked_sockets(); - if (item.link_index == linked_sockets.size()) { - /* All links connected to this socket have already been visited. */ - item.socket_index++; - item.link_index = 0; - continue; - } - const SocketRef &linked_socket = *linked_sockets[item.link_index]; - const NodeRef &linked_node = linked_socket.node(); - ToposortNodeState &linked_node_state = node_states[linked_node.id()]; - if (linked_node_state.is_done) { - /* The linked node has already been visited. */ - item.link_index++; - continue; - } - if (linked_node_state.is_in_stack) { - result.has_cycle = true; - } - else { - nodes_to_check.push({&linked_node}); - linked_node_state.is_in_stack = true; - } - break; - } - - /* If no other element has been pushed, the current node can be pushed to the sorted list. */ - if (&item == &nodes_to_check.peek()) { - ToposortNodeState &node_state = node_states[node.id()]; - node_state.is_done = true; - node_state.is_in_stack = false; - result.sorted_nodes.append(&node); - nodes_to_check.pop(); - } - } -} - -NodeTreeRef::ToposortResult NodeTreeRef::toposort(const ToposortDirection direction) const -{ - ToposortResult result; - result.sorted_nodes.reserve(nodes_by_id_.size()); - - Array<ToposortNodeState> node_states(nodes_by_id_.size()); - - for (const NodeRef *node : nodes_by_id_) { - if (node_states[node->id()].is_done) { - /* Ignore nodes that are done already. */ - continue; - } - if (node->any_socket_is_directly_linked( - direction == ToposortDirection::LeftToRight ? SOCK_OUT : SOCK_IN)) { - /* Ignore non-start nodes. */ - continue; - } - - toposort_from_start_node(direction, *node, node_states, result); - } - - /* Check if the loop above forgot some nodes because there is a cycle. */ - if (result.sorted_nodes.size() < nodes_by_id_.size()) { - result.has_cycle = true; - for (const NodeRef *node : nodes_by_id_) { - if (node_states[node->id()].is_done) { - /* Ignore nodes that are done already. */ - continue; - } - /* Start toposort at this node which is somewhere in the middle of a loop. */ - toposort_from_start_node(direction, *node, node_states, result); - } - } - - BLI_assert(result.sorted_nodes.size() == nodes_by_id_.size()); - return result; -} - -const NodeRef *NodeTreeRef::find_node(const bNode &bnode) const -{ - for (const NodeRef *node : this->nodes_by_type(bnode.typeinfo)) { - if (node->bnode_ == &bnode) { - return node; - } - } - return nullptr; -} - -std::string NodeTreeRef::to_dot() const -{ - dot::DirectedGraph digraph; - digraph.set_rankdir(dot::Attr_rankdir::LeftToRight); - - Map<const NodeRef *, dot::NodeWithSocketsRef> dot_nodes; - - for (const NodeRef *node : nodes_by_id_) { - dot::Node &dot_node = digraph.new_node(""); - dot_node.set_background_color("white"); - - Vector<std::string> input_names; - Vector<std::string> output_names; - for (const InputSocketRef *socket : node->inputs()) { - input_names.append(socket->name()); - } - for (const OutputSocketRef *socket : node->outputs()) { - output_names.append(socket->name()); - } - - dot_nodes.add_new(node, - dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names)); - } - - for (const OutputSocketRef *from_socket : output_sockets_) { - for (const InputSocketRef *to_socket : from_socket->directly_linked_sockets()) { - dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(&from_socket->node()); - dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(&to_socket->node()); - - digraph.new_edge(from_dot_node.output(from_socket->index()), - to_dot_node.input(to_socket->index())); - } - } - - return digraph.to_dot_string(); -} - -const NodeTreeRef &get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree) -{ - return *node_tree_refs.lookup_or_add_cb(&btree, - [&]() { return std::make_unique<NodeTreeRef>(&btree); }); -} - -PointerRNA NodeRef::rna() const -{ - PointerRNA rna; - RNA_pointer_create(&tree_->btree()->id, &RNA_Node, bnode_, &rna); - return rna; -} - -PointerRNA SocketRef::rna() const -{ - PointerRNA rna; - RNA_pointer_create(&this->tree().btree()->id, &RNA_NodeSocket, bsocket_, &rna); - return rna; -} - -} // namespace blender::nodes diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 3e90f185168..d135f9a12a4 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -68,6 +68,7 @@ set(SRC nodes/node_shader_mapping.cc nodes/node_shader_math.cc nodes/node_shader_mix_rgb.cc + nodes/node_shader_mix.cc nodes/node_shader_mix_shader.cc nodes/node_shader_normal.cc nodes/node_shader_normal_map.cc diff --git a/source/blender/nodes/shader/node_shader_util.hh b/source/blender/nodes/shader/node_shader_util.hh index d5f54d9cac9..38220634695 100644 --- a/source/blender/nodes/shader/node_shader_util.hh +++ b/source/blender/nodes/shader/node_shader_util.hh @@ -59,6 +59,8 @@ #include "RE_pipeline.h" #include "RE_texture.h" +#include "RNA_access.h" + bool sh_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree, const char **r_disabled_hint); diff --git a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc index 3723480ffa3..d73ffd89288 100644 --- a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc @@ -125,7 +125,7 @@ class ColorBandFunction : public fn::MultiFunction { static void sh_node_valtorgb_build_multi_function(nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); const ColorBand *color_band = (const ColorBand *)bnode.storage; builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band); } diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc index eb47059063d..4725aef5991 100644 --- a/source/blender/nodes/shader/nodes/node_shader_curves.cc +++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc @@ -95,7 +95,7 @@ class CurveVecFunction : public fn::MultiFunction { static void sh_node_curve_vec_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); CurveMapping *cumap = (CurveMapping *)bnode.storage; BKE_curvemapping_init(cumap); builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap); @@ -237,7 +237,7 @@ class CurveRGBFunction : public fn::MultiFunction { static void sh_node_curve_rgb_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); CurveMapping *cumap = (CurveMapping *)bnode.storage; BKE_curvemapping_init(cumap); builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap); @@ -356,7 +356,7 @@ class CurveFloatFunction : public fn::MultiFunction { static void sh_node_curve_float_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); + const bNode &bnode = builder.node(); CurveMapping *cumap = (CurveMapping *)bnode.storage; BKE_curvemapping_init(cumap); builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap); diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index 73ee6fb3f85..bd83f8dac37 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -102,7 +102,7 @@ static int gpu_shader_math(GPUMaterial *mat, return 0; } -static const fn::MultiFunction *get_base_multi_function(bNode &node) +static const fn::MultiFunction *get_base_multi_function(const bNode &node) { const int mode = node.custom1; const fn::MultiFunction *base_fn = nullptr; diff --git a/source/blender/nodes/shader/nodes/node_shader_mix.cc b/source/blender/nodes/shader/nodes/node_shader_mix.cc new file mode 100644 index 00000000000..918d9b747d5 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_mix.cc @@ -0,0 +1,443 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2005 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup shdnodes + */ + +#include <algorithm> + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_shader_util.hh" + +#include "NOD_socket_search_link.hh" +#include "RNA_enum_types.h" + +namespace blender::nodes::node_sh_mix_cc { + +NODE_STORAGE_FUNCS(NodeShaderMix) + +static void sh_node_mix_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + b.add_input<decl::Float>(N_("Factor"), "Factor_Float") + .default_value(0.5f) + .min(0.0f) + .max(1.0f) + .subtype(PROP_FACTOR); + b.add_input<decl::Vector>(N_("Factor"), "Factor_Vector") + .default_value(float3(0.5f)) + .subtype(PROP_FACTOR); + + b.add_input<decl::Float>(N_("A"), "A_Float") + .min(-10000.0f) + .max(10000.0f) + .is_default_link_socket(); + b.add_input<decl::Float>(N_("B"), "B_Float").min(-10000.0f).max(10000.0f); + + b.add_input<decl::Vector>(N_("A"), "A_Vector").is_default_link_socket(); + b.add_input<decl::Vector>(N_("B"), "B_Vector"); + + b.add_input<decl::Color>(N_("A"), "A_Color") + .default_value({0.5f, 0.5f, 0.5f, 1.0f}) + .is_default_link_socket(); + b.add_input<decl::Color>(N_("B"), "B_Color").default_value({0.5f, 0.5f, 0.5f, 1.0f}); + + b.add_output<decl::Float>(N_("Result"), "Result_Float"); + b.add_output<decl::Vector>(N_("Result"), "Result_Vector"); + b.add_output<decl::Color>(N_("Result"), "Result_Color"); +}; + +static void sh_node_mix_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + const NodeShaderMix &data = node_storage(*static_cast<const bNode *>(ptr->data)); + uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + if (data.data_type == SOCK_VECTOR) { + uiItemR(layout, ptr, "factor_mode", 0, "", ICON_NONE); + } + if (data.data_type == SOCK_RGBA) { + uiItemR(layout, ptr, "blend_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "clamp_result", 0, nullptr, ICON_NONE); + uiItemR(layout, ptr, "clamp_factor", 0, nullptr, ICON_NONE); + } + else { + uiItemR(layout, ptr, "clamp_factor", 0, nullptr, ICON_NONE); + } +} + +static void sh_node_mix_label(const bNodeTree *UNUSED(ntree), + const bNode *node, + char *label, + int maxlen) +{ + const NodeShaderMix &storage = node_storage(*node); + if (storage.data_type == SOCK_RGBA) { + const char *name; + bool enum_label = RNA_enum_name(rna_enum_ramp_blend_items, storage.blend_type, &name); + if (!enum_label) { + name = "Unknown"; + } + BLI_strncpy(label, IFACE_(name), maxlen); + } +} + +static int sh_node_mix_ui_class(const bNode *node) +{ + const NodeShaderMix &storage = node_storage(*node); + const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.data_type); + + switch (data_type) { + case SOCK_VECTOR: + return NODE_CLASS_OP_VECTOR; + case SOCK_RGBA: + return NODE_CLASS_OP_COLOR; + default: + return NODE_CLASS_CONVERTER; + } +} + +static void sh_node_mix_update(bNodeTree *ntree, bNode *node) +{ + const NodeShaderMix &storage = node_storage(*node); + const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.data_type); + + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + nodeSetSocketAvailability(ntree, socket, socket->type == data_type); + } + + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + nodeSetSocketAvailability(ntree, socket, socket->type == data_type); + } + + bool use_vector_factor = data_type == SOCK_VECTOR && + storage.factor_mode != NODE_MIX_MODE_UNIFORM; + + bNodeSocket *sock_factor = (bNodeSocket *)BLI_findlink(&node->inputs, 0); + nodeSetSocketAvailability(ntree, sock_factor, !use_vector_factor); + + bNodeSocket *sock_factor_vec = (bNodeSocket *)BLI_findlink(&node->inputs, 1); + nodeSetSocketAvailability(ntree, sock_factor_vec, use_vector_factor); +} + +static void node_mix_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const eNodeSocketDatatype sock_type = static_cast<eNodeSocketDatatype>( + params.other_socket().type); + + if (ELEM(sock_type, SOCK_BOOLEAN, SOCK_FLOAT, SOCK_RGBA, SOCK_VECTOR, SOCK_INT)) { + const eNodeSocketDatatype type = ELEM(sock_type, SOCK_BOOLEAN, SOCK_INT) ? SOCK_FLOAT : + sock_type; + + if (params.in_out() == SOCK_OUT) { + params.add_item(IFACE_("Result"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeMix"); + node_storage(node).data_type = type; + params.update_and_connect_available_socket(node, "Result"); + }); + } + else { + if (ELEM(sock_type, SOCK_VECTOR, SOCK_RGBA)) { + params.add_item(IFACE_("Factor (Non-Uniform)"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeMix"); + node_storage(node).data_type = SOCK_VECTOR; + node_storage(node).factor_mode = NODE_MIX_MODE_NON_UNIFORM; + params.update_and_connect_available_socket(node, "Factor"); + }); + } + params.add_item(IFACE_("Factor"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeMix"); + node_storage(node).data_type = type; + params.update_and_connect_available_socket(node, "Factor"); + }); + params.add_item(IFACE_("A"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeMix"); + node_storage(node).data_type = type; + params.update_and_connect_available_socket(node, "A"); + }); + params.add_item(IFACE_("B"), [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("ShaderNodeMix"); + node_storage(node).data_type = type; + params.update_and_connect_available_socket(node, "B"); + }); + } + } +} + +static void node_mix_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeShaderMix *data = MEM_cnew<NodeShaderMix>(__func__); + data->data_type = SOCK_FLOAT; + data->factor_mode = NODE_MIX_MODE_UNIFORM; + data->clamp_factor = 1; + data->clamp_result = 0; + data->blend_type = MA_RAMP_BLEND; + node->storage = data; +} + +static const char *gpu_shader_get_name(eNodeSocketDatatype data_type, + const bool non_uniform, + const int blend_type) +{ + switch (data_type) { + case SOCK_FLOAT: + return "node_mix_float"; + case SOCK_VECTOR: + return (non_uniform) ? "node_mix_vector_non_uniform" : "node_mix_vector"; + case SOCK_RGBA: + switch (blend_type) { + case MA_RAMP_BLEND: + return "node_mix_blend"; + case MA_RAMP_ADD: + return "node_mix_add"; + case MA_RAMP_MULT: + return "node_mix_mult"; + case MA_RAMP_SUB: + return "node_mix_sub"; + case MA_RAMP_SCREEN: + return "node_mix_screen"; + case MA_RAMP_DIV: + return "node_mix_div_fallback"; + case MA_RAMP_DIFF: + return "node_mix_diff"; + case MA_RAMP_DARK: + return "node_mix_dark"; + case MA_RAMP_LIGHT: + return "node_mix_light"; + case MA_RAMP_OVERLAY: + return "node_mix_overlay"; + case MA_RAMP_DODGE: + return "node_mix_dodge"; + case MA_RAMP_BURN: + return "node_mix_burn"; + case MA_RAMP_HUE: + return "node_mix_hue"; + case MA_RAMP_SAT: + return "node_mix_sat"; + case MA_RAMP_VAL: + return "node_mix_val"; + case MA_RAMP_COLOR: + return "node_mix_color"; + case MA_RAMP_SOFT: + return "node_mix_soft"; + case MA_RAMP_LINEAR: + return "node_mix_linear"; + default: + BLI_assert_unreachable(); + return nullptr; + } + default: + BLI_assert_unreachable(); + return nullptr; + } +} + +static int gpu_shader_mix(GPUMaterial *mat, + bNode *node, + bNodeExecData *UNUSED(execdata), + GPUNodeStack *in, + GPUNodeStack *out) +{ + const NodeShaderMix &storage = node_storage(*node); + const bool is_non_uniform = storage.factor_mode == NODE_MIX_MODE_NON_UNIFORM; + const bool is_color_mode = storage.data_type == SOCK_RGBA; + const bool is_vector_mode = storage.data_type == SOCK_VECTOR; + const int blend_type = storage.blend_type; + const char *name = gpu_shader_get_name( + (eNodeSocketDatatype)storage.data_type, is_non_uniform, blend_type); + + if (name == nullptr) { + return 0; + } + + if (storage.clamp_factor) { + if (is_non_uniform && is_vector_mode) { + const float min[3] = {0.0f, 0.0f, 0.0f}; + const float max[3] = {1.0f, 1.0f, 1.0f}; + const GPUNodeLink *factor_link = in[1].link ? in[1].link : GPU_uniform(in[1].vec); + GPU_link(mat, + "node_mix_clamp_vector", + factor_link, + GPU_constant(min), + GPU_constant(max), + &in[1].link); + } + else { + const float min = 0.0f; + const float max = 1.0f; + const GPUNodeLink *factor_link = in[0].link ? in[0].link : GPU_uniform(in[0].vec); + GPU_link(mat, + "node_mix_clamp_value", + factor_link, + GPU_constant(&min), + GPU_constant(&max), + &in[0].link); + } + } + + int ret = GPU_stack_link(mat, node, name, in, out); + + if (ret && is_color_mode && storage.clamp_result) { + const float min[3] = {0.0f, 0.0f, 0.0f}; + const float max[3] = {1.0f, 1.0f, 1.0f}; + GPU_link(mat, + "node_mix_clamp_vector", + out[2].link, + GPU_constant(min), + GPU_constant(max), + &out[2].link); + } + return ret; +} + +class MixColorFunction : public fn::MultiFunction { + private: + const bool clamp_factor_; + const bool clamp_result_; + const int blend_type_; + + public: + MixColorFunction(const bool clamp_factor, const bool clamp_result, const int blend_type) + : clamp_factor_(clamp_factor), clamp_result_(clamp_result), blend_type_(blend_type) + { + static fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static fn::MFSignature create_signature() + { + fn::MFSignatureBuilder signature{"MixColor"}; + signature.single_input<float>("Factor"); + signature.single_input<ColorGeometry4f>("A"); + signature.single_input<ColorGeometry4f>("B"); + signature.single_output<ColorGeometry4f>("Result"); + return signature.build(); + } + + void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override + { + const VArray<float> &fac = params.readonly_single_input<float>(0, "Factor"); + const VArray<ColorGeometry4f> &col1 = params.readonly_single_input<ColorGeometry4f>(1, "A"); + const VArray<ColorGeometry4f> &col2 = params.readonly_single_input<ColorGeometry4f>(2, "B"); + MutableSpan<ColorGeometry4f> results = params.uninitialized_single_output<ColorGeometry4f>( + 3, "Result"); + + if (clamp_factor_) { + for (int64_t i : mask) { + results[i] = col1[i]; + ramp_blend(blend_type_, results[i], std::clamp(fac[i], 0.0f, 1.0f), col2[i]); + } + } + else { + for (int64_t i : mask) { + results[i] = col1[i]; + ramp_blend(blend_type_, results[i], fac[i], col2[i]); + } + } + + if (clamp_result_) { + for (int64_t i : mask) { + clamp_v3(results[i], 0.0f, 1.0f); + } + } + } +}; + +static const fn::MultiFunction *get_multi_function(const bNode &node) +{ + const NodeShaderMix *data = (NodeShaderMix *)node.storage; + bool uniform_factor = data->factor_mode == NODE_MIX_MODE_UNIFORM; + const bool clamp_factor = data->clamp_factor; + switch (data->data_type) { + case SOCK_FLOAT: { + if (clamp_factor) { + static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{ + "Clamp Mix Float", [](float t, const float a, const float b) { + return math::interpolate(a, b, std::clamp(t, 0.0f, 1.0f)); + }}; + return &fn; + } + else { + static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{ + "Mix Float", [](const float t, const float a, const float b) { + return math::interpolate(a, b, t); + }}; + return &fn; + } + } + case SOCK_VECTOR: { + if (clamp_factor) { + if (uniform_factor) { + static fn::CustomMF_SI_SI_SI_SO<float, float3, float3, float3> fn{ + "Clamp Mix Vector", [](const float t, const float3 a, const float3 b) { + return math::interpolate(a, b, std::clamp(t, 0.0f, 1.0f)); + }}; + return &fn; + } + else { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ + "Clamp Mix Vector Non Uniform", [](float3 t, const float3 a, const float3 b) { + t = math::clamp(t, 0.0f, 1.0f); + return a * (float3(1.0f) - t) + b * t; + }}; + return &fn; + } + } + else { + if (uniform_factor) { + static fn::CustomMF_SI_SI_SI_SO<float, float3, float3, float3> fn{ + "Mix Vector", [](const float t, const float3 a, const float3 b) { + return math::interpolate(a, b, t); + }}; + return &fn; + } + else { + static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ + "Mix Vector Non Uniform", [](const float3 t, const float3 a, const float3 b) { + return a * (float3(1.0f) - t) + b * t; + }}; + return &fn; + } + } + } + } + BLI_assert_unreachable(); + return nullptr; +} + +static void sh_node_mix_build_multi_function(NodeMultiFunctionBuilder &builder) +{ + const NodeShaderMix &storage = node_storage(builder.node()); + + if (storage.data_type == SOCK_RGBA) { + builder.construct_and_set_matching_fn<MixColorFunction>( + storage.clamp_factor, storage.clamp_result, storage.blend_type); + } + else { + const fn::MultiFunction *fn = get_multi_function(builder.node()); + builder.set_matching_fn(fn); + } +} + +} // namespace blender::nodes::node_sh_mix_cc + +void register_node_type_sh_mix() +{ + namespace file_ns = blender::nodes::node_sh_mix_cc; + + static bNodeType ntype; + sh_fn_node_type_base(&ntype, SH_NODE_MIX, "Mix", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::sh_node_mix_declare; + ntype.ui_class = file_ns::sh_node_mix_ui_class; + node_type_gpu(&ntype, file_ns::gpu_shader_mix); + node_type_update(&ntype, file_ns::sh_node_mix_update); + node_type_init(&ntype, file_ns::node_mix_init); + node_type_storage( + &ntype, "NodeShaderMix", node_free_standard_storage, node_copy_standard_storage); + ntype.build_multi_function = file_ns::sh_node_mix_build_multi_function; + ntype.draw_buttons = file_ns::sh_node_mix_layout; + ntype.labelfunc = file_ns::sh_node_mix_label; + ntype.gather_link_search_ops = file_ns::node_mix_gather_link_searches; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc index 478a6812c36..46ac8f05803 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc @@ -136,7 +136,7 @@ class MixRGBFunction : public fn::MultiFunction { static void sh_node_mix_rgb_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); bool clamp = node.custom2 & SHD_MIXRGB_CLAMP; int mix_type = node.custom1; builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type); @@ -150,11 +150,11 @@ void register_node_type_sh_mix_rgb() static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR); + sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB_LEGACY, "Mix", NODE_CLASS_OP_COLOR); ntype.declare = file_ns::sh_node_mix_rgb_declare; ntype.labelfunc = node_blend_label; node_type_gpu(&ntype, file_ns::gpu_shader_mix_rgb); ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function; - + ntype.gather_link_search_ops = nullptr; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc index cad9e1b33f2..a1c51a440d0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc @@ -261,7 +261,7 @@ class BrickFunction : public fn::MultiFunction { static void sh_node_brick_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexBrick *tex = (NodeTexBrick *)node.storage; builder.construct_and_set_matching_fn<BrickFunction>( diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc index 8478cbd406b..37c72ec1f17 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc @@ -139,7 +139,7 @@ class GradientFunction : public fn::MultiFunction { static void sh_node_gradient_tex_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexGradient *tex = (NodeTexGradient *)node.storage; builder.construct_and_set_matching_fn<GradientFunction>(tex->gradient_type); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc index 95c4a8b8e46..205d3b89016 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc @@ -161,7 +161,7 @@ class MagicFunction : public fn::MultiFunction { static void sh_node_magic_tex_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexMagic *tex = (NodeTexMagic *)node.storage; builder.construct_and_set_matching_fn<MagicFunction>(tex->depth); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc index c13ce3c3df3..a2241c2327f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc @@ -516,7 +516,7 @@ class MusgraveFunction : public fn::MultiFunction { static void sh_node_musgrave_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexMusgrave *tex = (NodeTexMusgrave *)node.storage; builder.construct_and_set_matching_fn<MusgraveFunction>(tex->dimensions, tex->musgrave_type); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc index ad24224dc7f..8475101dbaf 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc @@ -206,7 +206,7 @@ class WaveFunction : public fn::MultiFunction { static void sh_node_wave_tex_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); NodeTexWave *tex = (NodeTexWave *)node.storage; builder.construct_and_set_matching_fn<WaveFunction>( tex->wave_type, tex->bands_direction, tex->rings_direction, tex->wave_profile); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc index 6d4c491046b..64075a903ab 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc @@ -176,7 +176,7 @@ class WhiteNoiseFunction : public fn::MultiFunction { static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder) { - bNode &node = builder.node(); + const bNode &node = builder.node(); builder.construct_and_set_matching_fn<WhiteNoiseFunction>((int)node.custom1); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index 21f5c44c640..d01e03f9d71 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -225,7 +225,7 @@ static void node_shader_update_vector_math(bNodeTree *ntree, bNode *node) } } -static const fn::MultiFunction *get_multi_function(bNode &node) +static const fn::MultiFunction *get_multi_function(const bNode &node) { NodeVectorMathOperation operation = NodeVectorMathOperation(node.custom1); diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index b35f686e331..a036fc52d84 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -96,7 +96,7 @@ static float3 sh_node_vector_rotate_euler(const float3 &vector, return result + center; } -static const fn::MultiFunction *get_multi_function(bNode &node) +static const fn::MultiFunction *get_multi_function(const bNode &node) { bool invert = node.custom2; const int mode = node.custom1; diff --git a/source/blender/render/intern/pipeline.cc b/source/blender/render/intern/pipeline.cc index 8cc1293eae3..746adeaddb2 100644 --- a/source/blender/render/intern/pipeline.cc +++ b/source/blender/render/intern/pipeline.cc @@ -1948,15 +1948,17 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format); - ok &= mh->append_movie(movie_ctx_arr[view_id], - rd, - preview ? scene->r.psfra : scene->r.sfra, - scene->r.cfra, - (int *)ibuf->rect, - ibuf->x, - ibuf->y, - suffix, - reports); + if (!mh->append_movie(movie_ctx_arr[view_id], + rd, + preview ? scene->r.psfra : scene->r.sfra, + scene->r.cfra, + (int *)ibuf->rect, + ibuf->x, + ibuf->y, + suffix, + reports)) { + ok = false; + } /* imbuf knows which rects are not part of ibuf */ IMB_freeImBuf(ibuf); @@ -1979,7 +1981,7 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]); - ok = mh->append_movie(movie_ctx_arr[0], + if (!mh->append_movie(movie_ctx_arr[0], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra, @@ -1987,7 +1989,9 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, ibuf_arr[2]->x, ibuf_arr[2]->y, "", - reports); + reports)) { + ok = false; + } for (i = 0; i < 3; i++) { /* imbuf knows which rects are not part of ibuf */ diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index 2bba0ac802d..3054708fbdb 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -1591,6 +1591,7 @@ static int wm_operator_call_internal(bContext *C, case WM_OP_EXEC_AREA: case WM_OP_EXEC_SCREEN: event = nullptr; + break; default: break; } |