Blender V4.5
transform_mode_mirror.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
8
9#include <cstdlib>
10
11#include "BLI_math_bits.h"
12#include "BLI_math_matrix.h"
13#include "BLI_math_vector.h"
14#include "BLI_string.h"
15
16#include "ED_screen.hh"
17
18#include "UI_interface.hh"
19
20#include "BLT_translation.hh"
21
22#include "transform.hh"
23#include "transform_convert.hh"
24
25#include "transform_mode.hh"
26
27namespace blender::ed::transform {
28
29/* -------------------------------------------------------------------- */
32
42static void ElementMirror(TransInfo *t, TransDataContainer *tc, TransData *td, int axis, bool flip)
43{
44 if ((t->flag & T_V3D_ALIGN) == 0 && td->ext) {
45 /* Size checked needed since the 3D cursor only uses rotation fields. */
46 if (td->ext->scale) {
47 float fscale[] = {1.0, 1.0, 1.0};
48
49 if (axis >= 0) {
50 fscale[axis] = -fscale[axis];
51 }
52 if (flip) {
53 negate_v3(fscale);
54 }
55
57
58 mul_v3_v3v3(td->ext->scale, td->ext->iscale, fscale);
59
60 constraintScaleLim(t, tc, td);
61 }
62
63 float rmat[3][3];
64 if (axis >= 0) {
65 float imat[3][3];
66 mul_m3_m3m3(rmat, t->spacemtx_inv, td->axismtx);
67 rmat[axis][0] = -rmat[axis][0];
68 rmat[axis][1] = -rmat[axis][1];
69 rmat[axis][2] = -rmat[axis][2];
70 rmat[0][axis] = -rmat[0][axis];
71 rmat[1][axis] = -rmat[1][axis];
72 rmat[2][axis] = -rmat[2][axis];
73 invert_m3_m3(imat, td->axismtx);
74 mul_m3_m3m3(rmat, rmat, imat);
75 mul_m3_m3m3(rmat, t->spacemtx, rmat);
76
77 ElementRotation_ex(t, tc, td, rmat, td->center);
78
79 if (td->ext->rotAngle) {
80 *td->ext->rotAngle = -td->ext->irotAngle;
81 }
82 }
83 else {
84 unit_m3(rmat);
85 ElementRotation_ex(t, tc, td, rmat, td->center);
86
87 if (td->ext->rotAngle) {
88 *td->ext->rotAngle = td->ext->irotAngle;
89 }
90 }
91 }
92
93 if ((td->flag & TD_NO_LOC) == 0) {
94 float center[3], vec[3];
95
96 /* Local constraint shouldn't alter center. */
98 copy_v3_v3(center, td->center);
99 }
100 else if (t->options & CTX_MOVIECLIP) {
101 if (td->flag & TD_INDIVIDUAL_SCALE) {
102 copy_v3_v3(center, td->center);
103 }
104 else {
105 copy_v3_v3(center, tc->center_local);
106 }
107 }
108 else {
109 copy_v3_v3(center, tc->center_local);
110 }
111
112 /* For individual element center, Editmode need to use iloc. */
113 if (t->flag & T_POINTS) {
114 sub_v3_v3v3(vec, td->iloc, center);
115 }
116 else {
117 sub_v3_v3v3(vec, td->center, center);
118 }
119
120 if (axis >= 0) {
121 /* Always do the mirror in global space. */
122 if (t->flag & T_EDIT) {
123 mul_m3_v3(td->mtx, vec);
124 }
125 reflect_v3_v3v3(vec, vec, t->spacemtx[axis]);
126 if (t->flag & T_EDIT) {
127 mul_m3_v3(td->smtx, vec);
128 }
129 }
130 if (flip) {
131 negate_v3(vec);
132 }
133
134 add_v3_v3(vec, center);
135 if (t->flag & T_POINTS) {
136 sub_v3_v3(vec, td->iloc);
137 }
138 else {
139 sub_v3_v3(vec, td->center);
140 }
141
142 if (t->options & (CTX_OBJECT | CTX_POSE_BONE)) {
143 mul_m3_v3(td->smtx, vec);
144 }
145
147 if (td->loc) {
148 add_v3_v3v3(td->loc, td->iloc, vec);
149 }
150
151 constraintTransLim(t, tc, td);
152 }
153}
154
155static void applyMirror(TransInfo *t)
156{
157 int i;
158 char str[UI_MAX_DRAW_STR];
160
161 /* OPTIMIZATION:
162 * This still recalculates transformation on mouse move
163 * while it should only recalculate on constraint change. */
164
165 /* If an axis has been selected. */
166 if (t->con.mode & CON_APPLY) {
167 /* #special_axis is either the constraint plane normal or the constraint axis.
168 * Assuming that CON_AXIS0 < CON_AXIS1 < CON_AXIS2 and CON_AXIS2 is CON_AXIS0 << 2 */
170 int axis_bitmap = (t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2)) / CON_AXIS0;
171 int special_axis_bitmap = 0;
172 int special_axis = -1;
173 int bitmap_len = count_bits_i(axis_bitmap);
174 if (LIKELY(!ELEM(bitmap_len, 0, 3))) {
175 special_axis_bitmap = (bitmap_len == 2) ? ~axis_bitmap : axis_bitmap;
176 special_axis = bitscan_forward_i(special_axis_bitmap);
177 }
178
179 SNPRINTF(str, IFACE_("Mirror%s"), t->con.text);
180
181 if (t->options & CTX_SEQUENCER_IMAGE) {
182 if (axis_bitmap == 1) {
183 t->values_final[0] = -1;
184 t->values_final[1] = 1;
185 }
186 if (axis_bitmap == 2) {
187 t->values_final[0] = 1;
188 t->values_final[1] = -1;
189 }
190 }
191
193 TransData *td = tc->data;
194 for (i = 0; i < tc->data_len; i++, td++) {
195 if (td->flag & TD_SKIP) {
196 continue;
197 }
198
199 ElementMirror(t, tc, td, special_axis, bitmap_len >= 2);
200 }
201 }
202
203 recalc_data(t);
204
206 }
207 else {
208 if (t->options & CTX_SEQUENCER_IMAGE) {
209 t->values_final[0] = 1.0f;
210 t->values_final[1] = 1.0f;
211 }
213 TransData *td = tc->data;
214 for (i = 0; i < tc->data_len; i++, td++) {
215 if (td->flag & TD_SKIP) {
216 continue;
217 }
218
219 ElementMirror(t, tc, td, -1, false);
220 }
221 }
222
223 recalc_data(t);
224
225 if (t->flag & T_2D_EDIT) {
226 ED_area_status_text(t->area, IFACE_("Select a mirror axis (X, Y)"));
227 }
228 else {
229 ED_area_status_text(t->area, IFACE_("Select a mirror axis (X, Y, Z)"));
230 }
231 }
232}
233
234static void initMirror(TransInfo *t, wmOperator * /*op*/)
235{
237}
238
240
242 /*flags*/ T_NULL_ONE,
243 /*init_fn*/ initMirror,
244 /*transform_fn*/ applyMirror,
245 /*transform_matrix_fn*/ nullptr,
246 /*handle_event_fn*/ nullptr,
247 /*snap_distance_fn*/ nullptr,
248 /*snap_apply_fn*/ nullptr,
249 /*draw_fn*/ nullptr,
250};
251
252} // namespace blender::ed::transform
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE int bitscan_forward_i(int a)
MINLINE int count_bits_i(unsigned int n)
void mul_m3_v3(const float M[3][3], float r[3])
void unit_m3(float m[3][3])
bool invert_m3_m3(float inverse[3][3], const float mat[3][3])
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
void reflect_v3_v3v3(float out[3], const float v[3], const float normal[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
MINLINE void mul_v3_v3v3(float r[3], const float v1[3], const float v2[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
#define ELEM(...)
#define LIKELY(x)
#define IFACE_(msgid)
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:872
#define UI_MAX_DRAW_STR
#define str(s)
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
void recalc_data(TransInfo *t)
static void initMirror(TransInfo *t, wmOperator *)
static void ElementMirror(TransInfo *t, TransDataContainer *tc, TransData *td, int axis, bool flip)
void protectedTransBits(short protectflag, float vec[3])
void protectedScaleBits(short protectflag, float scale[3])
static void applyMirror(TransInfo *t)
void constraintScaleLim(const TransInfo *t, const TransDataContainer *tc, TransData *td)
void ElementRotation_ex(const TransInfo *t, const TransDataContainer *tc, TransData *td, const float mat[3][3], const float *center)
void constraintTransLim(const TransInfo *t, const TransDataContainer *tc, TransData *td)
bool transdata_check_local_center(const TransInfo *t, short around)
i
Definition text_draw.cc:230
#define FOREACH_TRANS_DATA_CONTAINER(t, th)
Definition transform.hh:42
conversion and adaptation of different datablocks to a common struct.
transform modes used by different operators.