Blender V4.5
node_composite_boxmask.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10
11#include "BKE_node.hh"
12#include "BLI_math_base.hh"
15
16#include "UI_interface.hh"
17#include "UI_resources.hh"
18
19#include "GPU_shader.hh"
20
21#include "COM_node_operation.hh"
22#include "COM_utilities.hh"
23
25
26/* **************** SCALAR MATH ******************** */
27
29
31{
32 b.add_input<decl::Float>("Mask").subtype(PROP_FACTOR).default_value(0.0f).min(0.0f).max(1.0f);
33 b.add_input<decl::Float>("Value").subtype(PROP_FACTOR).default_value(1.0f).min(0.0f).max(1.0f);
34 b.add_input<decl::Vector>("Position")
35 .subtype(PROP_FACTOR)
36 .dimensions(2)
37 .default_value({0.5f, 0.5f})
38 .min(-0.5f)
39 .max(1.5f)
40 .compositor_expects_single_value();
41 b.add_input<decl::Vector>("Size")
42 .subtype(PROP_FACTOR)
43 .dimensions(2)
44 .default_value({0.2f, 0.1f})
45 .min(0.0f)
46 .max(1.0f)
47 .compositor_expects_single_value();
48 b.add_input<decl::Float>("Rotation").subtype(PROP_ANGLE).compositor_expects_single_value();
49
50 b.add_output<decl::Float>("Mask");
51}
52
54{
55 layout->prop(ptr, "mask_type", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE);
56}
57
58using namespace blender::compositor;
59
60template<CMPNodeMaskType MaskType>
61static void box_mask(const Result &base_mask,
62 const Result &value_mask,
63 Result &output_mask,
64 const int2 &texel,
65 const int2 &domain_size,
66 const float2 &location,
67 const float2 &size,
68 const float cos_angle,
69 const float sin_angle)
70{
71 float2 uv = float2(texel) / float2(domain_size - int2(1));
72 uv -= location;
73 uv.y *= float(domain_size.y) / float(domain_size.x);
74 uv = float2x2(float2(cos_angle, -sin_angle), float2(sin_angle, cos_angle)) * uv;
75 bool is_inside = math::abs(uv.x) < size.x && math::abs(uv.y) < size.y;
76
77 float base_mask_value = base_mask.load_pixel<float, true>(texel);
78 float value = value_mask.load_pixel<float, true>(texel);
79
80 float output_mask_value = 0.0f;
81 if constexpr (MaskType == CMP_NODE_MASKTYPE_ADD) {
82 output_mask_value = is_inside ? math::max(base_mask_value, value) : base_mask_value;
83 }
84 else if constexpr (MaskType == CMP_NODE_MASKTYPE_SUBTRACT) {
85 output_mask_value = is_inside ? math::clamp(base_mask_value - value, 0.0f, 1.0f) :
86 base_mask_value;
87 }
88 else if constexpr (MaskType == CMP_NODE_MASKTYPE_MULTIPLY) {
89 output_mask_value = is_inside ? base_mask_value * value : 0.0f;
90 }
91 else if constexpr (MaskType == CMP_NODE_MASKTYPE_NOT) {
92 output_mask_value = is_inside ? (base_mask_value > 0.0f ? 0.0f : value) : base_mask_value;
93 }
94
95 output_mask.store_pixel(texel, output_mask_value);
96}
97
99 public:
101
102 void execute() override
103 {
104 const Result &input_mask = get_input("Mask");
105 Result &output_mask = get_result("Mask");
106 /* For single value masks, the output will assume the compositing region, so ensure it is valid
107 * first. See the compute_domain method. */
108 if (input_mask.is_single_value() && !context().is_valid_compositing_region()) {
109 output_mask.allocate_invalid();
110 return;
111 }
112
113 if (this->context().use_gpu()) {
114 this->execute_gpu();
115 }
116 else {
117 this->execute_cpu();
118 }
119 }
120
122 {
123 GPUShader *shader = context().get_shader(get_shader_name());
124 GPU_shader_bind(shader);
125
126 const Domain domain = compute_domain();
127
128 GPU_shader_uniform_2iv(shader, "domain_size", domain.size);
129
130 GPU_shader_uniform_2fv(shader, "location", get_location());
131 GPU_shader_uniform_2fv(shader, "size", get_size() / 2.0f);
132 GPU_shader_uniform_1f(shader, "cos_angle", std::cos(get_angle()));
133 GPU_shader_uniform_1f(shader, "sin_angle", std::sin(get_angle()));
134
135 const Result &input_mask = get_input("Mask");
136 input_mask.bind_as_texture(shader, "base_mask_tx");
137
138 const Result &value = get_input("Value");
139 value.bind_as_texture(shader, "mask_value_tx");
140
141 Result &output_mask = get_result("Mask");
142 output_mask.allocate_texture(domain);
143 output_mask.bind_as_image(shader, "output_mask_img");
144
146
147 input_mask.unbind_as_texture();
148 value.unbind_as_texture();
149 output_mask.unbind_as_image();
151 }
152
153 const char *get_shader_name()
154 {
155 switch (get_mask_type()) {
156 default:
158 return "compositor_box_mask_add";
160 return "compositor_box_mask_subtract";
162 return "compositor_box_mask_multiply";
164 return "compositor_box_mask_not";
165 }
166 }
167
169 {
170 const Result &base_mask = this->get_input("Mask");
171 const Result &value_mask = this->get_input("Value");
172
173 Result &output_mask = get_result("Mask");
174 const Domain domain = this->compute_domain();
175 output_mask.allocate_texture(domain);
176
177 const int2 domain_size = domain.size;
178 const float2 location = this->get_location();
179 const float2 size = this->get_size() / 2.0f;
180 const float cos_angle = math::cos(this->get_angle());
181 const float sin_angle = math::sin(this->get_angle());
182
183 switch (this->get_mask_type()) {
185 parallel_for(domain_size, [&](const int2 texel) {
187 value_mask,
188 output_mask,
189 texel,
190 domain_size,
191 location,
192 size,
193 cos_angle,
194 sin_angle);
195 });
196 break;
198 parallel_for(domain_size, [&](const int2 texel) {
200 value_mask,
201 output_mask,
202 texel,
203 domain_size,
204 location,
205 size,
206 cos_angle,
207 sin_angle);
208 });
209 break;
211 parallel_for(domain_size, [&](const int2 texel) {
213 value_mask,
214 output_mask,
215 texel,
216 domain_size,
217 location,
218 size,
219 cos_angle,
220 sin_angle);
221 });
222 break;
224 parallel_for(domain_size, [&](const int2 texel) {
226 value_mask,
227 output_mask,
228 texel,
229 domain_size,
230 location,
231 size,
232 cos_angle,
233 sin_angle);
234 });
235 break;
236 }
237 }
238
240 {
241 if (get_input("Mask").is_single_value()) {
242 return Domain(context().get_compositing_region_size());
243 }
244 return get_input("Mask").domain();
245 }
246
248 {
249 return CMPNodeMaskType(bnode().custom1);
250 }
251
253 {
254 return this->get_input("Position").get_single_value_default(float3(0.5f, 0.5f, 0.0f)).xy();
255 }
256
258 {
259 return math::max(
260 float2(0.0f),
261 this->get_input("Size").get_single_value_default(float3(0.2f, 0.1f, 0.0f)).xy());
262 }
263
264 float get_angle()
265 {
266 return this->get_input("Rotation").get_single_value_default(0.0f);
267 }
268};
269
271{
272 return new BoxMaskOperation(context, node);
273}
274
275} // namespace blender::nodes::node_composite_boxmask_cc
276
278{
280
281 static blender::bke::bNodeType ntype;
282
283 cmp_node_type_base(&ntype, "CompositorNodeBoxMask", CMP_NODE_MASK_BOX);
284 ntype.ui_name = "Box Mask";
285 ntype.ui_description = "Create rectangular mask suitable for use as a simple matte";
286 ntype.enum_name_legacy = "BOXMASK";
287 ntype.nclass = NODE_CLASS_MATTE;
288 ntype.declare = file_ns::cmp_node_boxmask_declare;
289 ntype.draw_buttons = file_ns::node_composit_buts_boxmask;
290 ntype.get_compositor_operation = file_ns::get_compositor_operation;
291
293}
#define NODE_CLASS_MATTE
Definition BKE_node.hh:440
#define CMP_NODE_MASK_BOX
CMPNodeMaskType
void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2])
void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
void GPU_shader_bind(GPUShader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2])
void GPU_shader_unbind()
#define NOD_REGISTER_NODE(REGISTER_FUNC)
@ PROP_ANGLE
Definition RNA_types.hh:240
@ PROP_FACTOR
Definition RNA_types.hh:239
@ UI_ITEM_R_SPLIT_EMPTY_NAME
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
GPUShader * get_shader(const char *info_name, ResultPrecision precision)
NodeOperation(Context &context, DNode node)
Result & get_result(StringRef identifier)
Definition operation.cc:39
Result & get_input(StringRef identifier) const
Definition operation.cc:138
T get_single_value_default(const T &default_value) const
void allocate_texture(Domain domain, bool from_pool=true)
Definition result.cc:309
void store_pixel(const int2 &texel, const T &pixel_value)
void unbind_as_texture() const
Definition result.cc:389
void bind_as_texture(GPUShader *shader, const char *texture_name) const
Definition result.cc:365
const Domain & domain() const
T load_pixel(const int2 &texel) const
void bind_as_image(GPUShader *shader, const char *image_name, bool read=false) const
Definition result.cc:376
void unbind_as_image() const
Definition result.cc:395
bool is_single_value() const
Definition result.cc:625
#define CMP_NODE_MASKTYPE_MULTIPLY
#define CMP_NODE_MASKTYPE_ADD
#define CMP_NODE_MASKTYPE_NOT
#define CMP_NODE_MASKTYPE_SUBTRACT
static bool is_inside(int x, int y, int cols, int rows)
Definition filesel.cc:772
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:170
void parallel_for(const int2 range, const Function &function)
T cos(const AngleRadianBase< T > &a)
T clamp(const T &a, const T &min, const T &max)
T sin(const AngleRadianBase< T > &a)
T max(const T &a, const T &b)
T abs(const T &a)
static void box_mask(const Result &base_mask, const Result &value_mask, Result &output_mask, const int2 &texel, const int2 &domain_size, const float2 &location, const float2 &size, const float cos_angle, const float sin_angle)
static void cmp_node_boxmask_declare(NodeDeclarationBuilder &b)
static void node_composit_buts_boxmask(uiLayout *layout, bContext *, PointerRNA *ptr)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
MatBase< float, 2, 2 > float2x2
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
static void register_node_type_cmp_boxmask()
void cmp_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
#define min(a, b)
Definition sort.cc:36
Defines a node type.
Definition BKE_node.hh:226
std::string ui_description
Definition BKE_node.hh:232
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:336
const char * enum_name_legacy
Definition BKE_node.hh:235
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:355
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
int xy[2]
Definition wm_draw.cc:174
PointerRNA * ptr
Definition wm_files.cc:4227