Blender V4.3
node_composite_double_edge_mask.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "UI_interface.hh"
10#include "UI_resources.hh"
11
13#include "COM_node_operation.hh"
14#include "COM_utilities.hh"
15
17
18/* **************** Double Edge Mask ******************** */
19
21
23{
24 b.add_input<decl::Float>("Inner Mask")
25 .default_value(0.8f)
26 .min(0.0f)
27 .max(1.0f)
29 b.add_input<decl::Float>("Outer Mask")
30 .default_value(0.8f)
31 .min(0.0f)
32 .max(1.0f)
34 b.add_output<decl::Float>("Mask");
35}
36
38 bContext * /*C*/,
40{
42
43 col = uiLayoutColumn(layout, false);
44
45 uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE);
46 uiItemR(col, ptr, "inner_mode", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
47 uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE);
48 uiItemR(col, ptr, "edge_mode", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
49}
50
51using namespace blender::realtime_compositor;
52
54 public:
56
57 void execute() override
58 {
59 Result &inner_mask = get_input("Inner Mask");
60 Result &outer_mask = get_input("Outer Mask");
61 Result &output = get_result("Mask");
62 if (inner_mask.is_single_value() || outer_mask.is_single_value()) {
63 output.allocate_invalid();
64 return;
65 }
66
67 /* Compute an image that marks the boundary pixels of the masks as seed pixels in the format
68 * expected by the jump flooding algorithm. */
69 Result inner_boundary = context().create_result(ResultType::Int2, ResultPrecision::Half);
70 Result outer_boundary = context().create_result(ResultType::Int2, ResultPrecision::Half);
71 compute_boundary(inner_boundary, outer_boundary);
72
73 /* Compute a jump flooding table for each mask boundary to get a distance transform to each of
74 * the boundaries. */
75 Result flooded_inner_boundary = context().create_result(ResultType::Int2,
76 ResultPrecision::Half);
77 Result flooded_outer_boundary = context().create_result(ResultType::Int2,
78 ResultPrecision::Half);
79 jump_flooding(context(), inner_boundary, flooded_inner_boundary);
80 jump_flooding(context(), outer_boundary, flooded_outer_boundary);
81 inner_boundary.release();
82 outer_boundary.release();
83
84 /* Compute the gradient based on the jump flooding table. */
85 compute_gradient(flooded_inner_boundary, flooded_outer_boundary);
86 flooded_inner_boundary.release();
87 flooded_outer_boundary.release();
88 }
89
90 void compute_boundary(Result &inner_boundary, Result &outer_boundary)
91 {
92 GPUShader *shader = context().get_shader("compositor_double_edge_mask_compute_boundary",
93 ResultPrecision::Half);
94 GPU_shader_bind(shader);
95
96 GPU_shader_uniform_1b(shader, "include_all_inner_edges", include_all_inner_edges());
97 GPU_shader_uniform_1b(shader, "include_edges_of_image", include_edges_of_image());
98
99 const Result &inner_mask = get_input("Inner Mask");
100 inner_mask.bind_as_texture(shader, "inner_mask_tx");
101
102 const Result &outer_mask = get_input("Outer Mask");
103 outer_mask.bind_as_texture(shader, "outer_mask_tx");
104
105 const Domain domain = compute_domain();
106
107 inner_boundary.allocate_texture(domain);
108 inner_boundary.bind_as_image(shader, "inner_boundary_img");
109
110 outer_boundary.allocate_texture(domain);
111 outer_boundary.bind_as_image(shader, "outer_boundary_img");
112
113 compute_dispatch_threads_at_least(shader, domain.size);
114
115 inner_mask.unbind_as_texture();
116 outer_mask.unbind_as_texture();
117 inner_boundary.unbind_as_image();
118 outer_boundary.unbind_as_image();
120 }
121
122 void compute_gradient(Result &flooded_inner_boundary, Result &flooded_outer_boundary)
123 {
124 GPUShader *shader = context().get_shader("compositor_double_edge_mask_compute_gradient");
125 GPU_shader_bind(shader);
126
127 const Result &inner_mask = get_input("Inner Mask");
128 inner_mask.bind_as_texture(shader, "inner_mask_tx");
129
130 const Result &outer_mask = get_input("Outer Mask");
131 outer_mask.bind_as_texture(shader, "outer_mask_tx");
132
133 flooded_inner_boundary.bind_as_texture(shader, "flooded_inner_boundary_tx");
134 flooded_outer_boundary.bind_as_texture(shader, "flooded_outer_boundary_tx");
135
136 const Domain domain = compute_domain();
137 Result &output = get_result("Mask");
138 output.allocate_texture(domain);
139 output.bind_as_image(shader, "output_img");
140
141 compute_dispatch_threads_at_least(shader, domain.size);
142
143 inner_mask.unbind_as_texture();
144 outer_mask.unbind_as_texture();
145 output.unbind_as_image();
147 }
148
149 /* If false, only edges of the inner mask that lie inside the outer mask will be considered. If
150 * true, all edges of the inner mask will be considered. */
152 {
153 return !bool(bnode().custom1);
154 }
155
156 /* If true, the edges of the image that intersects the outer mask will be considered edges o the
157 * outer mask. If false, the outer mask will be considered open-ended. */
159 {
160 return bool(bnode().custom2);
161 }
162};
163
165{
166 return new DoubleEdgeMaskOperation(context, node);
167}
168
169} // namespace blender::nodes::node_composite_double_edge_mask_cc
170
172{
174
175 static blender::bke::bNodeType ntype; /* Allocate a node type data structure. */
176
177 cmp_node_type_base(&ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE);
178 ntype.declare = file_ns::cmp_node_double_edge_mask_declare;
179 ntype.draw_buttons = file_ns::node_composit_buts_double_edge_mask;
180 ntype.get_compositor_operation = file_ns::get_compositor_operation;
181
183}
#define NODE_CLASS_MATTE
Definition BKE_node.hh:411
#define IFACE_(msgid)
void GPU_shader_bind(GPUShader *shader)
void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value)
void GPU_shader_unbind()
void uiItemL(uiLayout *layout, const char *name, int icon)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
struct GPUShader GPUShader
void compute_gradient(Result &flooded_inner_boundary, Result &flooded_outer_boundary)
GPUShader * get_shader(const char *info_name, ResultPrecision precision)
Result create_result(ResultType type, ResultPrecision precision)
NodeOperation(Context &context, DNode node)
Result & get_input(StringRef identifier) const
Definition operation.cc:144
Result & get_result(StringRef identifier)
Definition operation.cc:46
void bind_as_image(GPUShader *shader, const char *image_name, bool read=false) const
Definition result.cc:264
void allocate_texture(Domain domain, bool from_pool=true)
Definition result.cc:204
void bind_as_texture(GPUShader *shader, const char *texture_name) const
Definition result.cc:253
local_group_size(16, 16) .push_constant(Type b
uint col
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
static void cmp_node_double_edge_mask_declare(NodeDeclarationBuilder &b)
static void node_composit_buts_double_edge_mask(uiLayout *layout, bContext *, PointerRNA *ptr)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
void jump_flooding(Context &context, Result &input, Result &output)
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:131
void register_node_type_cmp_doubleedgemask()
void cmp_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
Defines a node type.
Definition BKE_node.hh:218
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:324
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeDeclareFunction declare
Definition BKE_node.hh:347
PointerRNA * ptr
Definition wm_files.cc:4126