Blender V5.0
node_gizmo.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10
11#include "BLI_listbase.h"
12#include "BLI_math_matrix.h"
13#include "BLI_math_rotation.h"
14#include "BLI_math_vector.h"
15#include "BLI_rect.h"
16#include "BLI_string.h"
17#include "BLI_utildefines.h"
18
19#include "BKE_context.hh"
20#include "BKE_image.hh"
21#include "BKE_node_runtime.hh"
22
23#include "ED_gizmo_library.hh"
24#include "ED_screen.hh"
25
26#include "IMB_imbuf_types.hh"
27
28#include "MEM_guardedalloc.h"
29
30#include "RNA_access.hh"
31#include "RNA_prototypes.hh"
32
33#include "WM_types.hh"
34
35#include "node_intern.hh"
36
38
39/* -------------------------------------------------------------------- */
42
43static void node_gizmo_calc_matrix_space(const SpaceNode *snode,
44 const ARegion *region,
45 float matrix_space[4][4])
46{
47 unit_m4(matrix_space);
48 mul_v3_fl(matrix_space[0], snode->zoom);
49 mul_v3_fl(matrix_space[1], snode->zoom);
50 matrix_space[3][0] = (region->winx / 2) + snode->xof;
51 matrix_space[3][1] = (region->winy / 2) + snode->yof;
52}
53
55 const ARegion *region,
56 const float2 &image_dims,
57 const float2 &image_offset,
58 float matrix_space[4][4])
59{
60 unit_m4(matrix_space);
61 mul_v3_fl(matrix_space[0], snode->zoom * image_dims.x);
62 mul_v3_fl(matrix_space[1], snode->zoom * image_dims.y);
63 matrix_space[3][0] = ((region->winx / 2) + snode->xof) -
64 ((image_dims.x / 2.0f - image_offset.x) * snode->zoom);
65 matrix_space[3][1] = ((region->winy / 2) + snode->yof) -
66 ((image_dims.y / 2.0f - image_offset.y) * snode->zoom);
67}
68
70{
72 if (snode == nullptr) {
73 return false;
74 }
75
76 if ((snode->flag & SNODE_BACKDRAW) == 0) {
77 return false;
78 }
79
80 if (!snode->edittree || snode->edittree->type != NTREE_COMPOSIT) {
81 return false;
82 }
83
85 return true;
86 }
87
88 return false;
89}
90
91static const float2 GIZMO_NODE_DEFAULT_DIMS{64.0f, 64.0f};
92static float2 node_gizmo_safe_calc_dims(const ImBuf *ibuf, const float2 &fallback_dims)
93{
94 if (ibuf && ibuf->x > 0 && ibuf->y > 0) {
95 return float2{float(ibuf->x), float(ibuf->y)};
96 }
97
98 /* We typically want to divide by dims, so avoid returning zero here. */
99 BLI_assert(!math::is_any_zero(fallback_dims));
100 return fallback_dims;
101}
102
104
105/* -------------------------------------------------------------------- */
108
110 wmGizmoProperty *gz_prop,
111 void *value_p)
112{
113 float (*matrix)[4] = (float (*)[4])value_p;
114 BLI_assert(gz_prop->type->array_length == 16);
115 const SpaceNode *snode = (const SpaceNode *)gz_prop->custom_func.user_data;
116 matrix[0][0] = snode->zoom;
117 matrix[1][1] = snode->zoom;
118 matrix[3][0] = snode->xof;
119 matrix[3][1] = snode->yof;
120}
121
123 wmGizmoProperty *gz_prop,
124 const void *value_p)
125{
126 const float (*matrix)[4] = (const float (*)[4])value_p;
127 BLI_assert(gz_prop->type->array_length == 16);
128 SpaceNode *snode = (SpaceNode *)gz_prop->custom_func.user_data;
129 snode->zoom = matrix[0][0];
130 snode->xof = matrix[3][0];
131 snode->yof = matrix[3][1];
132}
133
135{
137 return false;
138 }
139
140 SpaceNode *snode = CTX_wm_space_node(C);
141 bNode *node = bke::node_get_active(*snode->edittree);
142
143 if (node && node->is_type("CompositorNodeViewer")) {
144 return true;
145 }
146
147 return false;
148}
149
150static void WIDGETGROUP_node_transform_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
151{
152 wmGizmoWrapper *wwrapper = MEM_mallocN<wmGizmoWrapper>(__func__);
153
154 wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
155
156 RNA_enum_set(wwrapper->gizmo->ptr,
157 "transform",
159
160 gzgroup->customdata = wwrapper;
161}
162
164{
165 Main *bmain = CTX_data_main(C);
166 wmGizmo *cage = ((wmGizmoWrapper *)gzgroup->customdata)->gizmo;
167 const ARegion *region = CTX_wm_region(C);
168 /* center is always at the origin */
169 const float origin[3] = {float(region->winx / 2), float(region->winy / 2), 0.0f};
170
171 void *lock;
172 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
173 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
174
175 if (UNLIKELY(ibuf == nullptr)) {
177 BKE_image_release_ibuf(ima, ibuf, lock);
178 return;
179 }
180
182
183 RNA_float_set_array(cage->ptr, "dimensions", dims);
184 WM_gizmo_set_matrix_location(cage, origin);
186
187 /* Need to set property here for undo. TODO: would prefer to do this in _init. */
188 SpaceNode *snode = CTX_wm_space_node(C);
189#if 0
190 PointerRNA nodeptr = RNA_pointer_create_discrete(snode->id, &RNA_SpaceNodeEditor, snode);
191 WM_gizmo_target_property_def_rna(cage, "offset", &nodeptr, "backdrop_offset", -1);
192 WM_gizmo_target_property_def_rna(cage, "scale", &nodeptr, "backdrop_zoom", -1);
193#endif
194
198 params.range_get_fn = nullptr;
199 params.user_data = snode;
201
202 BKE_image_release_ibuf(ima, ibuf, lock);
203}
204
206{
207 gzgt->name = "Backdrop Transform Widget";
208 gzgt->idname = "NODE_GGT_backdrop_transform";
209
211
216}
217
219
220/* -------------------------------------------------------------------- */
223
238
240{
242 bbox_group->update_data.context, &bbox_group->update_data.ptr, bbox_group->update_data.prop);
243}
244
245static void node_input_to_rect(const bNode *node,
246 const float2 &dims,
247 const float2 offset,
248 rctf *r_rect)
249{
250
251 const bNodeSocket *x_input = bke::node_find_socket(*node, SOCK_IN, "X");
252 PointerRNA x_input_rna_pointer = RNA_pointer_create_discrete(
253 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(x_input));
254 const float xmin = float(RNA_int_get(&x_input_rna_pointer, "default_value"));
255
256 const bNodeSocket *y_input = bke::node_find_socket(*node, SOCK_IN, "Y");
257 PointerRNA y_input_rna_pointer = RNA_pointer_create_discrete(
258 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(y_input));
259 const float ymin = float(RNA_int_get(&y_input_rna_pointer, "default_value"));
260
261 const bNodeSocket *width_input = bke::node_find_socket(*node, SOCK_IN, "Width");
262 PointerRNA width_input_rna_pointer = RNA_pointer_create_discrete(
263 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(width_input));
264 const float width = float(RNA_int_get(&width_input_rna_pointer, "default_value"));
265
266 const bNodeSocket *height_input = bke::node_find_socket(*node, SOCK_IN, "Height");
267 PointerRNA height_input_rna_pointer = RNA_pointer_create_discrete(
268 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(height_input));
269 const float height = float(RNA_int_get(&height_input_rna_pointer, "default_value"));
270
271 r_rect->xmin = (xmin + offset.x) / dims.x;
272 r_rect->xmax = (xmin + width + offset.x) / dims.x;
273 r_rect->ymin = (ymin + offset.y) / dims.y;
274 r_rect->ymax = (ymin + height + offset.y) / dims.y;
275}
276
277static void node_input_from_rect(bNode *node,
278 const rctf *rect,
279 const float2 &dims,
280 const float2 &offset)
281{
282 bNodeSocket *x_input = bke::node_find_socket(*node, SOCK_IN, "X");
283 PointerRNA x_input_rna_pointer = RNA_pointer_create_discrete(
284 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(x_input));
285
286 bNodeSocket *y_input = bke::node_find_socket(*node, SOCK_IN, "Y");
287 PointerRNA y_input_rna_pointer = RNA_pointer_create_discrete(
288 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(y_input));
289
290 bNodeSocket *width_input = bke::node_find_socket(*node, SOCK_IN, "Width");
291 PointerRNA width_input_rna_pointer = RNA_pointer_create_discrete(
292 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(width_input));
293
294 bNodeSocket *height_input = bke::node_find_socket(*node, SOCK_IN, "Height");
295 PointerRNA height_input_rna_pointer = RNA_pointer_create_discrete(
296 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(height_input));
297
298 const float xmin = rect->xmin * dims.x - offset.x;
299 const float width = rect->xmax * dims.x - offset.x - xmin;
300 const float ymin = rect->ymin * dims.y - offset.y;
301 const float height = rect->ymax * dims.y - offset.y - ymin;
302
303 RNA_int_set(&x_input_rna_pointer, "default_value", int(xmin));
304 RNA_int_set(&y_input_rna_pointer, "default_value", int(ymin));
305 RNA_int_set(&width_input_rna_pointer, "default_value", int(width));
306 RNA_int_set(&height_input_rna_pointer, "default_value", int(height));
307}
308
309/* scale callbacks */
311 wmGizmoProperty *gz_prop,
312 void *value_p)
313{
314 float (*matrix)[4] = (float (*)[4])value_p;
315 BLI_assert(gz_prop->type->array_length == 16);
317 const float2 dims = crop_group->state.dims;
318 const float2 offset = crop_group->state.offset;
319 const bNode *node = (const bNode *)gz_prop->custom_func.user_data;
320
321 rctf rct;
322 node_input_to_rect(node, dims, offset, &rct);
323
324 matrix[0][0] = fabsf(BLI_rctf_size_x(&rct));
325 matrix[1][1] = fabsf(BLI_rctf_size_y(&rct));
326 matrix[3][0] = (BLI_rctf_cent_x(&rct) - 0.5f) * dims[0];
327 matrix[3][1] = (BLI_rctf_cent_y(&rct) - 0.5f) * dims[1];
328}
329
331 wmGizmoProperty *gz_prop,
332 const void *value_p)
333{
334 const float (*matrix)[4] = (const float (*)[4])value_p;
335 BLI_assert(gz_prop->type->array_length == 16);
337 const float2 dims = crop_group->state.dims;
338 const float2 offset = crop_group->state.offset;
339 bNode *node = (bNode *)gz_prop->custom_func.user_data;
340
341 rctf rct;
342 node_input_to_rect(node, dims, offset, &rct);
343 BLI_rctf_resize(&rct, fabsf(matrix[0][0]), fabsf(matrix[1][1]));
344 BLI_rctf_recenter(&rct, ((matrix[3][0]) / dims[0]) + 0.5f, ((matrix[3][1]) / dims[1]) + 0.5f);
345 rctf rct_isect{};
346 rct_isect.xmin = offset.x / dims.x;
347 rct_isect.xmax = offset.x / dims.x + 1;
348 rct_isect.ymin = offset.y;
349 rct_isect.ymax = offset.y / dims.y + 1;
350 BLI_rctf_isect(&rct_isect, &rct, &rct);
351 node_input_from_rect(node, &rct, dims, offset);
352 gizmo_node_bbox_update(crop_group);
353}
354
356{
358 return false;
359 }
360
361 SpaceNode *snode = CTX_wm_space_node(C);
362 bNode *node = bke::node_get_active(*snode->edittree);
363
364 if (!node || !node->is_type("CompositorNodeCrop")) {
365 return false;
366 }
367
368 snode->edittree->ensure_topology_cache();
370 if (!STREQ(input->name, "Image") && input->is_directly_linked()) {
371 /* Note: the Image input could be connected to a single value input, in which case the
372 * gizmo has no effect. */
373 return false;
374 }
375 else if (STREQ(input->name, "Alpha Crop") && !input->is_directly_linked()) {
376 PointerRNA input_rna_pointer = RNA_pointer_create_discrete(nullptr, &RNA_NodeSocket, input);
377 if (RNA_boolean_get(&input_rna_pointer, "default_value")) {
378 /* If Alpha Crop is not set, the image size changes depending on the input parameters,
379 * so we can't usefully edit the crop in this case. */
380 return true;
381 }
382 }
383 }
384
385 return false;
386}
387
388static void WIDGETGROUP_node_crop_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
389{
390 NodeBBoxWidgetGroup *crop_group = MEM_new<NodeBBoxWidgetGroup>(__func__);
391 crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
392
393 RNA_enum_set(crop_group->border->ptr,
394 "transform",
396
397 gzgroup->customdata = crop_group;
398 gzgroup->customdata_free = [](void *customdata) {
399 MEM_delete(static_cast<NodeBBoxWidgetGroup *>(customdata));
400 };
401}
402
404{
405 ARegion *region = CTX_wm_region(C);
406 wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first;
407
408 SpaceNode *snode = CTX_wm_space_node(C);
409
410 node_gizmo_calc_matrix_space(snode, region, gz->matrix_space);
411}
412
414{
415 Main *bmain = CTX_data_main(C);
416 SpaceNode *snode = CTX_wm_space_node(C);
417
418 NodeBBoxWidgetGroup *crop_group = (NodeBBoxWidgetGroup *)gzgroup->customdata;
419 wmGizmo *gz = crop_group->border;
420
421 void *lock;
422 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
423 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
424
425 if (UNLIKELY(ibuf == nullptr)) {
427 BKE_image_release_ibuf(ima, ibuf, lock);
428 return;
429 }
430
432 copy_v2_v2(crop_group->state.offset, ima->runtime->backdrop_offset);
433
434 RNA_float_set_array(gz->ptr, "dimensions", crop_group->state.dims);
436
437 bNode *node = bke::node_get_active(*snode->edittree);
438
439 crop_group->update_data.context = (bContext *)C;
440 bNodeSocket *source_input = bke::node_find_socket(*node, SOCK_IN, "Alpha Crop");
442 reinterpret_cast<ID *>(snode->edittree), &RNA_NodeSocket, source_input);
443 crop_group->update_data.prop = RNA_struct_find_property(&crop_group->update_data.ptr, "enabled");
444 BLI_assert(crop_group->update_data.prop != nullptr);
445
449 params.range_get_fn = nullptr;
450 params.user_data = node;
452
453 BKE_image_release_ibuf(ima, ibuf, lock);
454}
455
457{
458 gzgt->name = "Backdrop Crop Widget";
459 gzgt->idname = "NODE_GGT_backdrop_crop";
460
462
468}
469
471
472/* -------------------------------------------------------------------- */
475
477 wmGizmoProperty *gz_prop,
478 void *value_p)
479{
480 float (*matrix)[4] = (float (*)[4])value_p;
481 BLI_assert(gz_prop->type->array_length == 16);
483 const float2 dims = mask_group->state.dims;
484 const float2 offset = mask_group->state.offset;
485 const bNode *node = (const bNode *)gz_prop->custom_func.user_data;
486 const float aspect = dims.x / dims.y;
487
488 float loc[3], rot[3][3], size[3];
489 mat4_to_loc_rot_size(loc, rot, size, matrix);
490
491 const bNodeSocket *rotation_input = bke::node_find_socket(*node, SOCK_IN, "Rotation");
492 const float rotation = rotation_input->default_value_typed<bNodeSocketValueFloat>()->value;
493 axis_angle_to_mat3_single(rot, 'Z', rotation);
494
495 const bNodeSocket *position_input = bke::node_find_socket(*node, SOCK_IN, "Position");
496 const float2 position = position_input->default_value_typed<bNodeSocketValueVector>()->value;
497 loc[0] = (position.x - 0.5) * dims.x + offset.x;
498 loc[1] = (position.y - 0.5) * dims.y + offset.y;
499 loc[2] = 0;
500
501 const bNodeSocket *size_input = bke::node_find_socket(*node, SOCK_IN, "Size");
502 const float2 size_value = size_input->default_value_typed<bNodeSocketValueVector>()->value;
503 size[0] = size_value.x;
504 size[1] = size_value.y * aspect;
505 size[2] = 1;
506
507 loc_rot_size_to_mat4(matrix, loc, rot, size);
508}
509
511 wmGizmoProperty *gz_prop,
512 const void *value_p)
513{
514 const float (*matrix)[4] = (const float (*)[4])value_p;
515 BLI_assert(gz_prop->type->array_length == 16);
517 const float2 dims = mask_group->state.dims;
518 const float2 offset = mask_group->state.offset;
519 bNode *node = (bNode *)gz_prop->custom_func.user_data;
520
521 bNodeSocket *position_input = bke::node_find_socket(*node, SOCK_IN, "Position");
522 const float2 position = position_input->default_value_typed<bNodeSocketValueVector>()->value;
523
524 bNodeSocket *size_input = bke::node_find_socket(*node, SOCK_IN, "Size");
525 const float2 size_value = size_input->default_value_typed<bNodeSocketValueVector>()->value;
526
527 const float aspect = dims.x / dims.y;
528 rctf rct;
529 rct.xmin = position.x - size_value.x / 2;
530 rct.xmax = position.x + size_value.x / 2;
531 rct.ymin = position.y - size_value.y / 2;
532 rct.ymax = position.y + size_value.y / 2;
533
534 float loc[3];
535 float rot[3][3];
536 float size[3];
537 mat4_to_loc_rot_size(loc, rot, size, matrix);
538
539 float eul[3];
540
541 /* Rotation can't be extracted from matrix when the gizmo width or height is zero. */
542 if (size[0] != 0 and size[1] != 0) {
543 mat4_to_eul(eul, matrix);
544 bNodeSocket *rotation_input = bke::node_find_socket(*node, SOCK_IN, "Rotation");
545 rotation_input->default_value_typed<bNodeSocketValueFloat>()->value = eul[2];
546 }
547
548 BLI_rctf_resize(&rct, fabsf(size[0]), fabsf(size[1]) / aspect);
550 &rct, ((loc[0] - offset.x) / dims.x) + 0.5, ((loc[1] - offset.y) / dims.y) + 0.5);
551
552 size_input->default_value_typed<bNodeSocketValueVector>()->value[0] = size[0];
553 size_input->default_value_typed<bNodeSocketValueVector>()->value[1] = size[1] / aspect;
554 position_input->default_value_typed<bNodeSocketValueVector>()->value[0] = rct.xmin +
555 size_value.x / 2;
556 position_input->default_value_typed<bNodeSocketValueVector>()->value[1] = rct.ymin +
557 size_value.y / 2;
558
559 gizmo_node_bbox_update(mask_group);
560}
561
563{
565 return false;
566 }
567
568 SpaceNode *snode = CTX_wm_space_node(C);
569 bNode *node = bke::node_get_active(*snode->edittree);
570
571 if (node && node->is_type("CompositorNodeBoxMask")) {
572 snode->edittree->ensure_topology_cache();
574 if (STR_ELEM(input->name, "Position", "Size", "Rotation") && input->is_directly_linked()) {
575 return false;
576 }
577 }
578 return true;
579 }
580
581 return false;
582}
583
584static void WIDGETGROUP_node_box_mask_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
585{
586 NodeBBoxWidgetGroup *mask_group = MEM_new<NodeBBoxWidgetGroup>(__func__);
587 mask_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
588
589 RNA_enum_set(mask_group->border->ptr,
590 "transform",
593
594 RNA_enum_set(mask_group->border->ptr,
595 "draw_options",
598
599 gzgroup->customdata = mask_group;
600 gzgroup->customdata_free = [](void *customdata) {
601 MEM_delete(static_cast<NodeBBoxWidgetGroup *>(customdata));
602 };
603}
604
606{
607 ARegion *region = CTX_wm_region(C);
608 wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first;
609
610 SpaceNode *snode = CTX_wm_space_node(C);
611
612 node_gizmo_calc_matrix_space(snode, region, gz->matrix_space);
613}
614
616{
617 Main *bmain = CTX_data_main(C);
618 NodeBBoxWidgetGroup *mask_group = (NodeBBoxWidgetGroup *)gzgroup->customdata;
619 wmGizmo *gz = mask_group->border;
620
621 void *lock;
622 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Render Result");
623 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
624
625 if (UNLIKELY(ibuf == nullptr)) {
627 BKE_image_release_ibuf(ima, ibuf, lock);
628 return;
629 }
630
632 copy_v2_v2(mask_group->state.offset, ima->runtime->backdrop_offset);
633
634 RNA_float_set_array(gz->ptr, "dimensions", mask_group->state.dims);
636
637 SpaceNode *snode = CTX_wm_space_node(C);
638 bNode *node = bke::node_get_active(*snode->edittree);
639
640 mask_group->update_data.context = (bContext *)C;
641 bNodeSocket *source_input = bke::node_find_socket(*node, SOCK_IN, "Mask");
643 reinterpret_cast<ID *>(snode->edittree), &RNA_NodeSocket, source_input);
644 mask_group->update_data.prop = RNA_struct_find_property(&mask_group->update_data.ptr, "enabled");
645 BLI_assert(mask_group->update_data.prop != nullptr);
646
650 params.range_get_fn = nullptr;
651 params.user_data = node;
653
654 BKE_image_release_ibuf(ima, ibuf, lock);
655}
656
658{
659 gzgt->name = "Backdrop Box Mask Widget";
660 gzgt->idname = "NODE_GGT_backdrop_box_mask";
661
663
669}
670
672
673/* -------------------------------------------------------------------- */
676
678{
680 return false;
681 }
682
683 SpaceNode *snode = CTX_wm_space_node(C);
684 bNode *node = bke::node_get_active(*snode->edittree);
685
686 if (node && node->is_type("CompositorNodeEllipseMask")) {
687 snode->edittree->ensure_topology_cache();
689 if (STR_ELEM(input->name, "Position", "Size", "Rotation") && input->is_directly_linked()) {
690 return false;
691 }
692 }
693 return true;
694 }
695
696 return false;
697}
698
700{
701 NodeBBoxWidgetGroup *mask_group = MEM_new<NodeBBoxWidgetGroup>(__func__);
702 mask_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
703
704 RNA_enum_set(mask_group->border->ptr,
705 "transform",
708 RNA_enum_set(mask_group->border->ptr, "draw_style", ED_GIZMO_CAGE2D_STYLE_CIRCLE);
709 RNA_enum_set(mask_group->border->ptr,
710 "draw_options",
713
714 gzgroup->customdata = mask_group;
715 gzgroup->customdata_free = [](void *customdata) {
716 MEM_delete(static_cast<NodeBBoxWidgetGroup *>(customdata));
717 };
718}
719
721{
722 gzgt->name = "Backdrop Ellipse Mask Widget";
723 gzgt->idname = "NODE_GGT_backdrop_ellipse_mask";
724
726
732}
733
735
736/* -------------------------------------------------------------------- */
739
748
750{
752 return false;
753 }
754
755 SpaceNode *snode = CTX_wm_space_node(C);
756 bNode *node = bke::node_get_active(*snode->edittree);
757
758 if (!node || !node->is_type("CompositorNodeGlare")) {
759 return false;
760 }
761
762 bNodeSocket &type_socket = *blender::bke::node_find_socket(*node, SOCK_IN, "Type");
763 snode->edittree->ensure_topology_cache();
764 if (type_socket.is_directly_linked()) {
765 return false;
766 }
767
768 if (type_socket.default_value_typed<bNodeSocketValueMenu>()->value != CMP_NODE_GLARE_SUN_BEAMS) {
769 return false;
770 }
771
773 if (STR_ELEM(input->name, "Sun Position") && input->is_directly_linked()) {
774 return false;
775 }
776 }
777 return true;
778}
779
780static void WIDGETGROUP_node_glare_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
781{
783
784 glare_group->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, nullptr);
785 wmGizmo *gz = glare_group->gizmo;
786
788
789 gz->scale_basis = 0.05f / 75.0f;
790
791 gzgroup->customdata = glare_group;
792}
793
795{
796 NodeGlareWidgetGroup *glare_group = (NodeGlareWidgetGroup *)gzgroup->customdata;
797 ARegion *region = CTX_wm_region(C);
798 wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first;
799
800 SpaceNode *snode = CTX_wm_space_node(C);
801
803 snode, region, glare_group->state.dims, glare_group->state.offset, gz->matrix_space);
804}
805
807{
808 Main *bmain = CTX_data_main(C);
809 NodeGlareWidgetGroup *glare_group = (NodeGlareWidgetGroup *)gzgroup->customdata;
810 wmGizmo *gz = glare_group->gizmo;
811
812 void *lock;
813 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
814 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
815
816 if (UNLIKELY(ibuf == nullptr)) {
818 BKE_image_release_ibuf(ima, ibuf, lock);
819 return;
820 }
821
823 copy_v2_v2(glare_group->state.offset, ima->runtime->backdrop_offset);
824
825 SpaceNode *snode = CTX_wm_space_node(C);
826 bNode *node = bke::node_get_active(*snode->edittree);
827
828 /* Need to set property here for undo. TODO: would prefer to do this in _init. */
829 bNodeSocket *source_input = bke::node_find_socket(*node, SOCK_IN, "Sun Position");
831 reinterpret_cast<ID *>(snode->edittree), &RNA_NodeSocket, source_input);
832 WM_gizmo_target_property_def_rna(gz, "offset", &socket_pointer, "default_value", -1);
833
835
836 BKE_image_release_ibuf(ima, ibuf, lock);
837}
838
852
854
855/* -------------------------------------------------------------------- */
858
867
869{
871 return false;
872 }
873
874 SpaceNode *snode = CTX_wm_space_node(C);
875 bNode *node = bke::node_get_active(*snode->edittree);
876
877 if (node && node->is_type("CompositorNodeCornerPin")) {
878 return true;
879 }
880
881 return false;
882}
883
884static void WIDGETGROUP_node_corner_pin_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
885{
887 const wmGizmoType *gzt_move_3d = WM_gizmotype_find("GIZMO_GT_move_3d", false);
888
889 for (int i = 0; i < 4; i++) {
890 cpin_group->gizmos[i] = WM_gizmo_new_ptr(gzt_move_3d, gzgroup, nullptr);
891 wmGizmo *gz = cpin_group->gizmos[i];
892
894
895 gz->scale_basis = 0.05f / 75.0;
896 }
897
898 gzgroup->customdata = cpin_group;
899}
900
902{
904 ARegion *region = CTX_wm_region(C);
905
906 SpaceNode *snode = CTX_wm_space_node(C);
907
908 float matrix_space[4][4];
910 snode, region, cpin_group->state.dims, cpin_group->state.offset, matrix_space);
911
912 for (int i = 0; i < 4; i++) {
913 wmGizmo *gz = cpin_group->gizmos[i];
914 copy_m4_m4(gz->matrix_space, matrix_space);
915 }
916}
917
919{
920 Main *bmain = CTX_data_main(C);
922
923 void *lock;
924 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
925 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
926
927 if (UNLIKELY(ibuf == nullptr)) {
928 for (int i = 0; i < 4; i++) {
929 wmGizmo *gz = cpin_group->gizmos[i];
931 }
932 BKE_image_release_ibuf(ima, ibuf, lock);
933 return;
934 }
935
937 copy_v2_v2(cpin_group->state.offset, ima->runtime->backdrop_offset);
938
939 SpaceNode *snode = CTX_wm_space_node(C);
940 bNode *node = bke::node_get_active(*snode->edittree);
941
942 /* need to set property here for undo. TODO: would prefer to do this in _init. */
943 int i = 0;
944 for (bNodeSocket *sock = (bNodeSocket *)node->inputs.first; sock && i < 4; sock = sock->next) {
945 if (sock->type == SOCK_VECTOR) {
946 wmGizmo *gz = cpin_group->gizmos[i++];
947
949 (ID *)snode->edittree, &RNA_NodeSocket, sock);
950 WM_gizmo_target_property_def_rna(gz, "offset", &sockptr, "default_value", -1);
951
953 }
954 }
955
956 BKE_image_release_ibuf(ima, ibuf, lock);
957}
958
972
974
975/* -------------------------------------------------------------------- */
978
980{
982 return false;
983 }
984
985 SpaceNode *snode = CTX_wm_space_node(C);
986 bNode *node = bke::node_get_active(*snode->edittree);
987
988 if (node && node->is_type("CompositorNodeSplit")) {
989 snode->edittree->ensure_topology_cache();
991 if (STR_ELEM(input->name, "Position", "Rotation") && input->is_directly_linked()) {
992 return false;
993 }
994 }
995 return true;
996 }
997
998 return false;
999}
1000
1001static void WIDGETGROUP_node_split_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
1002{
1003 NodeBBoxWidgetGroup *split_group = MEM_new<NodeBBoxWidgetGroup>(__func__);
1004 split_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
1005
1006 RNA_enum_set(split_group->border->ptr,
1007 "transform",
1009 RNA_enum_set(split_group->border->ptr, "draw_options", ED_GIZMO_CAGE_DRAW_FLAG_NOP);
1010
1011 gzgroup->customdata = split_group;
1012 gzgroup->customdata_free = [](void *customdata) {
1013 MEM_delete(static_cast<NodeBBoxWidgetGroup *>(customdata));
1014 };
1015}
1016
1018 wmGizmoProperty *gz_prop,
1019 void *value_p)
1020{
1021 float (*matrix)[4] = reinterpret_cast<float (*)[4]>(value_p);
1022 BLI_assert(gz_prop->type->array_length == 16);
1024 const float2 dims = split_group->state.dims;
1025 const float2 offset = split_group->state.offset;
1026 const bNode *node = (const bNode *)gz_prop->custom_func.user_data;
1027
1028 float loc[3], rot[3][3], size[3];
1029 mat4_to_loc_rot_size(loc, rot, size, matrix);
1030
1031 const bNodeSocket *pos_input = bke::node_find_socket(*node, SOCK_IN, "Position");
1032 const float2 pos = pos_input->default_value_typed<bNodeSocketValueVector>()->value;
1033
1034 const bNodeSocket *rotation_input = bke::node_find_socket(*node, SOCK_IN, "Rotation");
1035 const float rotation = rotation_input->default_value_typed<bNodeSocketValueFloat>()->value;
1036
1037 const float gizmo_width = 0.1f;
1038 axis_angle_to_mat3_single(rot, 'Z', rotation);
1040 matrix,
1041 float3{(pos.x - 0.5f) * dims.x + offset.x, (pos.y - 0.5f) * dims.y + offset.y, 0.0f},
1042 rot,
1043 float3{gizmo_width, std::numeric_limits<float>::epsilon(), 1.0f});
1044}
1045
1047 wmGizmoProperty *gz_prop,
1048 const void *value_p)
1049{
1050 const float (*matrix)[4] = reinterpret_cast<const float (*)[4]>(value_p);
1051 BLI_assert(gz_prop->type->array_length == 16);
1052 NodeBBoxWidgetGroup *split_group = reinterpret_cast<NodeBBoxWidgetGroup *>(
1054 const float2 dims = split_group->state.dims;
1055 const float2 offset = split_group->state.offset;
1056 bNode *node = reinterpret_cast<bNode *>(gz_prop->custom_func.user_data);
1057
1058 bNodeSocket *position_input = bke::node_find_socket(*node, SOCK_IN, "Position");
1059 bNodeSocket *rotation_input = bke::node_find_socket(*node, SOCK_IN, "Rotation");
1060
1061 float pos_x = (matrix[3][0] - offset.x) + dims.x * 0.5;
1062 float pos_y = (matrix[3][1] - offset.y) + dims.y * 0.5;
1063
1064 /* Prevent dragging the gizmo outside the image. */
1065 pos_x = math::clamp(pos_x, 0.0f, dims.x);
1066 pos_y = math::clamp(pos_y, 0.0f, dims.y);
1067
1068 position_input->default_value_typed<bNodeSocketValueVector>()->value[0] = pos_x / dims.x;
1069 position_input->default_value_typed<bNodeSocketValueVector>()->value[1] = pos_y / dims.y;
1070
1071 float3 eul;
1072 mat4_to_eul(eul, matrix);
1073
1074 rotation_input->default_value_typed<bNodeSocketValueFloat>()->value = eul[2];
1075
1076 gizmo_node_bbox_update(split_group);
1077}
1078
1080{
1081 Main *bmain = CTX_data_main(C);
1082 NodeBBoxWidgetGroup *split_group = reinterpret_cast<NodeBBoxWidgetGroup *>(gzgroup->customdata);
1083 wmGizmo *gz = split_group->border;
1084
1085 void *lock;
1086 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Render Result");
1087 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
1088
1089 if (UNLIKELY(ibuf == nullptr)) {
1091 BKE_image_release_ibuf(ima, ibuf, lock);
1092 return;
1093 }
1094
1095 /* Larger fallback size otherwise the gizmo would be partially hidden. */
1096 split_group->state.dims = node_gizmo_safe_calc_dims(ibuf, float2{1000.0f, 1000.0f});
1097 copy_v2_v2(split_group->state.offset, ima->runtime->backdrop_offset);
1098
1099 RNA_float_set_array(gz->ptr, "dimensions", split_group->state.dims);
1101
1102 SpaceNode *snode = CTX_wm_space_node(C);
1103 bNode *node = bke::node_get_active(*snode->edittree);
1104
1105 split_group->update_data.context = (bContext *)C;
1106 bNodeSocket *source_input = bke::node_find_socket(*node, SOCK_IN, "Position");
1108 reinterpret_cast<ID *>(snode->edittree), &RNA_NodeSocket, source_input);
1109 split_group->update_data.prop = RNA_struct_find_property(&split_group->update_data.ptr,
1110 "enabled");
1111
1115 params.range_get_fn = nullptr;
1116 params.user_data = node;
1118
1119 BKE_image_release_ibuf(ima, ibuf, lock);
1120}
1121
1123{
1124 gzgt->name = "Split Widget";
1125 gzgt->idname = "NODE_GGT_backdrop_split";
1126
1128
1134}
1135
1137
1138} // namespace blender::ed::space_node
SpaceNode * CTX_wm_space_node(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
Image * BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
void loc_rot_size_to_mat4(float R[4][4], const float loc[3], const float rot[3][3], const float size[3])
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void unit_m4(float m[4][4])
void axis_angle_to_mat3_single(float R[3][3], char axis, float angle)
void mat4_to_eul(float eul[3], const float mat[4][4])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition BLI_rect.h:189
bool BLI_rctf_isect(const struct rctf *src1, const struct rctf *src2, struct rctf *dest)
BLI_INLINE float BLI_rctf_cent_x(const struct rctf *rct)
Definition BLI_rect.h:185
void BLI_rctf_recenter(struct rctf *rect, float x, float y)
Definition rct.cc:602
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
void BLI_rctf_resize(struct rctf *rect, float x, float y)
Definition rct.cc:657
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
#define STR_ELEM(...)
Definition BLI_string.h:661
#define UNLIKELY(x)
#define STREQ(a, b)
@ IMA_TYPE_COMPOSITE
@ NTREE_COMPOSIT
@ SOCK_IN
@ SOCK_VECTOR
@ CMP_NODE_GLARE_SUN_BEAMS
@ SNODE_BACKDRAW
@ SNODE_GIZMO_HIDE_ACTIVE_NODE
@ SNODE_GIZMO_HIDE
@ ED_GIZMO_CAGE_DRAW_FLAG_CORNER_HANDLES
@ ED_GIZMO_CAGE_DRAW_FLAG_XFORM_CENTER_HANDLE
@ ED_GIZMO_CAGE_DRAW_FLAG_NOP
@ ED_GIZMO_CAGE2D_STYLE_CIRCLE
@ ED_GIZMO_CAGE_XFORM_FLAG_SCALE
@ ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE
@ ED_GIZMO_CAGE_XFORM_FLAG_ROTATE
@ ED_GIZMO_CAGE_XFORM_FLAG_SCALE_UNIFORM
@ ED_GIZMO_MOVE_STYLE_CROSS_2D
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ WM_GIZMO_HIDDEN
@ WM_GIZMO_DRAW_MODAL
@ WM_GIZMOGROUPTYPE_PERSISTENT
volatile int lock
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
nullptr float
#define rot(x, k)
uint pos
#define input
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
static ulong * next
static ulong state[N]
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2532
bNode * node_get_active(bNodeTree &ntree)
Definition node.cc:4685
static bool WIDGETGROUP_node_split_poll(const bContext *C, wmGizmoGroupType *)
static void WIDGETGROUP_node_split_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo_node_split_prop_matrix_set(const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value_p)
static bool WIDGETGROUP_node_transform_poll(const bContext *C, wmGizmoGroupType *)
static void gizmo_node_bbox_update(NodeBBoxWidgetGroup *bbox_group)
static void WIDGETGROUP_node_mask_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static bool WIDGETGROUP_node_ellipse_mask_poll(const bContext *C, wmGizmoGroupType *)
static void gizmo_node_box_mask_prop_matrix_set(const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value_p)
static bool node_gizmo_is_set_visible(const bContext *C)
Definition node_gizmo.cc:69
static float2 node_gizmo_safe_calc_dims(const ImBuf *ibuf, const float2 &fallback_dims)
Definition node_gizmo.cc:92
static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
static void WIDGETGROUP_node_corner_pin_setup(const bContext *, wmGizmoGroup *gzgroup)
static bool WIDGETGROUP_node_box_mask_poll(const bContext *C, wmGizmoGroupType *)
void NODE_GGT_backdrop_split(wmGizmoGroupType *gzgt)
static void WIDGETGROUP_node_crop_setup(const bContext *, wmGizmoGroup *gzgroup)
void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt)
static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void WIDGETGROUP_node_glare_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo_node_box_mask_prop_matrix_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p)
static void node_input_to_rect(const bNode *node, const float2 &dims, const float2 offset, rctf *r_rect)
static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo_node_crop_prop_matrix_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p)
static bool WIDGETGROUP_node_glare_poll(const bContext *C, wmGizmoGroupType *)
void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt)
static void WIDGETGROUP_node_transform_setup(const bContext *, wmGizmoGroup *gzgroup)
void NODE_GGT_backdrop_box_mask(wmGizmoGroupType *gzgt)
static void WIDGETGROUP_node_box_mask_setup(const bContext *, wmGizmoGroup *gzgroup)
static void gizmo_node_backdrop_prop_matrix_get(const wmGizmo *, wmGizmoProperty *gz_prop, void *value_p)
static void gizmo_node_backdrop_prop_matrix_set(const wmGizmo *, wmGizmoProperty *gz_prop, const void *value_p)
static void node_input_from_rect(bNode *node, const rctf *rect, const float2 &dims, const float2 &offset)
void NODE_GGT_backdrop_transform(wmGizmoGroupType *gzgt)
static void WIDGETGROUP_node_ellipse_mask_setup(const bContext *, wmGizmoGroup *gzgroup)
static void gizmo_node_split_prop_matrix_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p)
static void node_gizmo_calc_matrix_space(const SpaceNode *snode, const ARegion *region, float matrix_space[4][4])
Definition node_gizmo.cc:43
static bool WIDGETGROUP_node_corner_pin_poll(const bContext *C, wmGizmoGroupType *)
static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void node_gizmo_calc_matrix_space_with_image_dims(const SpaceNode *snode, const ARegion *region, const float2 &image_dims, const float2 &image_offset, float matrix_space[4][4])
Definition node_gizmo.cc:54
static void gizmo_node_crop_prop_matrix_set(const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value_p)
static void WIDGETGROUP_node_split_setup(const bContext *, wmGizmoGroup *gzgroup)
void NODE_GGT_backdrop_ellipse_mask(wmGizmoGroupType *gzgt)
static void WIDGETGROUP_node_glare_setup(const bContext *, wmGizmoGroup *gzgroup)
static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
static bool WIDGETGROUP_node_crop_poll(const bContext *C, wmGizmoGroupType *)
static void WIDGETGROUP_node_glare_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
void NODE_GGT_backdrop_glare(wmGizmoGroupType *gzgt)
static const float2 GIZMO_NODE_DEFAULT_DIMS
Definition node_gizmo.cc:91
static void WIDGETGROUP_bbox_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
T clamp(const T &a, const T &min, const T &max)
bool is_any_zero(const T &a)
VecBase< float, 2 > float2
VecBase< float, 3 > float3
#define fabsf
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
int RNA_int_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
Definition DNA_ID.h:414
ImageRuntimeHandle * runtime
void * first
struct bNodeTree * edittree
struct ID * id
ListBase inputs
struct blender::ed::space_node::NodeBBoxWidgetGroup::@337114177320035004071064132005160042304305253324 update_data
struct blender::ed::space_node::NodeBBoxWidgetGroup::@324243076160347311027122215363117004076020351055 state
struct blender::ed::space_node::NodeCornerPinWidgetGroup::@005022204207046064166265322302302232375057333331 state
struct blender::ed::space_node::NodeGlareWidgetGroup::@163305235270136235342041034115256335302022025251 state
float xmax
float xmin
float ymax
float ymin
wmGizmoGroupFnSetupKeymap setup_keymap
wmGizmoGroupFnRefresh refresh
wmGizmoGroupFnInit setup
const char * idname
eWM_GizmoFlagGroupTypeFlag flag
wmGizmoGroupFnPoll poll
wmGizmoGroupFnDrawPrepare draw_prepare
void(* customdata_free)(void *)
const wmGizmoPropertyType * type
struct wmGizmoProperty::@331027022007232055216276241130041346111314317052 custom_func
wmGizmoGroup * parent_gzgroup
PointerRNA * ptr
float scale_basis
float matrix_space[4][4]
i
Definition text_draw.cc:230
wmGizmo * WM_gizmo_new_ptr(const wmGizmoType *gzt, wmGizmoGroup *gzgroup, PointerRNA *properties)
Definition wm_gizmo.cc:85
void WM_gizmo_set_matrix_location(wmGizmo *gz, const float origin[3])
Definition wm_gizmo.cc:287
void WM_gizmo_set_flag(wmGizmo *gz, const int flag, const bool enable)
Definition wm_gizmo.cc:307
wmGizmo * WM_gizmo_new(const StringRef idname, wmGizmoGroup *gzgroup, PointerRNA *properties)
Definition wm_gizmo.cc:98
wmKeyMap * WM_gizmogroup_setup_keymap_generic_maybe_drag(const wmGizmoGroupType *, wmKeyConfig *kc)
void WM_gizmo_target_property_def_rna(wmGizmo *gz, const char *idname, PointerRNA *ptr, const char *propname, int index)
void WM_gizmo_target_property_def_func(wmGizmo *gz, const char *idname, const wmGizmoPropertyFnParams *params)
const wmGizmoType * WM_gizmotype_find(const StringRef idname, bool quiet)