Blender V4.5
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
92
93/* -------------------------------------------------------------------- */
96
98 wmGizmoProperty *gz_prop,
99 void *value_p)
100{
101 float(*matrix)[4] = (float(*)[4])value_p;
102 BLI_assert(gz_prop->type->array_length == 16);
103 const SpaceNode *snode = (const SpaceNode *)gz_prop->custom_func.user_data;
104 matrix[0][0] = snode->zoom;
105 matrix[1][1] = snode->zoom;
106 matrix[3][0] = snode->xof;
107 matrix[3][1] = snode->yof;
108}
109
111 wmGizmoProperty *gz_prop,
112 const void *value_p)
113{
114 const float(*matrix)[4] = (const float(*)[4])value_p;
115 BLI_assert(gz_prop->type->array_length == 16);
116 SpaceNode *snode = (SpaceNode *)gz_prop->custom_func.user_data;
117 snode->zoom = matrix[0][0];
118 snode->xof = matrix[3][0];
119 snode->yof = matrix[3][1];
120}
121
123{
125 return false;
126 }
127
128 SpaceNode *snode = CTX_wm_space_node(C);
129 bNode *node = bke::node_get_active(*snode->edittree);
130
131 if (node && node->is_type("CompositorNodeViewer")) {
132 return true;
133 }
134
135 return false;
136}
137
138static void WIDGETGROUP_node_transform_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
139{
140 wmGizmoWrapper *wwrapper = MEM_mallocN<wmGizmoWrapper>(__func__);
141
142 wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
143
144 RNA_enum_set(wwrapper->gizmo->ptr,
145 "transform",
147
148 gzgroup->customdata = wwrapper;
149}
150
152{
153 Main *bmain = CTX_data_main(C);
154 wmGizmo *cage = ((wmGizmoWrapper *)gzgroup->customdata)->gizmo;
155 const ARegion *region = CTX_wm_region(C);
156 /* center is always at the origin */
157 const float origin[3] = {float(region->winx / 2), float(region->winy / 2), 0.0f};
158
159 void *lock;
160 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
161 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
162
163 if (ibuf) {
164 const float2 dims = {
165 (ibuf->x > 0) ? ibuf->x : 64.0f,
166 (ibuf->y > 0) ? ibuf->y : 64.0f,
167 };
168
169 RNA_float_set_array(cage->ptr, "dimensions", dims);
170 WM_gizmo_set_matrix_location(cage, origin);
172
173 /* Need to set property here for undo. TODO: would prefer to do this in _init. */
174 SpaceNode *snode = CTX_wm_space_node(C);
175#if 0
176 PointerRNA nodeptr = RNA_pointer_create_discrete(snode->id, &RNA_SpaceNodeEditor, snode);
177 WM_gizmo_target_property_def_rna(cage, "offset", &nodeptr, "backdrop_offset", -1);
178 WM_gizmo_target_property_def_rna(cage, "scale", &nodeptr, "backdrop_zoom", -1);
179#endif
180
184 params.range_get_fn = nullptr;
185 params.user_data = snode;
187 }
188 else {
190 }
191
192 BKE_image_release_ibuf(ima, ibuf, lock);
193}
194
196{
197 gzgt->name = "Backdrop Transform Widget";
198 gzgt->idname = "NODE_GGT_backdrop_transform";
199
201
206}
207
209
210/* -------------------------------------------------------------------- */
213
228
230{
232 bbox_group->update_data.context, &bbox_group->update_data.ptr, bbox_group->update_data.prop);
233}
234
235static void node_input_to_rect(const bNode *node,
236 const float2 &dims,
237 const float2 offset,
238 rctf *r_rect)
239{
240
241 const bNodeSocket *x_input = bke::node_find_socket(*node, SOCK_IN, "X");
242 PointerRNA x_input_rna_pointer = RNA_pointer_create_discrete(
243 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(x_input));
244 const float xmin = float(RNA_int_get(&x_input_rna_pointer, "default_value"));
245
246 const bNodeSocket *y_input = bke::node_find_socket(*node, SOCK_IN, "Y");
247 PointerRNA y_input_rna_pointer = RNA_pointer_create_discrete(
248 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(y_input));
249 const float ymin = float(RNA_int_get(&y_input_rna_pointer, "default_value"));
250
251 const bNodeSocket *width_input = bke::node_find_socket(*node, SOCK_IN, "Width");
252 PointerRNA width_input_rna_pointer = RNA_pointer_create_discrete(
253 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(width_input));
254 const float width = float(RNA_int_get(&width_input_rna_pointer, "default_value"));
255
256 const bNodeSocket *height_input = bke::node_find_socket(*node, SOCK_IN, "Height");
257 PointerRNA height_input_rna_pointer = RNA_pointer_create_discrete(
258 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(height_input));
259 const float height = float(RNA_int_get(&height_input_rna_pointer, "default_value"));
260
261 r_rect->xmin = (xmin + offset.x) / dims.x;
262 r_rect->xmax = (xmin + width + offset.x) / dims.x;
263 r_rect->ymin = (ymin + offset.y) / dims.y;
264 r_rect->ymax = (ymin + height + offset.y) / dims.y;
265}
266
267static void node_input_from_rect(bNode *node,
268 const rctf *rect,
269 const float2 &dims,
270 const float2 &offset)
271{
272 bNodeSocket *x_input = bke::node_find_socket(*node, SOCK_IN, "X");
273 PointerRNA x_input_rna_pointer = RNA_pointer_create_discrete(
274 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(x_input));
275
276 bNodeSocket *y_input = bke::node_find_socket(*node, SOCK_IN, "Y");
277 PointerRNA y_input_rna_pointer = RNA_pointer_create_discrete(
278 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(y_input));
279
280 bNodeSocket *width_input = bke::node_find_socket(*node, SOCK_IN, "Width");
281 PointerRNA width_input_rna_pointer = RNA_pointer_create_discrete(
282 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(width_input));
283
284 bNodeSocket *height_input = bke::node_find_socket(*node, SOCK_IN, "Height");
285 PointerRNA height_input_rna_pointer = RNA_pointer_create_discrete(
286 nullptr, &RNA_NodeSocket, const_cast<bNodeSocket *>(height_input));
287
288 const float xmin = rect->xmin * dims.x - offset.x;
289 const float width = rect->xmax * dims.x - offset.x - xmin;
290 const float ymin = rect->ymin * dims.y - offset.y;
291 const float height = rect->ymax * dims.y - offset.y - ymin;
292
293 RNA_int_set(&x_input_rna_pointer, "default_value", int(xmin));
294 RNA_int_set(&y_input_rna_pointer, "default_value", int(ymin));
295 RNA_int_set(&width_input_rna_pointer, "default_value", int(width));
296 RNA_int_set(&height_input_rna_pointer, "default_value", int(height));
297}
298
299/* scale callbacks */
301 wmGizmoProperty *gz_prop,
302 void *value_p)
303{
304 float(*matrix)[4] = (float(*)[4])value_p;
305 BLI_assert(gz_prop->type->array_length == 16);
307 const float2 dims = crop_group->state.dims;
308 const float2 offset = crop_group->state.offset;
309 const bNode *node = (const bNode *)gz_prop->custom_func.user_data;
310
311 rctf rct;
312 node_input_to_rect(node, dims, offset, &rct);
313
314 matrix[0][0] = fabsf(BLI_rctf_size_x(&rct));
315 matrix[1][1] = fabsf(BLI_rctf_size_y(&rct));
316 matrix[3][0] = (BLI_rctf_cent_x(&rct) - 0.5f) * dims[0];
317 matrix[3][1] = (BLI_rctf_cent_y(&rct) - 0.5f) * dims[1];
318}
319
321 wmGizmoProperty *gz_prop,
322 const void *value_p)
323{
324 const float(*matrix)[4] = (const float(*)[4])value_p;
325 BLI_assert(gz_prop->type->array_length == 16);
327 const float2 dims = crop_group->state.dims;
328 const float2 offset = crop_group->state.offset;
329 bNode *node = (bNode *)gz_prop->custom_func.user_data;
330
331 rctf rct;
332 node_input_to_rect(node, dims, offset, &rct);
333 BLI_rctf_resize(&rct, fabsf(matrix[0][0]), fabsf(matrix[1][1]));
334 BLI_rctf_recenter(&rct, ((matrix[3][0]) / dims[0]) + 0.5f, ((matrix[3][1]) / dims[1]) + 0.5f);
335 rctf rct_isect{};
336 rct_isect.xmin = offset.x / dims.x;
337 rct_isect.xmax = offset.x / dims.x + 1;
338 rct_isect.ymin = offset.y;
339 rct_isect.ymax = offset.y / dims.y + 1;
340 BLI_rctf_isect(&rct_isect, &rct, &rct);
341 node_input_from_rect(node, &rct, dims, offset);
342 gizmo_node_bbox_update(crop_group);
343}
344
346{
348 return false;
349 }
350
351 SpaceNode *snode = CTX_wm_space_node(C);
352 bNode *node = bke::node_get_active(*snode->edittree);
353
354 if (!node || !node->is_type("CompositorNodeCrop")) {
355 return false;
356 }
357
358 snode->edittree->ensure_topology_cache();
360 if (!STREQ(input->name, "Image") && input->is_directly_linked()) {
361 /* Note: the Image input could be connected to a single value input, in which case the gizmo
362 * has no effect. */
363 return false;
364 }
365 else if (STREQ(input->name, "Alpha Crop") && !input->is_directly_linked()) {
366 PointerRNA input_rna_pointer = RNA_pointer_create_discrete(nullptr, &RNA_NodeSocket, input);
367 if (RNA_boolean_get(&input_rna_pointer, "default_value")) {
368 /* If Alpha Crop is not set, the image size changes depending on the input parameters,
369 * so we can't usefully edit the crop in this case. */
370 return true;
371 }
372 }
373 }
374
375 return false;
376}
377
378static void WIDGETGROUP_node_crop_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
379{
380 NodeBBoxWidgetGroup *crop_group = MEM_new<NodeBBoxWidgetGroup>(__func__);
381 crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
382
383 RNA_enum_set(crop_group->border->ptr,
384 "transform",
386
387 gzgroup->customdata = crop_group;
388 gzgroup->customdata_free = [](void *customdata) {
389 MEM_delete(static_cast<NodeBBoxWidgetGroup *>(customdata));
390 };
391}
392
394{
395 ARegion *region = CTX_wm_region(C);
396 wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first;
397
398 SpaceNode *snode = CTX_wm_space_node(C);
399
400 node_gizmo_calc_matrix_space(snode, region, gz->matrix_space);
401}
402
404{
405 Main *bmain = CTX_data_main(C);
406 SpaceNode *snode = CTX_wm_space_node(C);
407
408 NodeBBoxWidgetGroup *crop_group = (NodeBBoxWidgetGroup *)gzgroup->customdata;
409 wmGizmo *gz = crop_group->border;
410
411 void *lock;
412 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
413 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
414
415 if (ibuf) {
416 crop_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
417 crop_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f;
418 copy_v2_v2(crop_group->state.offset, ima->runtime->backdrop_offset);
419
420 RNA_float_set_array(gz->ptr, "dimensions", crop_group->state.dims);
422
423 bNode *node = bke::node_get_active(*snode->edittree);
424
425 crop_group->update_data.context = (bContext *)C;
427 (ID *)snode->edittree, &RNA_CompositorNodeCrop, node);
428 crop_group->update_data.prop = RNA_struct_find_property(&crop_group->update_data.ptr,
429 "relative");
430
434 params.range_get_fn = nullptr;
435 params.user_data = node;
437 }
438 else {
440 }
441
442 BKE_image_release_ibuf(ima, ibuf, lock);
443}
444
446{
447 gzgt->name = "Backdrop Crop Widget";
448 gzgt->idname = "NODE_GGT_backdrop_crop";
449
451
457}
458
460
461/* -------------------------------------------------------------------- */
464
466 wmGizmoProperty *gz_prop,
467 void *value_p)
468{
469 float(*matrix)[4] = (float(*)[4])value_p;
470 BLI_assert(gz_prop->type->array_length == 16);
472 const float2 dims = mask_group->state.dims;
473 const float2 offset = mask_group->state.offset;
474 const bNode *node = (const bNode *)gz_prop->custom_func.user_data;
475 const float aspect = dims.x / dims.y;
476
477 float loc[3], rot[3][3], size[3];
478 mat4_to_loc_rot_size(loc, rot, size, matrix);
479
480 const bNodeSocket *rotation_input = bke::node_find_socket(*node, SOCK_IN, "Rotation");
481 const float rotation = rotation_input->default_value_typed<bNodeSocketValueFloat>()->value;
482 axis_angle_to_mat3_single(rot, 'Z', rotation);
483
484 const bNodeSocket *position_input = bke::node_find_socket(*node, SOCK_IN, "Position");
485 const float2 position = position_input->default_value_typed<bNodeSocketValueVector>()->value;
486 loc[0] = (position.x - 0.5) * dims.x + offset.x;
487 loc[1] = (position.y - 0.5) * dims.y + offset.y;
488 loc[2] = 0;
489
490 const bNodeSocket *size_input = bke::node_find_socket(*node, SOCK_IN, "Size");
491 const float2 size_value = size_input->default_value_typed<bNodeSocketValueVector>()->value;
492 size[0] = size_value.x;
493 size[1] = size_value.y * aspect;
494 size[2] = 1;
495
496 loc_rot_size_to_mat4(matrix, loc, rot, size);
497}
498
500 wmGizmoProperty *gz_prop,
501 const void *value_p)
502{
503 const float(*matrix)[4] = (const float(*)[4])value_p;
504 BLI_assert(gz_prop->type->array_length == 16);
506 const float2 dims = mask_group->state.dims;
507 const float2 offset = mask_group->state.offset;
508 bNode *node = (bNode *)gz_prop->custom_func.user_data;
509
510 bNodeSocket *position_input = bke::node_find_socket(*node, SOCK_IN, "Position");
511 const float2 position = position_input->default_value_typed<bNodeSocketValueVector>()->value;
512
513 bNodeSocket *size_input = bke::node_find_socket(*node, SOCK_IN, "Size");
514 const float2 size_value = size_input->default_value_typed<bNodeSocketValueVector>()->value;
515
516 const float aspect = dims.x / dims.y;
517 rctf rct;
518 rct.xmin = position.x - size_value.x / 2;
519 rct.xmax = position.x + size_value.x / 2;
520 rct.ymin = position.y - size_value.y / 2;
521 rct.ymax = position.y + size_value.y / 2;
522
523 float loc[3];
524 float rot[3][3];
525 float size[3];
526 mat4_to_loc_rot_size(loc, rot, size, matrix);
527
528 float eul[3];
529
530 /* Rotation can't be extracted from matrix when the gizmo width or height is zero. */
531 if (size[0] != 0 and size[1] != 0) {
532 mat4_to_eul(eul, matrix);
533 bNodeSocket *rotation_input = bke::node_find_socket(*node, SOCK_IN, "Rotation");
534 rotation_input->default_value_typed<bNodeSocketValueFloat>()->value = eul[2];
535 }
536
537 BLI_rctf_resize(&rct, fabsf(size[0]), fabsf(size[1]) / aspect);
539 &rct, ((loc[0] - offset.x) / dims.x) + 0.5, ((loc[1] - offset.y) / dims.y) + 0.5);
540
541 size_input->default_value_typed<bNodeSocketValueVector>()->value[0] = size[0];
542 size_input->default_value_typed<bNodeSocketValueVector>()->value[1] = size[1] / aspect;
543 position_input->default_value_typed<bNodeSocketValueVector>()->value[0] = rct.xmin +
544 size_value.x / 2;
545 position_input->default_value_typed<bNodeSocketValueVector>()->value[1] = rct.ymin +
546 size_value.y / 2;
547
548 gizmo_node_bbox_update(mask_group);
549}
550
552{
554 return false;
555 }
556
557 SpaceNode *snode = CTX_wm_space_node(C);
558 bNode *node = bke::node_get_active(*snode->edittree);
559
560 if (node && node->is_type("CompositorNodeBoxMask")) {
561 snode->edittree->ensure_topology_cache();
563 if (STR_ELEM(input->name, "Position", "Size", "Rotation") && input->is_directly_linked()) {
564 return false;
565 }
566 }
567 return true;
568 }
569
570 return false;
571}
572
573static void WIDGETGROUP_node_box_mask_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
574{
575 NodeBBoxWidgetGroup *mask_group = MEM_new<NodeBBoxWidgetGroup>(__func__);
576 mask_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
577
578 RNA_enum_set(mask_group->border->ptr,
579 "transform",
582
583 RNA_enum_set(mask_group->border->ptr,
584 "draw_options",
587
588 gzgroup->customdata = mask_group;
589 gzgroup->customdata_free = [](void *customdata) {
590 MEM_delete(static_cast<NodeBBoxWidgetGroup *>(customdata));
591 };
592}
593
595{
596 ARegion *region = CTX_wm_region(C);
597 wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first;
598
599 SpaceNode *snode = CTX_wm_space_node(C);
600
601 node_gizmo_calc_matrix_space(snode, region, gz->matrix_space);
602}
603
605{
606 Main *bmain = CTX_data_main(C);
607 NodeBBoxWidgetGroup *mask_group = (NodeBBoxWidgetGroup *)gzgroup->customdata;
608 wmGizmo *gz = mask_group->border;
609
610 void *lock;
611 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Render Result");
612 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
613
614 if (ibuf) {
615 mask_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
616 mask_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f;
617 copy_v2_v2(mask_group->state.offset, ima->runtime->backdrop_offset);
618
619 RNA_float_set_array(gz->ptr, "dimensions", mask_group->state.dims);
621
622 SpaceNode *snode = CTX_wm_space_node(C);
623 bNode *node = bke::node_get_active(*snode->edittree);
624
625 mask_group->update_data.context = (bContext *)C;
627 (ID *)snode->edittree, &RNA_CompositorNodeCrop, node);
628 mask_group->update_data.prop = RNA_struct_find_property(&mask_group->update_data.ptr, "x");
629
633 params.range_get_fn = nullptr;
634 params.user_data = node;
636 }
637 else {
639 }
640
641 BKE_image_release_ibuf(ima, ibuf, lock);
642}
643
645{
646 gzgt->name = "Backdrop Box Mask Widget";
647 gzgt->idname = "NODE_GGT_backdrop_box_mask";
648
650
656}
657
659
660/* -------------------------------------------------------------------- */
663
665{
667 return false;
668 }
669
670 SpaceNode *snode = CTX_wm_space_node(C);
671 bNode *node = bke::node_get_active(*snode->edittree);
672
673 if (node && node->is_type("CompositorNodeEllipseMask")) {
674 snode->edittree->ensure_topology_cache();
676 if (STR_ELEM(input->name, "Position", "Size", "Rotation") && input->is_directly_linked()) {
677 return false;
678 }
679 }
680 return true;
681 }
682
683 return false;
684}
685
687{
688 NodeBBoxWidgetGroup *mask_group = MEM_new<NodeBBoxWidgetGroup>(__func__);
689 mask_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
690
691 RNA_enum_set(mask_group->border->ptr,
692 "transform",
695 RNA_enum_set(mask_group->border->ptr, "draw_style", ED_GIZMO_CAGE2D_STYLE_CIRCLE);
696 RNA_enum_set(mask_group->border->ptr,
697 "draw_options",
700
701 gzgroup->customdata = mask_group;
702 gzgroup->customdata_free = [](void *customdata) {
703 MEM_delete(static_cast<NodeBBoxWidgetGroup *>(customdata));
704 };
705}
706
708{
709 gzgt->name = "Backdrop Ellipse Mask Widget";
710 gzgt->idname = "NODE_GGT_backdrop_ellipse_mask";
711
713
719}
720
722
723/* -------------------------------------------------------------------- */
726
735
737{
739 return false;
740 }
741
742 SpaceNode *snode = CTX_wm_space_node(C);
743 bNode *node = bke::node_get_active(*snode->edittree);
744
745 if (node && node->is_type("CompositorNodeSunBeams")) {
746 snode->edittree->ensure_topology_cache();
748 if (STR_ELEM(input->name, "Source") && input->is_directly_linked()) {
749 return false;
750 }
751 }
752 return true;
753 }
754
755 return false;
756}
757
758static void WIDGETGROUP_node_sbeam_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
759{
761
762 sbeam_group->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, nullptr);
763 wmGizmo *gz = sbeam_group->gizmo;
764
766
767 gz->scale_basis = 0.05f / 75.0f;
768
769 gzgroup->customdata = sbeam_group;
770}
771
773{
775 ARegion *region = CTX_wm_region(C);
776 wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first;
777
778 SpaceNode *snode = CTX_wm_space_node(C);
779
781 snode, region, sbeam_group->state.dims, sbeam_group->state.offset, gz->matrix_space);
782}
783
785{
786 Main *bmain = CTX_data_main(C);
788 wmGizmo *gz = sbeam_group->gizmo;
789
790 void *lock;
791 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
792 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
793
794 if (ibuf) {
795 sbeam_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
796 sbeam_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f;
797 copy_v2_v2(sbeam_group->state.offset, ima->runtime->backdrop_offset);
798
799 SpaceNode *snode = CTX_wm_space_node(C);
800 bNode *node = bke::node_get_active(*snode->edittree);
801
802 /* Need to set property here for undo. TODO: would prefer to do this in _init. */
803 bNodeSocket *source_input = bke::node_find_socket(*node, SOCK_IN, "Source");
805 reinterpret_cast<ID *>(snode->edittree), &RNA_NodeSocket, source_input);
806 WM_gizmo_target_property_def_rna(gz, "offset", &socket_pointer, "default_value", -1);
807
809 }
810 else {
812 }
813
814 BKE_image_release_ibuf(ima, ibuf, lock);
815}
816
830
832
833/* -------------------------------------------------------------------- */
836
845
847{
849 return false;
850 }
851
852 SpaceNode *snode = CTX_wm_space_node(C);
853 bNode *node = bke::node_get_active(*snode->edittree);
854
855 if (node && node->is_type("CompositorNodeCornerPin")) {
856 return true;
857 }
858
859 return false;
860}
861
862static void WIDGETGROUP_node_corner_pin_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
863{
865 const wmGizmoType *gzt_move_3d = WM_gizmotype_find("GIZMO_GT_move_3d", false);
866
867 for (int i = 0; i < 4; i++) {
868 cpin_group->gizmos[i] = WM_gizmo_new_ptr(gzt_move_3d, gzgroup, nullptr);
869 wmGizmo *gz = cpin_group->gizmos[i];
870
872
873 gz->scale_basis = 0.05f / 75.0;
874 }
875
876 gzgroup->customdata = cpin_group;
877}
878
880{
882 ARegion *region = CTX_wm_region(C);
883
884 SpaceNode *snode = CTX_wm_space_node(C);
885
886 float matrix_space[4][4];
888 snode, region, cpin_group->state.dims, cpin_group->state.offset, matrix_space);
889
890 for (int i = 0; i < 4; i++) {
891 wmGizmo *gz = cpin_group->gizmos[i];
892 copy_m4_m4(gz->matrix_space, matrix_space);
893 }
894}
895
897{
898 Main *bmain = CTX_data_main(C);
900
901 void *lock;
902 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
903 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
904
905 if (ibuf) {
906 cpin_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
907 cpin_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f;
908 copy_v2_v2(cpin_group->state.offset, ima->runtime->backdrop_offset);
909
910 SpaceNode *snode = CTX_wm_space_node(C);
911 bNode *node = bke::node_get_active(*snode->edittree);
912
913 /* need to set property here for undo. TODO: would prefer to do this in _init. */
914 int i = 0;
915 for (bNodeSocket *sock = (bNodeSocket *)node->inputs.first; sock && i < 4; sock = sock->next) {
916 if (sock->type == SOCK_VECTOR) {
917 wmGizmo *gz = cpin_group->gizmos[i++];
918
920 (ID *)snode->edittree, &RNA_NodeSocket, sock);
921 WM_gizmo_target_property_def_rna(gz, "offset", &sockptr, "default_value", -1);
922
924 }
925 }
926 }
927 else {
928 for (int i = 0; i < 4; i++) {
929 wmGizmo *gz = cpin_group->gizmos[i];
931 }
932 }
933
934 BKE_image_release_ibuf(ima, ibuf, lock);
935}
936
950
952
953/* -------------------------------------------------------------------- */
956
958{
960 return false;
961 }
962
963 SpaceNode *snode = CTX_wm_space_node(C);
964 bNode *node = bke::node_get_active(*snode->edittree);
965
966 if (node && node->is_type("CompositorNodeSplit")) {
967 snode->edittree->ensure_topology_cache();
969 if (STR_ELEM(input->name, "Factor") && input->is_directly_linked()) {
970 return false;
971 }
972 }
973 return true;
974 }
975
976 return false;
977}
978
979static void WIDGETGROUP_node_split_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
980{
981 NodeBBoxWidgetGroup *split_group = MEM_new<NodeBBoxWidgetGroup>(__func__);
982 split_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr);
983
984 RNA_enum_set(split_group->border->ptr, "transform", ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE);
985 RNA_enum_set(split_group->border->ptr, "draw_options", ED_GIZMO_CAGE_DRAW_FLAG_NOP);
986
987 gzgroup->customdata = split_group;
988 gzgroup->customdata_free = [](void *customdata) {
989 MEM_delete(static_cast<NodeBBoxWidgetGroup *>(customdata));
990 };
991}
992
994 wmGizmoProperty *gz_prop,
995 void *value_p)
996{
997 float(*matrix)[4] = reinterpret_cast<float(*)[4]>(value_p);
998 BLI_assert(gz_prop->type->array_length == 16);
1000 const float2 dims = split_group->state.dims;
1001 const float2 offset = split_group->state.offset;
1002 const bNode *node = (const bNode *)gz_prop->custom_func.user_data;
1003
1004 float loc[3], rot[3][3], size[3];
1005 mat4_to_loc_rot_size(loc, rot, size, matrix);
1006
1007 const bNodeSocket *factor_input = bke::node_find_socket(*node, SOCK_IN, "Factor");
1008 const float fac = factor_input->default_value_typed<bNodeSocketValueFloat>()->value;
1009
1010 CMPNodeSplitAxis axis = static_cast<CMPNodeSplitAxis>(node->custom2);
1011 if (axis == CMP_NODE_SPLIT_VERTICAL) {
1012 matrix[3][0] = offset.x;
1013 matrix[3][1] = (fac - 0.5f) * dims.y + offset.y;
1014
1015 matrix[0][0] = 1.0f;
1016 /* Set non zero scale to silence warning "Gizmo has matrix that could not be inverted". */
1017 matrix[1][1] = std::numeric_limits<float>::epsilon();
1018 }
1019 else if (axis == CMP_NODE_SPLIT_HORIZONTAL) {
1020 matrix[3][0] = (fac - 0.5f) * dims.x + offset.x;
1021 matrix[3][1] = offset.y;
1022
1023 matrix[0][0] = std::numeric_limits<float>::epsilon();
1024 matrix[1][1] = 1.0f;
1025 }
1026}
1027
1029 wmGizmoProperty *gz_prop,
1030 const void *value_p)
1031{
1032 const float(*matrix)[4] = reinterpret_cast<const float(*)[4]>(value_p);
1033 BLI_assert(gz_prop->type->array_length == 16);
1034 NodeBBoxWidgetGroup *split_group = reinterpret_cast<NodeBBoxWidgetGroup *>(
1036 const float2 dims = split_group->state.dims;
1037 const float2 offset = split_group->state.offset;
1038 bNode *node = reinterpret_cast<bNode *>(gz_prop->custom_func.user_data);
1039
1040 bNodeSocket *factor_input = bke::node_find_socket(*node, SOCK_IN, "Factor");
1041
1042 CMPNodeSplitAxis axis = static_cast<CMPNodeSplitAxis>(node->custom2);
1043 if (axis == CMPNodeSplitAxis::CMP_NODE_SPLIT_VERTICAL) {
1044 float fac = (matrix[3][1] - offset.y) / dims.y + 0.5f;
1045 /* Prevent dragging the gizmo outside the image. */
1046 fac = math::clamp(fac, 0.0f, 1.0f);
1047 factor_input->default_value_typed<bNodeSocketValueFloat>()->value = fac;
1048 }
1049 else if (axis == CMP_NODE_SPLIT_HORIZONTAL) {
1050 float fac = (matrix[3][0] - offset.x) / dims.x + 0.5f;
1051 fac = math::clamp(fac, 0.0f, 1.0f);
1052 factor_input->default_value_typed<bNodeSocketValueFloat>()->value = fac;
1053 }
1054
1055 gizmo_node_bbox_update(split_group);
1056}
1057
1059{
1060 Main *bmain = CTX_data_main(C);
1061 NodeBBoxWidgetGroup *split_group = reinterpret_cast<NodeBBoxWidgetGroup *>(gzgroup->customdata);
1062 wmGizmo *gz = split_group->border;
1063
1064 void *lock;
1065 Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Render Result");
1066 ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
1067
1068 if (ibuf) {
1069 split_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f;
1070 split_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f;
1071 copy_v2_v2(split_group->state.offset, ima->runtime->backdrop_offset);
1072
1073 RNA_float_set_array(gz->ptr, "dimensions", split_group->state.dims);
1075
1076 SpaceNode *snode = CTX_wm_space_node(C);
1077 bNode *node = bke::node_get_active(*snode->edittree);
1078
1079 split_group->update_data.context = (bContext *)C;
1081 reinterpret_cast<ID *>(snode->edittree), &RNA_CompositorNodeSplit, node);
1082 split_group->update_data.prop = RNA_struct_find_property(&split_group->update_data.ptr,
1083 "axis");
1084
1088 params.range_get_fn = nullptr;
1089 params.user_data = node;
1091 }
1092 else {
1094 }
1095
1096 BKE_image_release_ibuf(ima, ibuf, lock);
1097}
1098
1100{
1101 gzgt->name = "Split Widget";
1102 gzgt->idname = "NODE_GGT_backdrop_split";
1103
1105
1111}
1112
1114
1115} // 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:656
#define STREQ(a, b)
@ IMA_TYPE_COMPOSITE
@ NTREE_COMPOSIT
CMPNodeSplitAxis
@ CMP_NODE_SPLIT_VERTICAL
@ CMP_NODE_SPLIT_HORIZONTAL
@ SOCK_IN
@ SOCK_VECTOR
@ SNODE_BACKDRAW
@ SNODE_GIZMO_HIDE_ACTIVE_NODE
@ SNODE_GIZMO_HIDE
@ 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
@ ED_GIZMO_CAGE2D_STYLE_CIRCLE
@ ED_GIZMO_CAGE_DRAW_FLAG_CORNER_HANDLES
@ ED_GIZMO_CAGE_DRAW_FLAG_XFORM_CENTER_HANDLE
@ ED_GIZMO_CAGE_DRAW_FLAG_NOP
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
#define fabsf(x)
#define rot(x, k)
#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:2864
bNode * node_get_active(bNodeTree &ntree)
Definition node.cc:4957
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 WIDGETGROUP_node_sbeam_setup(const bContext *, wmGizmoGroup *gzgroup)
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 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_sbeam_poll(const bContext *C, wmGizmoGroupType *)
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 gizmo_node_box_mask_prop_matrix_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p)
static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
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 WIDGETGROUP_node_sbeam_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo_node_crop_prop_matrix_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p)
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)
Definition node_gizmo.cc:97
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)
void NODE_GGT_backdrop_sun_beams(wmGizmoGroupType *gzgt)
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_crop_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
static bool WIDGETGROUP_node_crop_poll(const bContext *C, wmGizmoGroupType *)
static void WIDGETGROUP_bbox_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
T clamp(const T &a, const T &min, const T &max)
VecBase< float, 2 > float2
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:404
ImageRuntimeHandle * runtime
void * first
struct bNodeTree * edittree
struct ID * id
ListBase inputs
int16_t custom2
struct blender::ed::space_node::NodeBBoxWidgetGroup::@043357010263144072144151112310225073340321215155 update_data
struct blender::ed::space_node::NodeBBoxWidgetGroup::@076147345165247363224163157074236037167333371212 state
struct blender::ed::space_node::NodeCornerPinWidgetGroup::@201211300133160234133043042152107357341244174107 state
struct blender::ed::space_node::NodeSunBeamsWidgetGroup::@046023233113050326355046145242153071164256220276 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 *)
struct wmGizmoProperty::@046017364211037167053011312355256221126135017103 custom_func
const wmGizmoPropertyType * type
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:286
void WM_gizmo_set_flag(wmGizmo *gz, const int flag, const bool enable)
Definition wm_gizmo.cc:306
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)