Compositor: Turn Dilate node options into inputs
This patch turns the options of the Dilate node into inputs. Reference #137223. Pull Request: https://projects.blender.org/blender/blender/pulls/137593
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 29
|
||||
#define BLENDER_FILE_SUBVERSION 30
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
||||
@@ -768,6 +768,11 @@ static void write_compositor_legacy_properties(bNodeTree &node_tree)
|
||||
write_input_to_property_float("Light Adaptation", storage->a);
|
||||
write_input_to_property_float("Chromatic Adaptation", storage->c);
|
||||
}
|
||||
|
||||
if (node->type_legacy == CMP_NODE_DILATEERODE) {
|
||||
write_input_to_property_int16("Size", node->custom2);
|
||||
write_input_to_property_float("Falloff Size", node->custom3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2324,6 +2324,54 @@ static void do_version_tone_map_node_options_to_inputs_animation(bNodeTree *node
|
||||
});
|
||||
}
|
||||
|
||||
/* The options were converted into inputs. */
|
||||
static void do_version_dilate_node_options_to_inputs(bNodeTree *node_tree, bNode *node)
|
||||
{
|
||||
if (!blender::bke::node_find_socket(*node, SOCK_IN, "Size")) {
|
||||
bNodeSocket *input = blender::bke::node_add_static_socket(
|
||||
*node_tree, *node, SOCK_IN, SOCK_INT, PROP_NONE, "Size", "Size");
|
||||
input->default_value_typed<bNodeSocketValueInt>()->value = node->custom2;
|
||||
}
|
||||
|
||||
if (!blender::bke::node_find_socket(*node, SOCK_IN, "Falloff Size")) {
|
||||
bNodeSocket *input = blender::bke::node_add_static_socket(
|
||||
*node_tree, *node, SOCK_IN, SOCK_FLOAT, PROP_NONE, "Falloff Size", "Falloff Size");
|
||||
input->default_value_typed<bNodeSocketValueFloat>()->value = node->custom3;
|
||||
}
|
||||
}
|
||||
|
||||
/* The options were converted into inputs. */
|
||||
static void do_version_dilate_node_options_to_inputs_animation(bNodeTree *node_tree, bNode *node)
|
||||
{
|
||||
/* Compute the RNA path of the node. */
|
||||
char escaped_node_name[sizeof(node->name) * 2 + 1];
|
||||
BLI_str_escape(escaped_node_name, node->name, sizeof(escaped_node_name));
|
||||
const std::string node_rna_path = fmt::format("nodes[\"{}\"]", escaped_node_name);
|
||||
|
||||
BKE_fcurves_id_cb(&node_tree->id, [&](ID * /*id*/, FCurve *fcurve) {
|
||||
/* The FCurve does not belong to the node since its RNA path doesn't start with the node's RNA
|
||||
* path. */
|
||||
if (!blender::StringRef(fcurve->rna_path).startswith(node_rna_path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Change the RNA path of the FCurve from the old properties to the new inputs, adjusting the
|
||||
* values of the FCurves frames when needed. */
|
||||
char *old_rna_path = fcurve->rna_path;
|
||||
if (BLI_str_endswith(fcurve->rna_path, "distance")) {
|
||||
fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[1].default_value");
|
||||
}
|
||||
else if (BLI_str_endswith(fcurve->rna_path, "edge")) {
|
||||
fcurve->rna_path = BLI_sprintfN("%s.%s", node_rna_path.c_str(), "inputs[2].default_value");
|
||||
}
|
||||
|
||||
/* The RNA path was changed, free the old path. */
|
||||
if (fcurve->rna_path != old_rna_path) {
|
||||
MEM_freeN(old_rna_path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void do_version_viewer_shortcut(bNodeTree *node_tree)
|
||||
{
|
||||
LISTBASE_FOREACH_MUTABLE (bNode *, node, &node_tree->nodes) {
|
||||
@@ -2869,6 +2917,19 @@ void do_versions_after_linking_400(FileData *fd, Main *bmain)
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 30)) {
|
||||
FOREACH_NODETREE_BEGIN (bmain, node_tree, id) {
|
||||
if (node_tree->type == NTREE_COMPOSIT) {
|
||||
LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
|
||||
if (node->type_legacy == CMP_NODE_DILATEERODE) {
|
||||
do_version_dilate_node_options_to_inputs_animation(node_tree, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
@@ -7532,6 +7593,19 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 30)) {
|
||||
FOREACH_NODETREE_BEGIN (bmain, node_tree, id) {
|
||||
if (node_tree->type == NTREE_COMPOSIT) {
|
||||
LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
|
||||
if (node->type_legacy == CMP_NODE_DILATEERODE) {
|
||||
do_version_dilate_node_options_to_inputs(node_tree, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/* Always run this versioning (keep at the bottom of the function). Meshes are written with the
|
||||
* legacy format which always needs to be converted to the new format on file load. To be moved
|
||||
* to a subversion check in 5.0. */
|
||||
|
||||
@@ -3898,6 +3898,10 @@ static const char node_input_contrast[] = "Contrast";
|
||||
static const char node_input_light_adaptation[] = "Light Adaptation";
|
||||
static const char node_input_chromatic_adaptation[] = "Chromatic Adaptation";
|
||||
|
||||
/* Dilate/Erode node. */
|
||||
static const char node_input_size[] = "Size";
|
||||
static const char node_input_falloff_size[] = "Falloff Size";
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* White Balance Node.
|
||||
*/
|
||||
@@ -7526,17 +7530,27 @@ static void def_cmp_dilate_erode(BlenderRNA * /*brna*/, StructRNA *srna)
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "distance", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, nullptr, "custom2");
|
||||
RNA_def_property_int_funcs(prop,
|
||||
"rna_node_property_to_input_getter<int, node_input_size>",
|
||||
"rna_node_property_to_input_setter<int, node_input_size>",
|
||||
nullptr);
|
||||
RNA_def_property_range(prop, -5000, 5000);
|
||||
RNA_def_property_ui_range(prop, -100, 100, 1, -1);
|
||||
RNA_def_property_ui_text(prop, "Distance", "Distance to grow/shrink (number of iterations)");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Distance",
|
||||
"Distance to grow/shrink (number of iterations). (Deprecated: Use Size input instead.)");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
/* CMP_NODE_DILATE_ERODE_DISTANCE_THRESH only */
|
||||
prop = RNA_def_property(srna, "edge", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "custom3");
|
||||
RNA_def_property_float_funcs(prop,
|
||||
"rna_node_property_to_input_getter<float, node_input_falloff_size>",
|
||||
"rna_node_property_to_input_setter<float, node_input_falloff_size>",
|
||||
nullptr);
|
||||
RNA_def_property_range(prop, -100, 100);
|
||||
RNA_def_property_ui_text(prop, "Edge", "Edge to inset");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Edge", "Edge to inset. (Deprecated: Use Falloff Size input instead.)");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_IMAGE);
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
|
||||
@@ -38,6 +38,20 @@ NODE_STORAGE_FUNCS(NodeDilateErode)
|
||||
static void cmp_node_dilate_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Float>("Mask").default_value(0.0f).min(0.0f).max(1.0f);
|
||||
b.add_input<decl::Int>("Size")
|
||||
.default_value(0)
|
||||
.description(
|
||||
"The size of dilation/erosion in pixels. Positive values dilates and negative values "
|
||||
"erodes")
|
||||
.compositor_expects_single_value();
|
||||
b.add_input<decl::Float>("Falloff Size")
|
||||
.default_value(0.0f)
|
||||
.min(0.0f)
|
||||
.description(
|
||||
"The size of the falloff from the edges in pixels. If less than two pixels, the edges "
|
||||
"will be anti-aliased")
|
||||
.compositor_expects_single_value();
|
||||
|
||||
b.add_output<decl::Float>("Mask");
|
||||
}
|
||||
|
||||
@@ -51,17 +65,18 @@ static void node_composit_init_dilateerode(bNodeTree * /*ntree*/, bNode *node)
|
||||
static void node_composit_buts_dilateerode(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
uiItemR(layout, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
|
||||
uiItemR(layout, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
|
||||
switch (RNA_enum_get(ptr, "mode")) {
|
||||
case CMP_NODE_DILATE_ERODE_DISTANCE_THRESHOLD:
|
||||
uiItemR(layout, ptr, "edge", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
|
||||
break;
|
||||
case CMP_NODE_DILATE_ERODE_DISTANCE_FEATHER:
|
||||
uiItemR(layout, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
|
||||
break;
|
||||
if (RNA_enum_get(ptr, "mode") == CMP_NODE_DILATE_ERODE_DISTANCE_FEATHER) {
|
||||
uiItemR(layout, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void node_update(bNodeTree *ntree, bNode *node)
|
||||
{
|
||||
bNodeSocket *falloff_size_input = bke::node_find_socket(*node, SOCK_IN, "Falloff Size");
|
||||
const bool is_falloff_size_needed = node->custom1 == CMP_NODE_DILATE_ERODE_DISTANCE_THRESHOLD;
|
||||
blender::bke::node_set_socket_availability(*ntree, *falloff_size_input, is_falloff_size_needed);
|
||||
}
|
||||
|
||||
using namespace blender::compositor;
|
||||
|
||||
class DilateErodeOperation : public NodeOperation {
|
||||
@@ -319,7 +334,7 @@ class DilateErodeOperation : public NodeOperation {
|
||||
|
||||
void execute_distance()
|
||||
{
|
||||
morphological_distance(context(), get_input("Mask"), get_result("Mask"), get_distance());
|
||||
morphological_distance(context(), get_input("Mask"), get_result("Mask"), this->get_size());
|
||||
}
|
||||
|
||||
/* ------------------------------------------
|
||||
@@ -337,10 +352,10 @@ class DilateErodeOperation : public NodeOperation {
|
||||
this->execute_distance_threshold_cpu(output_mask);
|
||||
}
|
||||
|
||||
/* For configurations where there is little user-specified inset, anti-alias the result for
|
||||
* smoother edges. */
|
||||
/* For configurations where there is little user-specified falloff size, anti-alias the result
|
||||
* for smoother edges. */
|
||||
Result &output = this->get_result("Mask");
|
||||
if (this->get_inset() < 2.0f) {
|
||||
if (this->get_falloff_size() < 2.0f) {
|
||||
smaa(this->context(), output_mask, output);
|
||||
output_mask.release();
|
||||
}
|
||||
@@ -354,9 +369,9 @@ class DilateErodeOperation : public NodeOperation {
|
||||
GPUShader *shader = context().get_shader("compositor_morphological_distance_threshold");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "inset", math::max(this->get_inset(), 10e-6f));
|
||||
GPU_shader_uniform_1f(shader, "inset", math::max(this->get_falloff_size(), 10e-6f));
|
||||
GPU_shader_uniform_1i(shader, "radius", get_morphological_distance_threshold_radius());
|
||||
GPU_shader_uniform_1i(shader, "distance", get_distance());
|
||||
GPU_shader_uniform_1i(shader, "distance", this->get_size());
|
||||
|
||||
const Result &input_mask = get_input("Mask");
|
||||
input_mask.bind_as_texture(shader, "input_tx");
|
||||
@@ -381,9 +396,9 @@ class DilateErodeOperation : public NodeOperation {
|
||||
|
||||
const int2 image_size = input.domain().size;
|
||||
|
||||
const float inset = math::max(this->get_inset(), 10e-6f);
|
||||
const float inset = math::max(this->get_falloff_size(), 10e-6f);
|
||||
const int radius = this->get_morphological_distance_threshold_radius();
|
||||
const int distance = this->get_distance();
|
||||
const int distance = this->get_size();
|
||||
|
||||
/* The Morphological Distance Threshold operation is effectively three consecutive operations
|
||||
* implemented as a single operation. The three operations are as follows:
|
||||
@@ -476,7 +491,7 @@ class DilateErodeOperation : public NodeOperation {
|
||||
/* See the discussion in the implementation for more information. */
|
||||
int get_morphological_distance_threshold_radius()
|
||||
{
|
||||
return int(math::ceil(get_inset())) + math::abs(get_distance());
|
||||
return int(math::ceil(this->get_falloff_size())) + math::abs(this->get_size());
|
||||
}
|
||||
|
||||
/* ----------------------------------------
|
||||
@@ -488,7 +503,7 @@ class DilateErodeOperation : public NodeOperation {
|
||||
morphological_distance_feather(context(),
|
||||
get_input("Mask"),
|
||||
get_result("Mask"),
|
||||
get_distance(),
|
||||
this->get_size(),
|
||||
node_storage(bnode()).falloff);
|
||||
}
|
||||
|
||||
@@ -503,40 +518,42 @@ class DilateErodeOperation : public NodeOperation {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (get_method() == CMP_NODE_DILATE_ERODE_DISTANCE_THRESHOLD && get_inset() != 0.0f) {
|
||||
if (get_method() == CMP_NODE_DILATE_ERODE_DISTANCE_THRESHOLD &&
|
||||
this->get_falloff_size() != 0.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (get_distance() == 0) {
|
||||
if (this->get_size() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Gets the size of the structuring element. See the get_distance method for more information. */
|
||||
/* Gets the size of the structuring element. See the get_size method for more information. */
|
||||
int get_structuring_element_size()
|
||||
{
|
||||
return math::abs(this->get_distance()) * 2 + 1;
|
||||
return math::abs(this->get_size()) * 2 + 1;
|
||||
}
|
||||
|
||||
/* Returns true if dilation should be performed, as opposed to erosion. See the get_distance()
|
||||
/* Returns true if dilation should be performed, as opposed to erosion. See the get_size()
|
||||
* method for more information. */
|
||||
bool is_dilation()
|
||||
{
|
||||
return this->get_distance() > 0;
|
||||
return this->get_size() > 0;
|
||||
}
|
||||
|
||||
/* The signed radius of the structuring element, that is, half the structuring element size. The
|
||||
* sign indicates either dilation or erosion, where negative values means erosion. */
|
||||
int get_distance()
|
||||
int get_size()
|
||||
{
|
||||
return bnode().custom2;
|
||||
return this->get_input("Size").get_single_value_default(0);
|
||||
}
|
||||
|
||||
float get_inset()
|
||||
float get_falloff_size()
|
||||
{
|
||||
return bnode().custom3;
|
||||
return math::max(0.0f, this->get_input("Falloff Size").get_single_value_default(0.0f));
|
||||
}
|
||||
|
||||
CMPNodeDilateErodeMethod get_method()
|
||||
@@ -565,6 +582,7 @@ void register_node_type_cmp_dilateerode()
|
||||
ntype.nclass = NODE_CLASS_OP_FILTER;
|
||||
ntype.draw_buttons = file_ns::node_composit_buts_dilateerode;
|
||||
ntype.declare = file_ns::cmp_node_dilate_declare;
|
||||
ntype.updatefunc = file_ns::node_update;
|
||||
ntype.initfunc = file_ns::node_composit_init_dilateerode;
|
||||
blender::bke::node_type_storage(
|
||||
ntype, "NodeDilateErode", node_free_standard_storage, node_copy_standard_storage);
|
||||
|
||||
Reference in New Issue
Block a user