Blender V4.3
object_warp.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2013 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "DNA_object_types.h"
10#include "DNA_scene_types.h"
11#include "DNA_view3d_types.h"
12
13#include "BKE_context.hh"
14
15#include "BLI_math_matrix.h"
16#include "BLI_math_rotation.h"
17#include "BLI_math_vector.h"
18
19#include "RNA_access.hh"
20#include "RNA_define.hh"
21
22#include "WM_api.hh"
23#include "WM_types.hh"
24
25#include "ED_object.hh"
26#include "ED_transverts.hh"
27
28#include "object_intern.hh"
29
30namespace blender::ed::object {
31
32static void object_warp_calc_view_matrix(float r_mat_view[4][4],
33 float r_center_view[3],
34 Object *obedit,
35 const float viewmat[4][4],
36 const float center[3],
37 const float offset_angle)
38{
39 float mat_offset[4][4];
40 float viewmat_roll[4][4];
41
42 /* apply the rotation offset by rolling the view */
43 axis_angle_to_mat4_single(mat_offset, 'Z', offset_angle);
44 mul_m4_m4m4(viewmat_roll, mat_offset, viewmat);
45
46 /* apply the view and the object matrix */
47 mul_m4_m4m4(r_mat_view, viewmat_roll, obedit->object_to_world().ptr());
48
49 /* get the view-space cursor */
50 mul_v3_m4v3(r_center_view, viewmat_roll, center);
51}
52
54 const float mat_view[4][4],
55 const float center_view[3],
56 float *r_min,
57 float *r_max)
58{
59 /* no need to apply translation and cursor offset for every vertex, delay this */
60 const float x_ofs = (mat_view[3][0] - center_view[0]);
61 float min = FLT_MAX, max = -FLT_MAX;
62
63 TransVert *tv = tvs->transverts;
64 for (int i = 0; i < tvs->transverts_tot; i++, tv++) {
65 float val;
66
67 /* Convert object-space to view-space. */
68 val = dot_m4_v3_row_x(mat_view, tv->loc);
69
70 min = min_ff(min, val);
71 max = max_ff(max, val);
72 }
73
74 *r_min = min + x_ofs;
75 *r_max = max + x_ofs;
76}
77
79 const float mat_view[4][4],
80 const float center_view[3],
81 const float angle_,
82 const float min,
83 const float max)
84{
85 TransVert *tv;
86 const float angle = -angle_;
87/* cache vars for tiny speedup */
88#if 1
89 const float range = max - min;
90 const float range_inv = 1.0f / range;
91 const float min_ofs = min + (0.5f * range);
92#endif
93
94 float dir_min[2], dir_max[2];
95 float imat_view[4][4];
96
97 invert_m4_m4(imat_view, mat_view);
98
99 /* calculate the direction vectors outside min/max range */
100 {
101 const float phi = angle * 0.5f;
102
103 dir_max[0] = cosf(phi);
104 dir_max[1] = sinf(phi);
105
106 dir_min[0] = -dir_max[0];
107 dir_min[1] = dir_max[1];
108 }
109
110 tv = tvs->transverts;
111 for (int i = 0; i < tvs->transverts_tot; i++, tv++) {
112 float co[3], co_add[2];
113 float val, phi;
114
115 /* Convert object-space to view-space. */
116 mul_v3_m4v3(co, mat_view, tv->loc);
117 sub_v2_v2(co, center_view);
118
119 val = co[0];
120 /* is overwritten later anyway */
121 // co[0] = 0.0f;
122
123 if (val < min) {
124 mul_v2_v2fl(co_add, dir_min, min - val);
125 val = min;
126 }
127 else if (val > max) {
128 mul_v2_v2fl(co_add, dir_max, val - max);
129 val = max;
130 }
131 else {
132 zero_v2(co_add);
133 }
134
135/* map from x axis to (-0.5 - 0.5) */
136#if 0
137 val = ((val - min) / (max - min)) - 0.5f;
138#else
139 val = (val - min_ofs) * range_inv;
140#endif
141
142 /* convert the x axis into a rotation */
143 phi = val * angle;
144
145 co[0] = -sinf(phi) * co[1];
146 co[1] = cosf(phi) * co[1];
147
148 add_v2_v2(co, co_add);
149
150 /* Convert view-space to object-space. */
151 add_v2_v2(co, center_view);
152 mul_v3_m4v3(tv->loc, imat_view, co);
153 }
154}
155
157{
158 const float warp_angle = RNA_float_get(op->ptr, "warp_angle");
159 const float offset_angle = RNA_float_get(op->ptr, "offset_angle");
160
161 TransVertStore tvs = {nullptr};
162 Object *obedit = CTX_data_edit_object(C);
163
164 /* typically from 'rv3d' and 3d cursor */
165 float viewmat[4][4];
166 float center[3];
167
168 /* 'viewmat' relative vars */
169 float mat_view[4][4];
170 float center_view[3];
171
172 float min, max;
173
174 if (shape_key_report_if_locked(obedit, op->reports)) {
175 return OPERATOR_CANCELLED;
176 }
177
179 if (tvs.transverts == nullptr) {
180 return OPERATOR_CANCELLED;
181 }
182
183 /* Get view-matrix. */
184 {
185 PropertyRNA *prop_viewmat = RNA_struct_find_property(op->ptr, "viewmat");
186 if (RNA_property_is_set(op->ptr, prop_viewmat)) {
187 RNA_property_float_get_array(op->ptr, prop_viewmat, (float *)viewmat);
188 }
189 else {
191
192 if (rv3d) {
193 copy_m4_m4(viewmat, rv3d->viewmat);
194 }
195 else {
196 unit_m4(viewmat);
197 }
198
199 RNA_property_float_set_array(op->ptr, prop_viewmat, (float *)viewmat);
200 }
201 }
202
203 /* get center */
204 {
205 PropertyRNA *prop_center = RNA_struct_find_property(op->ptr, "center");
206 if (RNA_property_is_set(op->ptr, prop_center)) {
207 RNA_property_float_get_array(op->ptr, prop_center, center);
208 }
209 else {
210 const Scene *scene = CTX_data_scene(C);
211 copy_v3_v3(center, scene->cursor.location);
212
213 RNA_property_float_set_array(op->ptr, prop_center, center);
214 }
215 }
216
217 object_warp_calc_view_matrix(mat_view, center_view, obedit, viewmat, center, offset_angle);
218
219 /* get minmax */
220 {
221 PropertyRNA *prop_min = RNA_struct_find_property(op->ptr, "min");
222 PropertyRNA *prop_max = RNA_struct_find_property(op->ptr, "max");
223
224 if (RNA_property_is_set(op->ptr, prop_min) || RNA_property_is_set(op->ptr, prop_max)) {
225 min = RNA_property_float_get(op->ptr, prop_min);
226 max = RNA_property_float_get(op->ptr, prop_max);
227 }
228 else {
229 /* handy to set the bounds of the mesh */
230 object_warp_transverts_minmax_x(&tvs, mat_view, center_view, &min, &max);
231
232 RNA_property_float_set(op->ptr, prop_min, min);
233 RNA_property_float_set(op->ptr, prop_max, max);
234 }
235
236 if (min > max) {
237 std::swap(min, max);
238 }
239 }
240
241 if (min != max) {
242 object_warp_transverts(&tvs, mat_view, center_view, warp_angle, min, max);
243 }
244
245 ED_transverts_update_obedit(&tvs, obedit);
246 ED_transverts_free(&tvs);
247
249
250 return OPERATOR_FINISHED;
251}
252
254{
255 PropertyRNA *prop;
256
257 /* identifiers */
258 ot->name = "Warp";
259 ot->description = "Warp vertices around the cursor";
260 ot->idname = "TRANSFORM_OT_vertex_warp";
261
262 /* api callbacks */
265
266 /* flags */
268
269 /* props */
270 prop = RNA_def_float(ot->srna,
271 "warp_angle",
272 DEG2RADF(360.0f),
273 -FLT_MAX,
274 FLT_MAX,
275 "Warp Angle",
276 "Amount to warp about the cursor",
277 DEG2RADF(-360.0f),
278 DEG2RADF(360.0f));
280
281 prop = RNA_def_float(ot->srna,
282 "offset_angle",
283 DEG2RADF(0.0f),
284 -FLT_MAX,
285 FLT_MAX,
286 "Offset Angle",
287 "Angle to use as the basis for warping",
288 DEG2RADF(-360.0f),
289 DEG2RADF(360.0f));
291
292 prop = RNA_def_float(ot->srna, "min", -1.0f, -FLT_MAX, FLT_MAX, "Min", "", -100.0, 100.0);
293 prop = RNA_def_float(ot->srna, "max", 1.0f, -FLT_MAX, FLT_MAX, "Max", "", -100.0, 100.0);
294
295 /* hidden props */
297 ot->srna, "viewmat", 4, 4, nullptr, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
299
301 ot->srna, "center", 3, nullptr, -FLT_MAX, FLT_MAX, "Center", "", -FLT_MAX, FLT_MAX);
303}
304
305} // namespace blender::ed::object
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void unit_m4(float m[4][4])
Definition rct.c:1127
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
#define DEG2RADF(_deg)
void axis_angle_to_mat4_single(float R[4][4], char axis, float angle)
MINLINE void sub_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 zero_v2(float r[2])
MINLINE void mul_v2_v2fl(float r[2], const float a[2], float f)
MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT
Object is a sort of wrapper for general info.
bool ED_transverts_poll(bContext *C)
void ED_transverts_create_from_obedit(TransVertStore *tvs, const Object *obedit, int mode)
void ED_transverts_free(TransVertStore *tvs)
void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit)
@ TM_SKIP_HANDLES
@ TM_ALL_JOINTS
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
@ PROP_ANGLE
Definition RNA_types.hh:155
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_DRAW
Definition WM_types.hh:428
#define NC_OBJECT
Definition WM_types.hh:346
#define sinf(x)
#define cosf(x)
IndexRange range
static int object_warp_verts_exec(bContext *C, wmOperator *op)
bool shape_key_report_if_locked(const Object *obedit, ReportList *reports)
static void object_warp_calc_view_matrix(float r_mat_view[4][4], float r_center_view[3], Object *obedit, const float viewmat[4][4], const float center[3], const float offset_angle)
void TRANSFORM_OT_vertex_warp(wmOperatorType *ot)
static void object_warp_transverts(TransVertStore *tvs, const float mat_view[4][4], const float center_view[3], const float angle_, const float min, const float max)
static void object_warp_transverts_minmax_x(TransVertStore *tvs, const float mat_view[4][4], const float center_view[3], float *r_min, float *r_max)
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
PropertyRNA * RNA_def_float_matrix(StructOrFunctionRNA *cont_, const char *identifier, const int rows, const int columns, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float_vector_xyz(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
float viewmat[4][4]
TransVert * transverts
float * loc
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct PointerRNA * ptr
float max
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4125