Blender V4.3
transform_convert_node.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "DNA_space_types.h"
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_math_matrix.h"
14#include "BLI_math_vector.h"
15#include "BLI_math_vector.hh"
16#include "BLI_rect.h"
17
18#include "BKE_context.hh"
19#include "BKE_node.hh"
20
21#include "ED_node.hh"
22
23#include "UI_view2d.hh"
24
25#include "transform.hh"
26#include "transform_convert.hh"
27#include "transform_snap.hh"
28
29#include "WM_api.hh"
30
31namespace blender::ed::transform {
32
35
36 /* Compare if the view has changed so we can update with `transformViewUpdate`. */
38
40};
41
42/* -------------------------------------------------------------------- */
47 TransData2D &td2d,
48 bNode &node,
49 const float dpi_fac)
50{
51 /* Account for parents (nested nodes). */
52 const float2 node_offset = {node.offsetx, node.offsety};
53 float2 loc = bke::node_to_view(&node, math::round(node_offset));
54 loc *= dpi_fac;
55
56 /* Use top-left corner as the transform origin for nodes. */
57 /* Weirdo - but the node system is a mix of free 2d elements and DPI sensitive UI. */
58 td2d.loc[0] = loc.x;
59 td2d.loc[1] = loc.y;
60 td2d.loc[2] = 0.0f;
61 td2d.loc2d = td2d.loc; /* Current location. */
62
63 td.loc = td2d.loc;
64 copy_v3_v3(td.iloc, td.loc);
65 /* Use node center instead of origin (top-left corner). */
66 td.center[0] = td2d.loc[0];
67 td.center[1] = td2d.loc[1];
68 td.center[2] = 0.0f;
69
70 memset(td.axismtx, 0, sizeof(td.axismtx));
71 td.axismtx[2][2] = 1.0f;
72
73 td.ext = nullptr;
74 td.val = nullptr;
75
76 td.flag = TD_SELECTED;
77 td.dist = 0.0f;
78
79 unit_m3(td.mtx);
80 unit_m3(td.smtx);
81
82 td.extra = &node;
83}
84
85static bool is_node_parent_select(const bNode *node)
86{
87 while ((node = node->parent)) {
88 if (node->flag & NODE_SELECT) {
89 return true;
90 }
91 }
92 return false;
93}
94
95static void createTransNodeData(bContext * /*C*/, TransInfo *t)
96{
97 SpaceNode *snode = static_cast<SpaceNode *>(t->area->spacedata.first);
99 if (!node_tree) {
100 return;
101 }
102
103 /* Custom data to enable edge panning during the node transform. */
104 TransCustomDataNode *customdata = MEM_cnew<TransCustomDataNode>(__func__);
106 &customdata->edgepan_data,
113 customdata->viewrect_prev = customdata->edgepan_data.initial_rect;
114 customdata->is_new_node = t->remove_on_cancel;
115
117 *snode, *t->region, t->modifiers & MOD_NODE_ATTACH, customdata->is_new_node);
118
119 t->custom.type.data = customdata;
120 t->custom.type.use_free = true;
121
123
124 /* Nodes don't support proportional editing and probably never will. */
125 t->flag = t->flag & ~T_PROP_EDIT_ALL;
126
128 nodes.remove_if([&](bNode *node) { return is_node_parent_select(node); });
129 if (nodes.is_empty()) {
130 return;
131 }
132
133 tc->data_len = nodes.size();
134 tc->data = MEM_cnew_array<TransData>(tc->data_len, __func__);
135 tc->data_2d = MEM_cnew_array<TransData2D>(tc->data_len, __func__);
136
137 for (const int i : nodes.index_range()) {
138 create_transform_data_for_node(tc->data[i], tc->data_2d[i], *nodes[i], UI_SCALE_FAC);
139 }
140}
141
144/* -------------------------------------------------------------------- */
149{
150 if (!(transform_snap_is_active(t) &&
152 {
153 return;
154 }
155
156 float2 grid_size = t->snap_spatial;
157 if (t->modifiers & MOD_PRECISION) {
158 grid_size *= t->snap_spatial_precision;
159 }
160
161 /* Early exit on unusable grid size. */
162 if (math::is_zero(grid_size)) {
163 return;
164 }
165
167 for (const int i : IndexRange(tc->data_len)) {
168 TransData &td = tc->data[i];
169 float iloc[2], loc[2], tvec[2];
170 if (td.flag & TD_SKIP) {
171 continue;
172 }
173
174 if ((t->flag & T_PROP_EDIT) && (td.factor == 0.0f)) {
175 continue;
176 }
177
178 copy_v2_v2(iloc, td.loc);
179
180 loc[0] = roundf(iloc[0] / grid_size[0]) * grid_size[0];
181 loc[1] = roundf(iloc[1] / grid_size[1]) * grid_size[1];
182
183 sub_v2_v2v2(tvec, loc, iloc);
184 add_v2_v2(td.loc, tvec);
185 }
186 }
187}
188
190{
191 const float dpi_fac = UI_SCALE_FAC;
192 SpaceNode *snode = static_cast<SpaceNode *>(t->area->spacedata.first);
193
195
196 if (t->options & CTX_VIEW2D_EDGE_PAN) {
197 if (t->state == TRANS_CANCEL) {
199 }
200 else {
201 /* Edge panning functions expect window coordinates, mval is relative to region. */
202 const int xy[2] = {
203 t->region->winrct.xmin + int(t->mval[0]),
204 t->region->winrct.ymin + int(t->mval[1]),
205 };
207 }
208 }
209
210 float offset[2] = {0.0f, 0.0f};
211 if (t->state != TRANS_CANCEL) {
212 if (!BLI_rctf_compare(&customdata->viewrect_prev, &t->region->v2d.cur, FLT_EPSILON)) {
213 /* Additional offset due to change in view2D rect. */
214 BLI_rctf_transform_pt_v(&t->region->v2d.cur, &customdata->viewrect_prev, offset, offset);
216 customdata->viewrect_prev = t->region->v2d.cur;
217 }
218 }
219
222
223 /* Flush to 2d vector from internally used 3d vector. */
224 for (int i = 0; i < tc->data_len; i++) {
225 TransData *td = &tc->data[i];
226 TransData2D *td2d = &tc->data_2d[i];
227 bNode *node = static_cast<bNode *>(td->extra);
228
229 float2 loc;
230 add_v2_v2v2(loc, td2d->loc, offset);
231
232 /* Weirdo - but the node system is a mix of free 2d elements and DPI sensitive UI. */
233 loc /= dpi_fac;
234
235 /* Account for parents (nested nodes). */
236 const float2 node_offset = {node->offsetx, node->offsety};
237 const float2 new_node_location = loc - math::round(node_offset);
238 const float2 location = bke::node_from_view(node->parent, new_node_location);
239 node->locx = location.x;
240 node->locy = location.y;
241 }
242
243 /* Handle intersection with noodles. */
244 if (tc->data_len == 1) {
246 *snode, *t->region, t->modifiers & MOD_NODE_ATTACH, customdata->is_new_node);
247 }
248 }
249}
250
253/* -------------------------------------------------------------------- */
258{
259 Main *bmain = CTX_data_main(C);
260 SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
261 bNodeTree *ntree = snode->edittree;
262
263 const bool canceled = (t->state == TRANS_CANCEL);
264
265 if (canceled && t->remove_on_cancel) {
266 /* Remove selected nodes on cancel. */
267 if (ntree) {
268 LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
269 if (node->flag & NODE_SELECT) {
270 bke::node_remove_node(bmain, ntree, node, true);
271 }
272 }
273 ED_node_tree_propagate_change(C, bmain, ntree);
274 }
275 }
276
277 if (!canceled) {
279 if (t->modifiers & MOD_NODE_ATTACH) {
280 const TransCustomDataNode &customdata = *(TransCustomDataNode *)t->custom.type.data;
281 space_node::node_insert_on_link_flags(*bmain, *snode, customdata.is_new_node);
282 }
283 }
284
286
287 wmOperatorType *ot = WM_operatortype_find("NODE_OT_insert_offset", true);
288 BLI_assert(ot);
293}
294
297} // namespace blender::ed::transform
298
Main * CTX_data_main(const bContext *C)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void unit_m3(float m[3][3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
void BLI_rctf_transform_pt_v(const rctf *dst, const rctf *src, float xy_dst[2], const float xy_src[2])
Definition rct.c:530
bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, float limit)
@ NODE_SELECT
@ SCE_SNAP_TO_INCREMENT
@ SCE_SNAP_TO_GRID
#define UI_SCALE_FAC
void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *ntree)
Definition node_edit.cc:492
#define NODE_EDGE_PAN_OUTSIDE_PAD
Definition ED_node_c.hh:37
#define NODE_EDGE_PAN_INSIDE_PAD
Definition ED_node_c.hh:36
#define NODE_EDGE_PAN_MAX_SPEED
Definition ED_node_c.hh:39
void ED_node_post_apply_transform(bContext *C, bNodeTree *ntree)
Definition node_edit.cc:871
#define NODE_EDGE_PAN_DELAY
Definition ED_node_c.hh:40
#define NODE_EDGE_PAN_ZOOM_INFLUENCE
Definition ED_node_c.hh:41
#define NODE_EDGE_PAN_SPEED_RAMP
Definition ED_node_c.hh:38
Read Guarded memory(de)allocation.
void UI_view2d_edge_pan_cancel(bContext *C, View2DEdgePanData *vpd)
void UI_view2d_edge_pan_init(bContext *C, View2DEdgePanData *vpd, float inside_pad, float outside_pad, float speed_ramp, float max_speed, float delay, float zoom_influence)
void UI_view2d_edge_pan_apply(bContext *C, View2DEdgePanData *vpd, const int xy[2]) ATTR_NONNULL(1
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
OperationNode * node
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
float2 node_to_view(const bNode *node, float2 loc)
Definition node.cc:3089
void node_remove_node(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
Definition node.cc:3545
float2 node_from_view(const bNode *node, float2 view_loc)
Definition node.cc:3098
void node_insert_on_link_flags_set(SpaceNode &snode, const ARegion &region, bool attach_enabled, bool is_new_node)
VectorSet< bNode * > get_selected_nodes(bNodeTree &node_tree)
void node_insert_on_link_flags_clear(bNodeTree &node_tree)
void node_insert_on_link_flags(Main &bmain, SpaceNode &snode, bool is_new_node)
static void createTransNodeData(bContext *, TransInfo *t)
static void special_aftertrans_update__node(bContext *C, TransInfo *t)
static void node_snap_grid_apply(TransInfo *t)
static void flushTransNodes(TransInfo *t)
static void create_transform_data_for_node(TransData &td, TransData2D &td2d, bNode &node, const float dpi_fac)
static bool is_node_parent_select(const bNode *node)
bool is_zero(const T &a)
T round(const T &a)
void * first
ListBase spacedata
struct bNodeTree * edittree
TransCustomData type
Definition transform.hh:425
unsigned int use_free
Definition transform.hh:410
TransData * data
Definition transform.hh:445
TransData2D * data_2d
Definition transform.hh:449
float smtx[3][3]
float axismtx[3][3]
float mtx[3][3]
TransDataExtension * ext
float snap_spatial_precision
Definition transform.hh:568
float snap_spatial[3]
Definition transform.hh:563
TransSnap tsnap
Definition transform.hh:537
eTState state
Definition transform.hh:527
eTModifier modifiers
Definition transform.hh:525
TransCustomDataContainer custom
Definition transform.hh:676
bool remove_on_cancel
Definition transform.hh:645
eTFlag flag
Definition transform.hh:523
ARegion * region
Definition transform.hh:652
bContext * context
Definition transform.hh:649
blender::float2 mval
Definition transform.hh:663
eTContext options
Definition transform.hh:521
ScrArea * area
Definition transform.hh:651
eSnapMode mode
Definition transform.hh:312
ListBase nodes
int ymin
int xmin
@ CTX_VIEW2D_EDGE_PAN
Definition transform.hh:84
@ MOD_NODE_ATTACH
Definition transform.hh:166
@ MOD_PRECISION
Definition transform.hh:162
void transformViewUpdate(TransInfo *t)
@ T_PROP_EDIT
Definition transform.hh:98
@ T_2D_EDIT
Definition transform.hh:104
@ T_POINTS
Definition transform.hh:93
#define TRANS_DATA_CONTAINER_FIRST_SINGLE(t)
Definition transform.hh:851
@ TRANS_CANCEL
Definition transform.hh:210
#define FOREACH_TRANS_DATA_CONTAINER(t, th)
Definition transform.hh:854
conversion and adaptation of different datablocks to a common struct.
TransConvertTypeInfo TransConvertType_Node
@ TD_SELECTED
@ TD_SKIP
bool transform_snap_is_active(const TransInfo *t)
int xy[2]
Definition wm_draw.cc:170
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)