Fix memleak on snap_curs_to_sel_ex
[blender.git] / source / blender / editors / space_view3d / view3d_snap.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_view3d/view3d_snap.c
29  *  \ingroup spview3d
30  */
31
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_armature_types.h"
36 #include "DNA_object_types.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_utildefines.h"
40 #include "BLI_math.h"
41
42 #include "BKE_action.h"
43 #include "BKE_armature.h"
44 #include "BKE_context.h"
45 #include "BKE_editmesh.h"
46 #include "BKE_layer.h"
47 #include "BKE_main.h"
48 #include "BKE_mball.h"
49 #include "BKE_object.h"
50 #include "BKE_report.h"
51 #include "BKE_tracking.h"
52
53 #include "DEG_depsgraph.h"
54 #include "DEG_depsgraph_query.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "RNA_access.h"
60 #include "RNA_define.h"
61
62 #include "ED_object.h"
63 #include "ED_transverts.h"
64 #include "ED_keyframing.h"
65 #include "ED_screen.h"
66
67 #include "view3d_intern.h"
68
69 static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]);
70 static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3]);
71
72
73 /* *********************** operators ******************** */
74
75 /** Snaps every individual object center to its nearest point on the grid. **/
76 static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
77 {
78         Depsgraph *depsgraph = CTX_data_depsgraph(C);
79         ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
80         Object *obedit = CTX_data_edit_object(C);
81         Scene *scene = CTX_data_scene(C);
82         View3D *v3d = CTX_wm_view3d(C);
83         TransVertStore tvs = {NULL};
84         TransVert *tv;
85         float gridf, imat[3][3], bmat[3][3], vec[3];
86         int a;
87
88         gridf = ED_view3d_grid_scale(scene, v3d, NULL);
89
90         if (obedit) {
91                 ViewLayer *view_layer = CTX_data_view_layer(C);
92                 uint objects_len = 0;
93                 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
94                 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
95                         obedit = objects[ob_index];
96                         if (ED_transverts_check_obedit(obedit)) {
97                                 ED_transverts_create_from_obedit(&tvs, obedit, 0);
98                         }
99
100                         if (tvs.transverts_tot == 0) {
101                                 continue;
102                         }
103
104                         copy_m3_m4(bmat, obedit->obmat);
105                         invert_m3_m3(imat, bmat);
106
107                         tv = tvs.transverts;
108                         for (a = 0; a < tvs.transverts_tot; a++, tv++) {
109                                 copy_v3_v3(vec, tv->loc);
110                                 mul_m3_v3(bmat, vec);
111                                 add_v3_v3(vec, obedit->obmat[3]);
112                                 vec[0] = gridf * floorf(0.5f + vec[0] / gridf);
113                                 vec[1] = gridf * floorf(0.5f + vec[1] / gridf);
114                                 vec[2] = gridf * floorf(0.5f + vec[2] / gridf);
115                                 sub_v3_v3(vec, obedit->obmat[3]);
116
117                                 mul_m3_v3(imat, vec);
118                                 copy_v3_v3(tv->loc, vec);
119                         }
120
121                         ED_transverts_update_obedit(&tvs, obedit);
122                         ED_transverts_free(&tvs);
123                 }
124                 MEM_freeN(objects);
125         }
126         else {
127                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
128
129                 FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN(view_layer_eval, ob_eval)
130                 {
131                         Object *ob = DEG_get_original_object(ob_eval);
132                         if (ob->mode & OB_MODE_POSE) {
133                                 bPoseChannel *pchan_eval;
134                                 bArmature *arm_eval = ob_eval->data;
135
136                                 invert_m4_m4(ob_eval->imat, ob_eval->obmat);
137
138                                 for (pchan_eval = ob_eval->pose->chanbase.first; pchan_eval; pchan_eval = pchan_eval->next) {
139                                         if (pchan_eval->bone->flag & BONE_SELECTED) {
140                                                 if (pchan_eval->bone->layer & arm_eval->layer) {
141                                                         if ((pchan_eval->bone->flag & BONE_CONNECTED) == 0) {
142                                                                 float nLoc[3];
143
144                                                                 /* get nearest grid point to snap to */
145                                                                 copy_v3_v3(nLoc, pchan_eval->pose_mat[3]);
146                                                                 /* We must operate in world space! */
147                                                                 mul_m4_v3(ob_eval->obmat, nLoc);
148                                                                 vec[0] = gridf * floorf(0.5f + nLoc[0] / gridf);
149                                                                 vec[1] = gridf * floorf(0.5f + nLoc[1] / gridf);
150                                                                 vec[2] = gridf * floorf(0.5f + nLoc[2] / gridf);
151                                                                 /* Back in object space... */
152                                                                 mul_m4_v3(ob_eval->imat, vec);
153
154                                                                 /* Get location of grid point in pose space. */
155                                                                 BKE_armature_loc_pose_to_bone(pchan_eval, vec, vec);
156
157                                                                 /* adjust location on the original pchan*/
158                                                                 bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, pchan_eval->name);
159                                                                 if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
160                                                                         pchan->loc[0] = vec[0];
161                                                                 if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
162                                                                         pchan->loc[1] = vec[1];
163                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
164                                                                         pchan->loc[2] = vec[2];
165
166                                                                 /* auto-keyframing */
167                                                                 ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
168                                                         }
169                                                         /* if the bone has a parent and is connected to the parent,
170                                                          * don't do anything - will break chain unless we do auto-ik.
171                                                          */
172                                                 }
173                                         }
174                                 }
175                                 ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
176
177                                 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
178                         }
179                         else {
180                                 vec[0] = -ob_eval->obmat[3][0] + gridf * floorf(0.5f + ob_eval->obmat[3][0] / gridf);
181                                 vec[1] = -ob_eval->obmat[3][1] + gridf * floorf(0.5f + ob_eval->obmat[3][1] / gridf);
182                                 vec[2] = -ob_eval->obmat[3][2] + gridf * floorf(0.5f + ob_eval->obmat[3][2] / gridf);
183
184                                 if (ob->parent) {
185                                         float originmat[3][3];
186                                         BKE_object_where_is_calc_ex(depsgraph, scene, NULL, ob, originmat);
187
188                                         invert_m3_m3(imat, originmat);
189                                         mul_m3_v3(imat, vec);
190                                 }
191                                 if ((ob->protectflag & OB_LOCK_LOCX) == 0)
192                                         ob->loc[0] = ob_eval->loc[0] + vec[0];
193                                 if ((ob->protectflag & OB_LOCK_LOCY) == 0)
194                                         ob->loc[1] = ob_eval->loc[1] + vec[1];
195                                 if ((ob->protectflag & OB_LOCK_LOCZ) == 0)
196                                         ob->loc[2] = ob_eval->loc[2] + vec[2];
197
198                                 /* auto-keyframing */
199                                 ED_autokeyframe_object(C, scene, ob, ks);
200
201                                 DEG_id_tag_update(&ob->id, OB_RECALC_OB);
202                         }
203                 }
204                 FOREACH_SELECTED_EDITABLE_OBJECT_END;
205         }
206
207         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
208
209         return OPERATOR_FINISHED;
210 }
211
212 void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
213 {
214         /* identifiers */
215         ot->name = "Snap Selection to Grid";
216         ot->description = "Snap selected item(s) to their nearest grid division";
217         ot->idname = "VIEW3D_OT_snap_selected_to_grid";
218
219         /* api callbacks */
220         ot->exec = snap_sel_to_grid_exec;
221         ot->poll = ED_operator_region_view3d_active;
222
223         /* flags */
224         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
225 }
226
227 /* *************************************************** */
228
229 /** Snaps the selection as a whole (use_offset=true) or each selected object to the given location.
230  *
231  * \param snap_target_global: a location in global space to snap to (eg. 3D cursor or active object).
232  * \param use_offset: if the selected objects should maintain their relative offsets and be snapped by the selection
233  *                    pivot point (median, active), or if every object origin should be snapped to the given location.
234 **/
235 static int snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset)
236 {
237         Depsgraph *depsgraph = CTX_data_depsgraph(C);
238         Scene *scene = CTX_data_scene(C);
239         Object *obedit = CTX_data_edit_object(C);
240         Object *obact = CTX_data_active_object(C);
241         View3D *v3d = CTX_wm_view3d(C);
242         TransVertStore tvs = {NULL};
243         TransVert *tv;
244         float imat[3][3], bmat[3][3];
245         float center_global[3];
246         float offset_global[3];
247         int a;
248
249         if (use_offset) {
250                 if ((v3d && scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) &&
251                     snap_calc_active_center(C, true, center_global))
252                 {
253                         /* pass */
254                 }
255                 else {
256                         snap_curs_to_sel_ex(C, center_global);
257                 }
258                 sub_v3_v3v3(offset_global, snap_target_global, center_global);
259         }
260
261         if (obedit) {
262                 float snap_target_local[3];
263                 ViewLayer *view_layer = CTX_data_view_layer(C);
264                 uint objects_len = 0;
265                 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
266                 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
267                         obedit = objects[ob_index];
268
269                         if (ED_transverts_check_obedit(obedit)) {
270                                 ED_transverts_create_from_obedit(&tvs, obedit, 0);
271                         }
272                         if (tvs.transverts_tot == 0) {
273                                 continue;
274                         }
275
276                         copy_m3_m4(bmat, obedit->obmat);
277                         invert_m3_m3(imat, bmat);
278
279                         /* get the cursor in object space */
280                         sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]);
281                         mul_m3_v3(imat, snap_target_local);
282
283                         if (use_offset) {
284                                 float offset_local[3];
285
286                                 mul_v3_m3v3(offset_local, imat, offset_global);
287
288                                 tv = tvs.transverts;
289                                 for (a = 0; a < tvs.transverts_tot; a++, tv++) {
290                                         add_v3_v3(tv->loc, offset_local);
291                                 }
292                         }
293                         else {
294                                 tv = tvs.transverts;
295                                 for (a = 0; a < tvs.transverts_tot; a++, tv++) {
296                                         copy_v3_v3(tv->loc, snap_target_local);
297                                 }
298                         }
299
300                         ED_transverts_update_obedit(&tvs, obedit);
301                         ED_transverts_free(&tvs);
302                 }
303                 MEM_freeN(objects);
304         }
305         else if (obact && (obact->mode & OB_MODE_POSE)) {
306                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
307                 CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
308                 {
309                         bPoseChannel *pchan;
310                         bArmature *arm = ob->data;
311                         float snap_target_local[3];
312
313                         invert_m4_m4(ob->imat, ob->obmat);
314                         mul_v3_m4v3(snap_target_local, ob->imat, snap_target_global);
315
316                         for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
317                                 if ((pchan->bone->flag & BONE_SELECTED) &&
318                                         (PBONE_VISIBLE(arm, pchan->bone)) &&
319                                         /* if the bone has a parent and is connected to the parent,
320                                          * don't do anything - will break chain unless we do auto-ik.
321                                          */
322                                         (pchan->bone->flag & BONE_CONNECTED) == 0)
323                                 {
324                                         pchan->bone->flag |= BONE_TRANSFORM;
325                                 }
326                                 else {
327                                         pchan->bone->flag &= ~BONE_TRANSFORM;
328                                 }
329                         }
330
331                         for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
332                                 if ((pchan->bone->flag & BONE_TRANSFORM) &&
333                                         /* check that our parents not transformed (if we have one) */
334                                         ((pchan->bone->parent &&
335                                           BKE_armature_bone_flag_test_recursive(pchan->bone->parent, BONE_TRANSFORM)) == 0))
336                                 {
337                                         /* Get position in pchan (pose) space. */
338                                         float cursor_pose[3];
339
340                                         if (use_offset) {
341                                                 mul_v3_m4v3(cursor_pose, ob->obmat, pchan->pose_mat[3]);
342                                                 add_v3_v3(cursor_pose, offset_global);
343
344                                                 mul_m4_v3(ob->imat, cursor_pose);
345                                                 BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose);
346                                         }
347                                         else {
348                                                 BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose);
349                                         }
350
351                                         /* copy new position */
352                                         if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
353                                                 pchan->loc[0] = cursor_pose[0];
354                                         if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
355                                                 pchan->loc[1] = cursor_pose[1];
356                                         if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
357                                                 pchan->loc[2] = cursor_pose[2];
358
359                                         /* auto-keyframing */
360                                         ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
361                                 }
362                         }
363
364                         for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
365                                 pchan->bone->flag &= ~BONE_TRANSFORM;
366                         }
367
368                         ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
369
370                         DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
371                 }
372                 CTX_DATA_END;
373         }
374         else {
375                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
376                 Main *bmain = CTX_data_main(C);
377
378                 ListBase ctx_data_list;
379                 CollectionPointerLink *ctx_ob;
380                 Object *ob;
381
382                 CTX_data_selected_editable_objects(C, &ctx_data_list);
383
384                 /* reset flags */
385                 for (ob = bmain->object.first; ob; ob = ob->id.next) {
386                         ob->flag &= ~OB_DONE;
387                 }
388
389                 /* tag objects we're transforming */
390                 for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) {
391                         ob = ctx_ob->ptr.data;
392                         ob->flag |= OB_DONE;
393                 }
394
395                 for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) {
396                         ob = ctx_ob->ptr.data;
397
398                         if ((ob->parent && BKE_object_flag_test_recursive(ob->parent, OB_DONE)) == 0) {
399
400                                 float cursor_parent[3];  /* parent-relative */
401
402                                 if (use_offset) {
403                                         add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global);
404                                 }
405                                 else {
406                                         copy_v3_v3(cursor_parent, snap_target_global);
407                                 }
408
409                                 sub_v3_v3(cursor_parent, ob->obmat[3]);
410
411                                 if (ob->parent) {
412                                         float originmat[3][3];
413                                         BKE_object_where_is_calc_ex(depsgraph, scene, NULL, ob, originmat);
414
415                                         invert_m3_m3(imat, originmat);
416                                         mul_m3_v3(imat, cursor_parent);
417                                 }
418                                 if ((ob->protectflag & OB_LOCK_LOCX) == 0)
419                                         ob->loc[0] += cursor_parent[0];
420                                 if ((ob->protectflag & OB_LOCK_LOCY) == 0)
421                                         ob->loc[1] += cursor_parent[1];
422                                 if ((ob->protectflag & OB_LOCK_LOCZ) == 0)
423                                         ob->loc[2] += cursor_parent[2];
424
425                                 /* auto-keyframing */
426                                 ED_autokeyframe_object(C, scene, ob, ks);
427
428                                 DEG_id_tag_update(&ob->id, OB_RECALC_OB);
429                         }
430                 }
431
432                 BLI_freelistN(&ctx_data_list);
433         }
434
435         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
436
437         return OPERATOR_FINISHED;
438 }
439
440 static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op)
441 {
442         const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
443
444         Scene *scene = CTX_data_scene(C);
445         View3D *v3d = CTX_wm_view3d(C);
446
447         const float *snap_target_global = ED_view3d_cursor3d_get(scene, v3d)->location;
448
449         return snap_selected_to_location(C, snap_target_global, use_offset);
450 }
451
452 void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
453 {
454         /* identifiers */
455         ot->name = "Snap Selection to Cursor";
456         ot->description = "Snap selected item(s) to the 3D cursor";
457         ot->idname = "VIEW3D_OT_snap_selected_to_cursor";
458
459         /* api callbacks */
460         ot->exec = snap_selected_to_cursor_exec;
461         ot->poll = ED_operator_view3d_active;
462
463         /* flags */
464         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
465
466         /* rna */
467         RNA_def_boolean(ot->srna, "use_offset", 1, "Offset",
468                 "If the selection should be snapped as a whole or by each object center");
469 }
470
471 /* *************************************************** */
472
473 /** Snaps each selected object to the location of the active selected object. **/
474 static int snap_selected_to_active_exec(bContext *C, wmOperator *op)
475 {
476         float snap_target_global[3];
477
478         if (snap_calc_active_center(C, false, snap_target_global) == false) {
479                 BKE_report(op->reports, RPT_ERROR, "No active element found!");
480                 return OPERATOR_CANCELLED;
481         }
482
483         return snap_selected_to_location(C, snap_target_global, false);
484 }
485
486 void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot)
487 {
488         /* identifiers */
489         ot->name = "Snap Selection to Active";
490         ot->description = "Snap selected item(s) to the active item";
491         ot->idname = "VIEW3D_OT_snap_selected_to_active";
492
493         /* api callbacks */
494         ot->exec = snap_selected_to_active_exec;
495         ot->poll = ED_operator_view3d_active;
496
497         /* flags */
498         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
499 }
500
501
502 /* *************************************************** */
503
504 /** Snaps the 3D cursor location to its nearest point on the grid. **/
505 static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
506 {
507         Scene *scene = CTX_data_scene(C);
508         View3D *v3d = CTX_wm_view3d(C);
509         float gridf, *curs;
510
511         gridf = ED_view3d_grid_scale(scene, v3d, NULL);
512         curs = ED_view3d_cursor3d_get(scene, v3d)->location;
513
514         curs[0] = gridf * floorf(0.5f + curs[0] / gridf);
515         curs[1] = gridf * floorf(0.5f + curs[1] / gridf);
516         curs[2] = gridf * floorf(0.5f + curs[2] / gridf);
517
518         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);  /* hrm */
519         DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
520
521         return OPERATOR_FINISHED;
522 }
523
524 void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
525 {
526         /* identifiers */
527         ot->name = "Snap Cursor to Grid";
528         ot->description = "Snap 3D cursor to the nearest grid division";
529         ot->idname = "VIEW3D_OT_snap_cursor_to_grid";
530
531         /* api callbacks */
532         ot->exec = snap_curs_to_grid_exec;
533         ot->poll = ED_operator_region_view3d_active;
534
535         /* flags */
536         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
537 }
538
539 /* **************************************************** */
540
541 /** Returns the center position of a tracking marker visible on the viewport (useful to snap to). **/
542 static void bundle_midpoint(Depsgraph *depsgraph, Scene *scene, Object *ob, float r_vec[3])
543 {
544         MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
545         MovieTracking *tracking;
546         MovieTrackingObject *object;
547         bool ok = false;
548         float min[3], max[3], mat[4][4], pos[3], cammat[4][4];
549
550         if (!clip)
551                 return;
552
553         tracking = &clip->tracking;
554
555         copy_m4_m4(cammat, ob->obmat);
556
557         BKE_tracking_get_camera_object_matrix(depsgraph, scene, ob, mat);
558
559         INIT_MINMAX(min, max);
560
561         for (object = tracking->objects.first; object; object = object->next) {
562                 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
563                 MovieTrackingTrack *track = tracksbase->first;
564                 float obmat[4][4];
565
566                 if (object->flag & TRACKING_OBJECT_CAMERA) {
567                         copy_m4_m4(obmat, mat);
568                 }
569                 else {
570                         float imat[4][4];
571
572                         BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, scene->r.cfra, imat);
573                         invert_m4(imat);
574
575                         mul_m4_m4m4(obmat, cammat, imat);
576                 }
577
578                 while (track) {
579                         if ((track->flag & TRACK_HAS_BUNDLE) && TRACK_SELECTED(track)) {
580                                 ok = 1;
581                                 mul_v3_m4v3(pos, obmat, track->bundle_pos);
582                                 minmax_v3v3_v3(min, max, pos);
583                         }
584
585                         track = track->next;
586                 }
587         }
588
589         if (ok) {
590                 mid_v3_v3v3(r_vec, min, max);
591         }
592 }
593
594 /** Snaps the 3D cursor location to the median point of the selection. **/
595 static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
596 {
597         Depsgraph *depsgraph = CTX_data_depsgraph(C);
598         ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
599         Object *obedit = CTX_data_edit_object(C);
600         Scene *scene = CTX_data_scene(C);
601         View3D *v3d = CTX_wm_view3d(C);
602         TransVertStore tvs = {NULL};
603         TransVert *tv;
604         float bmat[3][3], vec[3], min[3], max[3], centroid[3];
605         int count, a;
606
607         count = 0;
608         INIT_MINMAX(min, max);
609         zero_v3(centroid);
610
611         if (obedit) {
612                 int global_transverts_tot = 0;
613                 ViewLayer *view_layer = CTX_data_view_layer(C);
614                 uint objects_len = 0;
615                 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
616                 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
617                         obedit = objects[ob_index];
618
619                         if (ED_transverts_check_obedit(obedit)) {
620                                 ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES);
621                         }
622
623                         global_transverts_tot += tvs.transverts_tot;
624                         if (global_transverts_tot != 0) {
625
626                                 Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
627                                 copy_m3_m4(bmat, obedit_eval->obmat);
628
629                                 tv = tvs.transverts;
630                                 for (a = 0; a < tvs.transverts_tot; a++, tv++) {
631                                         copy_v3_v3(vec, tv->loc);
632                                         mul_m3_v3(bmat, vec);
633                                         add_v3_v3(vec, obedit_eval->obmat[3]);
634                                         add_v3_v3(centroid, vec);
635                                         minmax_v3v3_v3(min, max, vec);
636                                 }
637                         }
638                         ED_transverts_free(&tvs);
639                 }
640                 MEM_freeN(objects);
641
642                 if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEAN) {
643                         mul_v3_fl(centroid, 1.0f / (float)global_transverts_tot);
644                         copy_v3_v3(cursor, centroid);
645                 }
646                 else {
647                         mid_v3_v3v3(cursor, min, max);
648                 }
649         }
650         else {
651                 Object *obact = CTX_data_active_object(C);
652
653                 if (obact && (obact->mode & OB_MODE_POSE)) {
654                         Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
655                         bArmature *arm = obact_eval->data;
656                         bPoseChannel *pchan;
657                         for (pchan = obact_eval->pose->chanbase.first; pchan; pchan = pchan->next) {
658                                 if (arm->layer & pchan->bone->layer) {
659                                         if (pchan->bone->flag & BONE_SELECTED) {
660                                                 copy_v3_v3(vec, pchan->pose_head);
661                                                 mul_m4_v3(obact_eval->obmat, vec);
662                                                 add_v3_v3(centroid, vec);
663                                                 minmax_v3v3_v3(min, max, vec);
664                                                 count++;
665                                         }
666                                 }
667                         }
668                 }
669                 else {
670                         FOREACH_SELECTED_OBJECT_BEGIN(view_layer_eval, ob_eval)
671                         {
672                                 copy_v3_v3(vec, ob_eval->obmat[3]);
673
674                                 /* special case for camera -- snap to bundles */
675                                 if (ob_eval->type == OB_CAMERA) {
676                                         /* snap to bundles should happen only when bundles are visible */
677                                         if (v3d->flag2 & V3D_SHOW_RECONSTRUCTION) {
678                                                 bundle_midpoint(depsgraph, scene, DEG_get_original_object(ob_eval), vec);
679                                         }
680                                 }
681
682                                 add_v3_v3(centroid, vec);
683                                 minmax_v3v3_v3(min, max, vec);
684                                 count++;
685                         }
686                         FOREACH_SELECTED_OBJECT_END;
687                 }
688
689                 if (count == 0) {
690                         return false;
691                 }
692
693                 if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEAN) {
694                         mul_v3_fl(centroid, 1.0f / (float)count);
695                         copy_v3_v3(cursor, centroid);
696                 }
697                 else {
698                         mid_v3_v3v3(cursor, min, max);
699                 }
700         }
701         return true;
702 }
703
704 static int snap_curs_to_sel_exec(bContext *C, wmOperator *UNUSED(op))
705 {
706         Scene *scene = CTX_data_scene(C);
707         View3D *v3d = CTX_wm_view3d(C);
708         float *curs;
709
710         curs = ED_view3d_cursor3d_get(scene, v3d)->location;
711
712         if (snap_curs_to_sel_ex(C, curs)) {
713                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
714                 DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
715
716                 return OPERATOR_FINISHED;
717         }
718         else {
719                 return OPERATOR_CANCELLED;
720         }
721 }
722
723 void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
724 {
725         /* identifiers */
726         ot->name = "Snap Cursor to Selected";
727         ot->description = "Snap 3D cursor to the middle of the selected item(s)";
728         ot->idname = "VIEW3D_OT_snap_cursor_to_selected";
729
730         /* api callbacks */
731         ot->exec = snap_curs_to_sel_exec;
732         ot->poll = ED_operator_view3d_active;
733
734         /* flags */
735         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
736 }
737
738 /* ********************************************** */
739
740 /** Calculates the center position of the active object in global space.
741  *
742  * Note: this could be exported to be a generic function.
743  * see: calculateCenterActive
744 **/
745 static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3])
746 {
747         const Depsgraph *depsgraph = CTX_data_depsgraph(C);
748         Object *obedit = CTX_data_edit_object(C);
749
750         if (obedit) {
751                 Object *ob_edit_eval = DEG_get_evaluated_object(depsgraph, obedit);
752
753                 if (ED_object_editmode_calc_active_center(ob_edit_eval, select_only, r_center)) {
754                         mul_m4_v3(ob_edit_eval->obmat, r_center);
755                         return true;
756                 }
757         }
758         else {
759                 Object *ob = CTX_data_active_object(C);
760                 if (ob) {
761                         Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
762
763                         if (ob->mode & OB_MODE_POSE) {
764                                 bPoseChannel *pchan = BKE_pose_channel_active(ob_eval);
765                                 if (pchan) {
766                                         if (!select_only || (pchan->bone->flag & BONE_SELECTED)) {
767                                                 copy_v3_v3(r_center, pchan->pose_head);
768                                                 mul_m4_v3(ob_eval->obmat, r_center);
769                                                 return true;
770                                         }
771                                 }
772                         }
773                         else {
774
775                                 if (!select_only || (ob_eval->flag & SELECT)) {
776                                         copy_v3_v3(r_center, ob_eval->obmat[3]);
777                                         return true;
778                                 }
779                         }
780                 }
781         }
782
783         return false;
784 }
785
786 static int snap_curs_to_active_exec(bContext *C, wmOperator *UNUSED(op))
787 {
788         Scene *scene = CTX_data_scene(C);
789         View3D *v3d = CTX_wm_view3d(C);
790         float *curs;
791
792         curs = ED_view3d_cursor3d_get(scene, v3d)->location;
793
794         if (snap_calc_active_center(C, false, curs)) {
795                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
796                 DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
797
798                 return OPERATOR_FINISHED;
799         }
800         else {
801                 return OPERATOR_CANCELLED;
802         }
803 }
804
805 void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
806 {
807         /* identifiers */
808         ot->name = "Snap Cursor to Active";
809         ot->description = "Snap 3D cursor to the active item";
810         ot->idname = "VIEW3D_OT_snap_cursor_to_active";
811
812         /* api callbacks */
813         ot->exec = snap_curs_to_active_exec;
814         ot->poll = ED_operator_view3d_active;
815
816         /* flags */
817         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
818 }
819
820 /* **************************************************** */
821
822 /** Snaps the 3D cursor location to the origin. **/
823 static int snap_curs_to_center_exec(bContext *C, wmOperator *UNUSED(op))
824 {
825         Scene *scene = CTX_data_scene(C);
826         View3D *v3d = CTX_wm_view3d(C);
827         float *curs;
828         curs = ED_view3d_cursor3d_get(scene, v3d)->location;
829
830         zero_v3(curs);
831
832         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
833         DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
834
835         return OPERATOR_FINISHED;
836 }
837
838 void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
839 {
840         /* identifiers */
841         ot->name = "Snap Cursor to Center";
842         ot->description = "Snap 3D cursor to the world origin";
843         ot->idname = "VIEW3D_OT_snap_cursor_to_center";
844
845         /* api callbacks */
846         ot->exec = snap_curs_to_center_exec;
847         ot->poll = ED_operator_view3d_active;
848
849         /* flags */
850         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
851 }
852
853 /* **************************************************** */
854
855 /** Calculates the bounding box corners (min and max) for \a obedit. The returned values are in global space. **/
856 bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3])
857 {
858         TransVertStore tvs = {NULL};
859         TransVert *tv;
860         float centroid[3], vec[3], bmat[3][3];
861
862         /* Metaballs are an exception. */
863         if (obedit->type == OB_MBALL) {
864                 float ob_min[3], ob_max[3];
865                 bool changed;
866
867                 changed = BKE_mball_minmax_ex(obedit->data, ob_min, ob_max, obedit->obmat, SELECT);
868                 if (changed) {
869                         minmax_v3v3_v3(r_min, r_max, ob_min);
870                         minmax_v3v3_v3(r_min, r_max, ob_max);
871                 }
872                 return changed;
873         }
874
875         if (ED_transverts_check_obedit(obedit))
876                 ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS);
877
878         if (tvs.transverts_tot == 0)
879                 return false;
880
881         copy_m3_m4(bmat, obedit->obmat);
882
883         tv = tvs.transverts;
884         for (int a = 0; a < tvs.transverts_tot; a++, tv++) {
885                 copy_v3_v3(vec, (tv->flag & TX_VERT_USE_MAPLOC) ? tv->maploc : tv->loc);
886                 mul_m3_v3(bmat, vec);
887                 add_v3_v3(vec, obedit->obmat[3]);
888                 add_v3_v3(centroid, vec);
889                 minmax_v3v3_v3(r_min, r_max, vec);
890         }
891
892         ED_transverts_free(&tvs);
893
894         return true;
895 }