Blender V4.3
transform_mode_bend.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 <cstdlib>
10
11#include "MEM_guardedalloc.h"
12
14
15#include "BLI_math_geom.h"
16#include "BLI_math_matrix.h"
17#include "BLI_math_rotation.h"
18#include "BLI_math_vector.h"
19#include "BLI_string.h"
20#include "BLI_task.h"
21
22#include "BKE_unit.hh"
23
24#include "ED_screen.hh"
25
26#include "WM_api.hh"
27#include "WM_types.hh"
28
29#include "UI_interface.hh"
30
31#include "BLT_translation.hh"
32
33#include "transform.hh"
34#include "transform_convert.hh"
35#include "transform_snap.hh"
36
37#include "transform_mode.hh"
38
39/* -------------------------------------------------------------------- */
47 /* All values are in global space. */
48 float warp_sta[3];
49 float warp_end[3];
50
51 float warp_nor[3];
52 float warp_tan[3];
53
54 /* For applying the mouse distance. */
56};
57
60/* -------------------------------------------------------------------- */
80
81static void transdata_elem_bend(const TransInfo *t,
82 const TransDataContainer *tc,
83 TransData *td,
84 float angle,
85 const BendCustomData *bend_data,
86 const float warp_sta_local[3],
87 const float[3] /*warp_end_local*/,
88 const float warp_end_radius_local[3],
89 const float pivot_local[3],
90
91 bool is_clamp)
92{
93 if (UNLIKELY(angle == 0.0f)) {
94 copy_v3_v3(td->loc, td->iloc);
95 return;
96 }
97
98 float vec[3];
99 float mat[3][3];
100 float delta[3];
101 float fac, fac_scaled;
102
103 copy_v3_v3(vec, td->iloc);
104 mul_m3_v3(td->mtx, vec);
105
106 fac = line_point_factor_v3(vec, warp_sta_local, warp_end_radius_local);
107 if (is_clamp) {
108 CLAMP(fac, 0.0f, 1.0f);
109 }
110
111 if (t->options & CTX_GPENCIL_STROKES) {
112 /* Grease pencil multi-frame falloff. */
113 bGPDstroke *gps = (bGPDstroke *)td->extra;
114 if (gps != nullptr) {
115 fac_scaled = fac * td->factor * gps->runtime.multi_frame_falloff;
116 }
117 else {
118 fac_scaled = fac * td->factor;
119 }
120 }
121 else {
122 fac_scaled = fac * td->factor;
123 }
124
125 axis_angle_normalized_to_mat3(mat, bend_data->warp_nor, angle * fac_scaled);
126 interp_v3_v3v3(delta, warp_sta_local, warp_end_radius_local, fac_scaled);
127 sub_v3_v3(delta, warp_sta_local);
128
129 /* Delta is subtracted, rotation adds back this offset. */
130 sub_v3_v3(vec, delta);
131
132 sub_v3_v3(vec, pivot_local);
133 mul_m3_v3(mat, vec);
134 add_v3_v3(vec, pivot_local);
135
136 mul_m3_v3(td->smtx, vec);
137
138 /* Rotation. */
139 if ((t->flag & T_POINTS) == 0) {
141 }
142
143 /* Location. */
144 copy_v3_v3(td->loc, vec);
145}
146
147static void transdata_elem_bend_fn(void *__restrict iter_data_v,
148 const int iter,
149 const TaskParallelTLS *__restrict /*tls*/)
150{
151 TransDataArgs_Bend *data = static_cast<TransDataArgs_Bend *>(iter_data_v);
152 TransData *td = &data->tc->data[iter];
153 if (td->flag & TD_SKIP) {
154 return;
155 }
156 transdata_elem_bend(data->t,
157 data->tc,
158 td,
159 data->angle,
160 &data->bend_data,
161 data->warp_sta_local,
162 data->warp_end_local,
163 data->warp_end_radius_local,
164 data->pivot_local,
165 data->is_clamp);
166}
167
170/* -------------------------------------------------------------------- */
174static eRedrawFlag handleEventBend(TransInfo * /*t*/, const wmEvent *event)
175{
177
178 if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
179 status = TREDRAW_HARD;
180 }
181
182 return status;
183}
184
185static void Bend(TransInfo *t)
186{
187 float pivot_global[3];
188 float warp_end_radius_global[3];
189 int i;
190 char str[UI_MAX_DRAW_STR];
191 const BendCustomData *bend_data = static_cast<const BendCustomData *>(t->custom.mode.data);
192 const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0;
193
194 union {
195 struct {
196 float angle, scale;
197 };
198 float vector[2];
199 } values;
200
201 /* Amount of radians for bend. */
202 copy_v2_v2(values.vector, t->values);
203
204#if 0
205 snapGrid(t, angle_rad);
206#else
207 /* Hrmf, snapping radius is using 'angle' steps, need to convert to something else
208 * this isn't essential but nicer to give reasonable snapping values for radius. */
210 const float radius_snap = 0.1f;
211 const float snap_hack = (t->snap[0] * bend_data->warp_init_dist) / radius_snap;
212 values.scale *= snap_hack;
213 transform_snap_increment(t, values.vector);
214 values.scale /= snap_hack;
215 }
216#endif
217
218 if (applyNumInput(&t->num, values.vector)) {
219 values.scale = values.scale / bend_data->warp_init_dist;
220 }
221
222 copy_v2_v2(t->values_final, values.vector);
223
224 /* Header print for NumInput. */
225 if (hasNumInput(&t->num)) {
226 char c[NUM_STR_REP_LEN * 2];
227
228 outputNumInput(&(t->num), c, &t->scene->unit);
229
231 IFACE_("Bend Angle: %s, Radius: %s, Alt: Clamp %s"),
232 &c[0],
233 &c[NUM_STR_REP_LEN],
234 WM_bool_as_string(is_clamp));
235 }
236 else {
237 /* Default header print. */
239 IFACE_("Bend Angle: %.3f, Radius: %.4f, Alt: Clamp %s"),
240 RAD2DEGF(values.angle),
241 values.scale * bend_data->warp_init_dist,
242 WM_bool_as_string(is_clamp));
243 }
244
245 values.angle *= -1.0f;
246 values.scale *= bend_data->warp_init_dist;
247
248 /* Calculate `data->warp_end` from `data->warp_end_init`. */
249 copy_v3_v3(warp_end_radius_global, bend_data->warp_end);
250 dist_ensure_v3_v3fl(warp_end_radius_global, bend_data->warp_sta, values.scale);
251 /* Done. */
252
253 /* Calculate pivot. */
254 copy_v3_v3(pivot_global, bend_data->warp_sta);
255 if (values.angle > 0.0f) {
256 madd_v3_v3fl(pivot_global,
257 bend_data->warp_tan,
258 -values.scale * shell_angle_to_dist(float(M_PI_2) - values.angle));
259 }
260 else {
261 madd_v3_v3fl(pivot_global,
262 bend_data->warp_tan,
263 +values.scale * shell_angle_to_dist(float(M_PI_2) + values.angle));
264 }
265
266 /* TODO(@ideasman42): xform, compensate object center. */
268
269 float warp_sta_local[3];
270 float warp_end_local[3];
271 float warp_end_radius_local[3];
272 float pivot_local[3];
273
274 if (tc->use_local_mat) {
275 sub_v3_v3v3(warp_sta_local, bend_data->warp_sta, tc->mat[3]);
276 sub_v3_v3v3(warp_end_local, bend_data->warp_end, tc->mat[3]);
277 sub_v3_v3v3(warp_end_radius_local, warp_end_radius_global, tc->mat[3]);
278 sub_v3_v3v3(pivot_local, pivot_global, tc->mat[3]);
279 }
280 else {
281 copy_v3_v3(warp_sta_local, bend_data->warp_sta);
282 copy_v3_v3(warp_end_local, bend_data->warp_end);
283 copy_v3_v3(warp_end_radius_local, warp_end_radius_global);
284 copy_v3_v3(pivot_local, pivot_global);
285 }
286
287 if (tc->data_len < TRANSDATA_THREAD_LIMIT) {
288 TransData *td = tc->data;
289
290 for (i = 0; i < tc->data_len; i++, td++) {
291 if (td->flag & TD_SKIP) {
292 continue;
293 }
295 tc,
296 td,
297 values.angle,
298 bend_data,
299 warp_sta_local,
300 warp_end_local,
301 warp_end_radius_local,
302 pivot_local,
303 is_clamp);
304 }
305 }
306 else {
307 TransDataArgs_Bend data{};
308 data.t = t;
309 data.tc = tc;
310 data.angle = values.angle;
311 data.bend_data = *bend_data;
312 copy_v3_v3(data.warp_sta_local, warp_sta_local);
313 copy_v3_v3(data.warp_end_local, warp_end_local);
314 copy_v3_v3(data.warp_end_radius_local, warp_end_radius_local);
315 copy_v3_v3(data.pivot_local, pivot_local);
316 data.is_clamp = is_clamp;
317 TaskParallelSettings settings;
319 BLI_task_parallel_range(0, tc->data_len, &data, transdata_elem_bend_fn, &settings);
320 }
321 }
322
323 recalc_data(t);
324
326}
327
328static void initBend(TransInfo *t, wmOperator * /*op*/)
329{
330 const float *curs;
331 float tvec[3];
333
334 t->mode = TFM_BEND;
335
337
338 t->idx_max = 1;
339 t->num.idx_max = 1;
341
342 copy_v3_fl(t->num.val_inc, t->snap[0]);
343 t->num.unit_sys = t->scene->unit.system;
347
348 // copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
349 if ((t->flag & T_OVERRIDE_CENTER) == 0) {
351 }
353
354 data = static_cast<BendCustomData *>(MEM_callocN(sizeof(*data), __func__));
355
356 curs = t->scene->cursor.location;
357 copy_v3_v3(data->warp_sta, curs);
359 (View3D *)t->area->spacedata.first, t->region, curs, t->mval, data->warp_end);
360
361 copy_v3_v3(data->warp_nor, t->viewinv[2]);
362 normalize_v3(data->warp_nor);
363
364 /* Tangent. */
365 sub_v3_v3v3(tvec, data->warp_end, data->warp_sta);
366 cross_v3_v3v3(data->warp_tan, tvec, data->warp_nor);
367 normalize_v3(data->warp_tan);
368
369 data->warp_init_dist = len_v3v3(data->warp_end, data->warp_sta);
370
371 t->custom.mode.data = data;
372 t->custom.mode.use_free = true;
373}
374
378 /*flags*/ T_NO_CONSTRAINT,
379 /*init_fn*/ initBend,
380 /*transform_fn*/ Bend,
381 /*transform_matrix_fn*/ nullptr,
382 /*handle_event_fn*/ handleEventBend,
383 /*snap_distance_fn*/ nullptr,
384 /*snap_apply_fn*/ nullptr,
385 /*draw_fn*/ nullptr,
386};
@ B_UNIT_LENGTH
Definition BKE_unit.hh:107
@ B_UNIT_ROTATION
Definition BKE_unit.hh:111
#define M_PI_2
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
MINLINE float shell_angle_to_dist(float angle)
void mul_m3_v3(const float M[3][3], float r[3])
void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], float angle)
#define RAD2DEGF(_rad)
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[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])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition math_vector.c:36
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], float dist)
MINLINE float normalize_v3(float n[3])
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:230
#define CLAMP(a, b, c)
#define UNLIKELY(x)
#define IFACE_(msgid)
@ USER_UNIT_ROT_RADIANS
@ SCE_SNAP_TO_INCREMENT
@ V3D_AROUND_LOCAL_ORIGINS
#define NUM_STR_REP_LEN
void outputNumInput(NumInput *n, char *str, const UnitSettings *unit_settings)
Definition numinput.cc:88
bool applyNumInput(NumInput *n, float *vec)
Definition numinput.cc:190
bool hasNumInput(const NumInput *n)
Definition numinput.cc:171
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:803
@ TFM_BEND
void ED_view3d_win_to_3d(const View3D *v3d, const ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
Read Guarded memory(de)allocation.
#define UI_MAX_DRAW_STR
@ KM_PRESS
Definition WM_types.hh:284
#define str(s)
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void * first
short idx_max
float val_inc[NUM_MAX_ELEMENTS]
int unit_type[NUM_MAX_ELEMENTS]
bool unit_use_radians
View3DCursor cursor
struct UnitSettings unit
ListBase spacedata
TransCustomData mode
Definition transform.hh:423
unsigned int use_free
Definition transform.hh:410
const TransDataContainer * tc
float smtx[3][3]
float mtx[3][3]
eTfmMode mode
Definition transform.hh:517
float viewinv[4][4]
Definition transform.hh:575
float snap[2]
Definition transform.hh:561
float values[4]
Definition transform.hh:624
TransSnap tsnap
Definition transform.hh:537
short idx_max
Definition transform.hh:559
NumInput num
Definition transform.hh:540
TransCustomDataContainer custom
Definition transform.hh:676
Scene * scene
Definition transform.hh:654
eTFlag flag
Definition transform.hh:523
ARegion * region
Definition transform.hh:652
MouseInput mouse
Definition transform.hh:543
float values_final[4]
Definition transform.hh:632
float center_global[3]
Definition transform.hh:555
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
bGPDstroke_Runtime runtime
short val
Definition WM_types.hh:724
short type
Definition WM_types.hh:722
@ INPUT_ANGLE_SPRING
Definition transform.hh:747
@ CTX_GPENCIL_STROKES
Definition transform.hh:68
eRedrawFlag
Definition transform.hh:214
@ TREDRAW_NOTHING
Definition transform.hh:215
@ TREDRAW_HARD
Definition transform.hh:217
@ T_OVERRIDE_CENTER
Definition transform.hh:129
@ T_ALT_TRANSFORM
Definition transform.hh:126
@ T_POINTS
Definition transform.hh:93
@ T_NO_CONSTRAINT
Definition transform.hh:95
void calculateCenterCursor(TransInfo *t, float r_center[3])
void calculateCenterLocal(TransInfo *t, const float center_global[3])
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
#define FOREACH_TRANS_DATA_CONTAINER(t, th)
Definition transform.hh:854
void recalc_data(TransInfo *t)
conversion and adaptation of different datablocks to a common struct.
@ TD_SKIP
#define TRANSDATA_THREAD_LIMIT
void ElementRotation(const TransInfo *t, const TransDataContainer *tc, TransData *td, const float mat[3][3], const short around)
transform modes used by different operators.
static void initBend(TransInfo *t, wmOperator *)
TransModeInfo TransMode_bend
static eRedrawFlag handleEventBend(TransInfo *, const wmEvent *event)
static void transdata_elem_bend(const TransInfo *t, const TransDataContainer *tc, TransData *td, float angle, const BendCustomData *bend_data, const float warp_sta_local[3], const float[3], const float warp_end_radius_local[3], const float pivot_local[3], bool is_clamp)
static void Bend(TransInfo *t)
static void transdata_elem_bend_fn(void *__restrict iter_data_v, const int iter, const TaskParallelTLS *__restrict)
bool transform_snap_increment(const TransInfo *t, float *r_val)
void initSnapAngleIncrements(TransInfo *t)
@ MIDDLEMOUSE
const char * WM_bool_as_string(bool test)