Blender V5.0
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_utf8.h"
15
16#include "ED_screen.hh"
17
18#include "BLT_translation.hh"
19
20#include "UI_interface_types.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, int td_index, int axis, bool flip)
43{
44 TransData *td = &tc->data[td_index];
45
46 if ((t->flag & T_V3D_ALIGN) == 0 && tc->data_ext) {
47 TransDataExtension *td_ext = &tc->data_ext[td_index];
48
49 /* Size checked needed since the 3D cursor only uses rotation fields. */
50 if (td_ext->scale) {
51 float fscale[] = {1.0, 1.0, 1.0};
52
53 if (axis >= 0) {
54 fscale[axis] = -fscale[axis];
55 }
56 if (flip) {
57 negate_v3(fscale);
58 }
59
61
62 mul_v3_v3v3(td_ext->scale, td_ext->iscale, fscale);
63
64 constraintScaleLim(t, tc, td_index);
65 }
66
67 float rmat[3][3];
68 if (axis >= 0) {
69 float imat[3][3];
70 mul_m3_m3m3(rmat, t->spacemtx_inv, td->axismtx);
71 rmat[axis][0] = -rmat[axis][0];
72 rmat[axis][1] = -rmat[axis][1];
73 rmat[axis][2] = -rmat[axis][2];
74 rmat[0][axis] = -rmat[0][axis];
75 rmat[1][axis] = -rmat[1][axis];
76 rmat[2][axis] = -rmat[2][axis];
77 invert_m3_m3(imat, td->axismtx);
78 mul_m3_m3m3(rmat, rmat, imat);
79 mul_m3_m3m3(rmat, t->spacemtx, rmat);
80
81 ElementRotation_ex(t, tc, td, td_ext, rmat, td->center);
82
83 if (td_ext->rotAngle) {
84 *td_ext->rotAngle = -td_ext->irotAngle;
85 }
86 }
87 else {
88 unit_m3(rmat);
89 ElementRotation_ex(t, tc, td, td_ext, rmat, td->center);
90
91 if (td_ext->rotAngle) {
92 *td_ext->rotAngle = td_ext->irotAngle;
93 }
94 }
95 }
96
97 if ((td->flag & TD_NO_LOC) == 0) {
98 float center[3], vec[3];
99
100 /* Local constraint shouldn't alter center. */
102 copy_v3_v3(center, td->center);
103 }
104 else if (t->options & CTX_MOVIECLIP) {
105 if (td->flag & TD_INDIVIDUAL_SCALE) {
106 copy_v3_v3(center, td->center);
107 }
108 else {
109 copy_v3_v3(center, tc->center_local);
110 }
111 }
112 else {
113 copy_v3_v3(center, tc->center_local);
114 }
115
116 /* For individual element center, Editmode need to use iloc. */
117 if (t->flag & T_POINTS) {
118 sub_v3_v3v3(vec, td->iloc, center);
119 }
120 else {
121 sub_v3_v3v3(vec, td->center, center);
122 }
123
124 if (axis >= 0) {
125 /* Always do the mirror in global space. */
126 if (t->flag & T_EDIT) {
127 mul_m3_v3(td->mtx, vec);
128 }
129 reflect_v3_v3v3(vec, vec, t->spacemtx[axis]);
130 if (t->flag & T_EDIT) {
131 mul_m3_v3(td->smtx, vec);
132 }
133 }
134 if (flip) {
135 negate_v3(vec);
136 }
137
138 add_v3_v3(vec, center);
139 if (t->flag & T_POINTS) {
140 sub_v3_v3(vec, td->iloc);
141 }
142 else {
143 sub_v3_v3(vec, td->center);
144 }
145
146 if (t->options & (CTX_OBJECT | CTX_POSE_BONE)) {
147 mul_m3_v3(td->smtx, vec);
148 }
149
151 if (td->loc) {
152 add_v3_v3v3(td->loc, td->iloc, vec);
153 }
154
155 constraintTransLim(t, tc, td);
156 }
157}
158
159static void applyMirror(TransInfo *t)
160{
161 int i;
162 char str[UI_MAX_DRAW_STR];
164
165 /* OPTIMIZATION:
166 * This still recalculates transformation on mouse move
167 * while it should only recalculate on constraint change. */
168
169 /* If an axis has been selected. */
170 if (t->con.mode & CON_APPLY) {
171 /* #special_axis is either the constraint plane normal or the constraint axis.
172 * Assuming that CON_AXIS0 < CON_AXIS1 < CON_AXIS2 and CON_AXIS2 is CON_AXIS0 << 2 */
174 int axis_bitmap = (t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2)) / CON_AXIS0;
175 int special_axis_bitmap = 0;
176 int special_axis = -1;
177 int bitmap_len = count_bits_i(axis_bitmap);
178 if (LIKELY(!ELEM(bitmap_len, 0, 3))) {
179 special_axis_bitmap = (bitmap_len == 2) ? ~axis_bitmap : axis_bitmap;
180 special_axis = bitscan_forward_i(special_axis_bitmap);
181 }
182
183 SNPRINTF_UTF8(str, IFACE_("Mirror%s"), t->con.text);
184
185 if (t->options & CTX_SEQUENCER_IMAGE) {
186 if (axis_bitmap == 1) {
187 t->values_final[0] = -1;
188 t->values_final[1] = 1;
189 }
190 if (axis_bitmap == 2) {
191 t->values_final[0] = 1;
192 t->values_final[1] = -1;
193 }
194 }
195
197 TransData *td = tc->data;
198 for (i = 0; i < tc->data_len; i++, td++) {
199 if (td->flag & TD_SKIP) {
200 continue;
201 }
202
203 ElementMirror(t, tc, i, special_axis, bitmap_len >= 2);
204 }
205 }
206
207 recalc_data(t);
208
210 }
211 else {
212 if (t->options & CTX_SEQUENCER_IMAGE) {
213 t->values_final[0] = 1.0f;
214 t->values_final[1] = 1.0f;
215 }
217 TransData *td = tc->data;
218 for (i = 0; i < tc->data_len; i++, td++) {
219 if (td->flag & TD_SKIP) {
220 continue;
221 }
222
223 ElementMirror(t, tc, i, -1, false);
224 }
225 }
226
227 recalc_data(t);
228
229 if (t->flag & T_2D_EDIT) {
230 ED_area_status_text(t->area, IFACE_("Select a mirror axis (X, Y)"));
231 }
232 else {
233 ED_area_status_text(t->area, IFACE_("Select a mirror axis (X, Y, Z)"));
234 }
235 }
236}
237
238static void initMirror(TransInfo *t, wmOperator * /*op*/)
239{
241}
242
244
246 /*flags*/ T_NULL_ONE,
247 /*init_fn*/ initMirror,
248 /*transform_fn*/ applyMirror,
249 /*transform_matrix_fn*/ nullptr,
250 /*handle_event_fn*/ nullptr,
251 /*snap_distance_fn*/ nullptr,
252 /*snap_apply_fn*/ nullptr,
253 /*draw_fn*/ nullptr,
254};
255
256} // 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_UTF8(dst, format,...)
#define ELEM(...)
#define LIKELY(x)
#define IFACE_(msgid)
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:851
#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 *)
void protectedTransBits(short protectflag, float vec[3])
void protectedScaleBits(short protectflag, float scale[3])
void ElementRotation_ex(const TransInfo *t, const TransDataContainer *tc, TransData *td, TransDataExtension *td_ext, const float mat[3][3], const float *center)
static void ElementMirror(TransInfo *t, TransDataContainer *tc, int td_index, int axis, bool flip)
static void applyMirror(TransInfo *t)
void constraintScaleLim(const TransInfo *t, const TransDataContainer *tc, int td_index)
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.