4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): Martin Poirier
27 * ***** END GPL LICENSE BLOCK *****
37 #include "DNA_action_types.h"
38 #include "DNA_armature_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_meshdata_types.h" // Temporary, for snapping to other unselected meshes
42 #include "DNA_space_types.h"
43 #include "DNA_screen_types.h"
44 #include "DNA_userdef_types.h"
45 #include "DNA_view3d_types.h"
46 #include "DNA_windowmanager_types.h"
48 #include "RNA_access.h"
50 #include "BLI_arithb.h"
51 #include "BLI_editVert.h"
52 #include "BLI_blenlib.h"
54 //#include "BDR_drawobject.h"
56 //#include "editmesh.h"
57 //#include "BIF_editsima.h"
59 #include "BIF_glutil.h"
60 //#include "BIF_mywindow.h"
61 //#include "BIF_screen.h"
62 //#include "BIF_editsima.h"
63 //#include "BIF_drawimage.h"
64 //#include "BIF_editmesh.h"
66 #include "BKE_global.h"
67 #include "BKE_utildefines.h"
68 #include "BKE_DerivedMesh.h"
69 #include "BKE_object.h"
70 #include "BKE_anim.h" /* for duplis */
71 #include "BKE_context.h"
73 #include "ED_armature.h"
76 #include "ED_transform.h"
77 #include "ED_uvedit.h"
78 #include "ED_view3d.h"
82 #include "UI_resources.h"
83 #include "UI_view2d.h"
85 #include "MEM_guardedalloc.h"
87 #include "transform.h"
89 //#include "blendef.h" /* for selection modes */
91 /********************* PROTOTYPES ***********************/
93 void setSnappingCallback(TransInfo *t, short snap_target);
95 void ApplySnapTranslation(TransInfo *t, float vec[3]);
96 void ApplySnapRotation(TransInfo *t, float *vec);
97 void ApplySnapResize(TransInfo *t, float *vec);
99 void CalcSnapGrid(TransInfo *t, float *vec);
100 void CalcSnapGeometry(TransInfo *t, float *vec);
102 void TargetSnapMedian(TransInfo *t);
103 void TargetSnapCenter(TransInfo *t);
104 void TargetSnapClosest(TransInfo *t);
105 void TargetSnapActive(TransInfo *t);
107 float RotationBetween(TransInfo *t, float p1[3], float p2[3]);
108 float TranslationBetween(TransInfo *t, float p1[3], float p2[3]);
109 float ResizeBetween(TransInfo *t, float p1[3], float p2[3]);
112 /****************** IMPLEMENTATIONS *********************/
114 int BIF_snappingSupported(Object *obedit)
118 if (obedit == NULL || ELEM(obedit->type, OB_MESH, OB_ARMATURE)) /* only support object mesh or armature */
126 void drawSnapping(const struct bContext *C, TransInfo *t)
128 if ((t->tsnap.status & (SNAP_ON|POINT_INIT|TARGET_INIT)) == (SNAP_ON|POINT_INIT|TARGET_INIT) &&
129 (t->modifiers & MOD_SNAP_GEARS))
132 char col[4] = {1, 0, 1};
133 UI_GetThemeColor3ubv(TH_TRANSFORM, col);
134 glColor4ub(col[0], col[1], col[2], 128);
136 if (t->spacetype == SPACE_VIEW3D) {
137 View3D *v3d = CTX_wm_view3d(C);
138 RegionView3D *rv3d = CTX_wm_region_view3d(C);
139 float tmat[4][4], imat[4][4];
142 glDisable(GL_DEPTH_TEST);
144 size = get_drawsize(t->ar, t->tsnap.snapPoint);
146 size *= 0.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
148 Mat4CpyMat4(tmat, rv3d->viewmat);
149 Mat4Invert(imat, tmat);
151 drawcircball(GL_LINE_LOOP, t->tsnap.snapPoint, size, imat);
153 /* draw normal if needed */
154 if (usingSnappingNormal(t) && validSnappingNormal(t))
157 glVertex3f(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]);
158 glVertex3f( t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0],
159 t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1],
160 t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]);
165 glEnable(GL_DEPTH_TEST);
167 else if (t->spacetype==SPACE_IMAGE)
169 /*This will not draw, and Im nor sure why - campbell */
172 float xuser_asp, yuser_asp;
176 calc_image_view(G.sima, 'f'); // float
177 myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
180 ED_space_image_aspect(t->sa->spacedata.first, &xuser_aspx, &yuser_asp);
181 ED_space_image_width(t->sa->spacedata.first, &wi, &hi);
182 w = (((float)wi)/256.0f)*G.sima->zoom * xuser_asp;
183 h = (((float)hi)/256.0f)*G.sima->zoom * yuser_asp;
186 glTranslatef(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], 0.0f);
192 fdrawline(-0.020/w, 0, -0.1/w, 0);
193 fdrawline(0.1/w, 0, .020/w, 0);
194 fdrawline(0, -0.020/h, 0, -0.1/h);
195 fdrawline(0, 0.1/h, 0, 0.020/h);
197 glTranslatef(-t->tsnap.snapPoint[0], -t->tsnap.snapPoint[1], 0.0f);
205 int handleSnapping(TransInfo *t, wmEvent *event)
209 if (BIF_snappingSupported(t->obedit) && event->type == TABKEY && event->shift)
211 /* toggle snap and reinit */
212 t->settings->snap_flag ^= SCE_SNAP;
213 initSnapping(t, NULL);
220 void applyProject(TransInfo *t)
222 /* XXX FLICKER IN OBJECT MODE */
223 if ((t->tsnap.project) && (t->tsnap.status & SNAP_ON) && (t->modifiers & MOD_SNAP_GEARS))
225 TransData *td = t->data;
230 if(t->flag & (T_EDIT|T_POSE)) {
231 Object *ob = t->obedit?t->obedit:t->poseobj;
232 Mat4Invert(imat, ob->obmat);
235 for(i = 0 ; i < t->total; i++, td++) {
236 float iloc[3], loc[3], no[3];
240 if (td->flag & TD_NOACTION)
243 if (td->flag & TD_SKIP)
246 VECCOPY(iloc, td->loc);
247 if (t->flag & (T_EDIT|T_POSE))
249 Object *ob = t->obedit?t->obedit:t->poseobj;
250 Mat4MulVecfl(ob->obmat, iloc);
252 else if (t->flag & T_OBJECT)
254 VECCOPY(iloc, td->ob->obmat[3]);
257 project_float(t->ar, iloc, mval);
259 if (snapObjectsTransform(t, mval, &dist, loc, no, t->tsnap.mode))
261 // if(t->flag & (T_EDIT|T_POSE)) {
262 // Mat4MulVecfl(imat, loc);
265 VecSubf(tvec, loc, iloc);
267 Mat3MulVecfl(td->smtx, tvec);
269 VecAddf(td->loc, td->loc, tvec);
272 //XXX constraintTransLim(t, td);
277 void applySnapping(TransInfo *t, float *vec)
279 /* project is not applied this way */
280 if (t->tsnap.project)
283 if (t->tsnap.status & SNAP_FORCED)
285 t->tsnap.targetSnap(t);
287 t->tsnap.applySnap(t, vec);
289 else if ((t->tsnap.status & SNAP_ON) &&
290 (t->modifiers & MOD_SNAP_GEARS))
292 double current = PIL_check_seconds_timer();
294 // Time base quirky code to go around findnearest slowness
295 /* !TODO! add exception for object mode, no need to slow it down then */
296 if (current - t->tsnap.last >= 0.1)
298 t->tsnap.calcSnap(t, vec);
299 t->tsnap.targetSnap(t);
301 t->tsnap.last = current;
303 if ((t->tsnap.status & (POINT_INIT|TARGET_INIT)) == (POINT_INIT|TARGET_INIT))
305 t->tsnap.applySnap(t, vec);
310 void resetSnapping(TransInfo *t)
315 t->tsnap.modePoint = 0;
316 t->tsnap.modeTarget = 0;
318 t->tsnap.applySnap = NULL;
320 t->tsnap.snapNormal[0] = 0;
321 t->tsnap.snapNormal[1] = 0;
322 t->tsnap.snapNormal[2] = 0;
325 int usingSnappingNormal(TransInfo *t)
327 return t->tsnap.align;
330 int validSnappingNormal(TransInfo *t)
332 if ((t->tsnap.status & (POINT_INIT|TARGET_INIT)) == (POINT_INIT|TARGET_INIT))
334 if (Inpf(t->tsnap.snapNormal, t->tsnap.snapNormal) > 0)
343 void initSnapping(TransInfo *t, wmOperator *op)
345 ToolSettings *ts = t->settings;
346 Object *obedit = t->obedit;
348 short snap_mode = t->settings->snap_target;
352 if (op && RNA_struct_find_property(op->ptr, "snap") && RNA_property_is_set(op->ptr, "snap"))
354 if (RNA_boolean_get(op->ptr, "snap"))
357 snap_mode = RNA_enum_get(op->ptr, "snap_mode");
359 t->tsnap.status |= SNAP_FORCED|POINT_INIT;
360 RNA_float_get_array(op->ptr, "snap_point", t->tsnap.snapPoint);
362 /* snap align only defined in specific cases */
363 if (RNA_struct_find_property(op->ptr, "snap_align"))
365 t->tsnap.align = RNA_boolean_get(op->ptr, "snap_align");
366 RNA_float_get_array(op->ptr, "snap_normal", t->tsnap.snapNormal);
367 Normalize(t->tsnap.snapNormal);
370 if (RNA_struct_find_property(op->ptr, "snap_project"))
372 t->tsnap.project = RNA_boolean_get(op->ptr, "snap_project");
378 snapping = ((ts->snap_flag & SCE_SNAP) == SCE_SNAP);
379 t->tsnap.align = ((t->settings->snap_flag & SCE_SNAP_ROTATE) == SCE_SNAP_ROTATE);
380 t->tsnap.project = ((t->settings->snap_flag & SCE_SNAP_PROJECT) == SCE_SNAP_PROJECT);
383 /* force project off when not supported */
384 if (ts->snap_mode != SCE_SNAP_MODE_FACE)
386 t->tsnap.project = 0;
389 if ((t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) && // Only 3D view or UV
390 (t->flag & T_CAMERA) == 0) { // Not with camera selected
391 setSnappingCallback(t, snap_mode);
394 if (t->tsnap.applySnap != NULL && // A snapping function actually exist
395 (snapping) && // Only if the snap flag is on
396 (obedit != NULL && ELEM(obedit->type, OB_MESH, OB_ARMATURE)) ) // Temporary limited to edit mode meshes or armature
398 t->tsnap.status |= SNAP_ON;
399 t->tsnap.modePoint = SNAP_GEO;
401 if (t->flag & T_PROP_EDIT)
403 t->tsnap.mode = SNAP_NOT_OBEDIT;
407 t->tsnap.mode = SNAP_ALL;
411 else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
412 (snapping) && // Only if the snap flag is on
413 (obedit == NULL) ) // Object Mode
415 t->tsnap.status |= SNAP_ON;
416 t->tsnap.modePoint = SNAP_GEO;
417 t->tsnap.mode = SNAP_NOT_SELECTED;
421 /* Grid if snap is not possible */
422 t->tsnap.modePoint = SNAP_GRID;
427 /* Always grid outside of 3D view */
428 t->tsnap.modePoint = SNAP_GRID;
432 void setSnappingCallback(TransInfo *t, short snap_target)
434 t->tsnap.calcSnap = CalcSnapGeometry;
438 case SCE_SNAP_TARGET_CLOSEST:
439 t->tsnap.modeTarget = SNAP_CLOSEST;
440 t->tsnap.targetSnap = TargetSnapClosest;
442 case SCE_SNAP_TARGET_CENTER:
443 t->tsnap.modeTarget = SNAP_CENTER;
444 t->tsnap.targetSnap = TargetSnapCenter;
446 case SCE_SNAP_TARGET_MEDIAN:
447 t->tsnap.modeTarget = SNAP_MEDIAN;
448 t->tsnap.targetSnap = TargetSnapMedian;
450 case SCE_SNAP_TARGET_ACTIVE:
451 t->tsnap.modeTarget = SNAP_ACTIVE;
452 t->tsnap.targetSnap = TargetSnapActive;
459 case TFM_TRANSLATION:
460 t->tsnap.applySnap = ApplySnapTranslation;
461 t->tsnap.distance = TranslationBetween;
464 t->tsnap.applySnap = ApplySnapRotation;
465 t->tsnap.distance = RotationBetween;
467 // Can't do TARGET_CENTER with rotation, use TARGET_MEDIAN instead
468 if (snap_target == SCE_SNAP_TARGET_CENTER) {
469 t->tsnap.modeTarget = SNAP_MEDIAN;
470 t->tsnap.targetSnap = TargetSnapMedian;
474 t->tsnap.applySnap = ApplySnapResize;
475 t->tsnap.distance = ResizeBetween;
477 // Can't do TARGET_CENTER with resize, use TARGET_MEDIAN instead
478 if (snap_target == SCE_SNAP_TARGET_CENTER) {
479 t->tsnap.modeTarget = SNAP_MEDIAN;
480 t->tsnap.targetSnap = TargetSnapMedian;
484 t->tsnap.applySnap = NULL;
489 /********************** APPLY **************************/
491 void ApplySnapTranslation(TransInfo *t, float vec[3])
493 VecSubf(vec, t->tsnap.snapPoint, t->tsnap.snapTarget);
496 void ApplySnapRotation(TransInfo *t, float *vec)
498 if (t->tsnap.modeTarget == SNAP_CLOSEST) {
499 *vec = t->tsnap.dist;
502 *vec = RotationBetween(t, t->tsnap.snapTarget, t->tsnap.snapPoint);
506 void ApplySnapResize(TransInfo *t, float vec[3])
508 if (t->tsnap.modeTarget == SNAP_CLOSEST) {
509 vec[0] = vec[1] = vec[2] = t->tsnap.dist;
512 vec[0] = vec[1] = vec[2] = ResizeBetween(t, t->tsnap.snapTarget, t->tsnap.snapPoint);
516 /********************** DISTANCE **************************/
518 float TranslationBetween(TransInfo *t, float p1[3], float p2[3])
520 return VecLenf(p1, p2);
523 float RotationBetween(TransInfo *t, float p1[3], float p2[3])
525 float angle, start[3], end[3], center[3];
527 VECCOPY(center, t->center);
528 if(t->flag & (T_EDIT|T_POSE)) {
529 Object *ob= t->obedit?t->obedit:t->poseobj;
530 Mat4MulVecfl(ob->obmat, center);
533 VecSubf(start, p1, center);
534 VecSubf(end, p2, center);
536 // Angle around a constraint axis (error prone, will need debug)
537 if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
538 float axis[3], tmp[3];
540 t->con.applyRot(t, NULL, axis, NULL);
542 Projf(tmp, end, axis);
543 VecSubf(end, end, tmp);
545 Projf(tmp, start, axis);
546 VecSubf(start, start, tmp);
551 Crossf(tmp, start, end);
553 if (Inpf(tmp, axis) < 0.0)
554 angle = -acos(Inpf(start, end));
556 angle = acos(Inpf(start, end));
561 Mat3CpyMat4(mtx, t->viewmat);
563 Mat3MulVecfl(mtx, end);
564 Mat3MulVecfl(mtx, start);
566 angle = atan2(start[1],start[0]) - atan2(end[1],end[0]);
570 angle = angle - 2 * M_PI;
572 else if (angle < -(M_PI)) {
573 angle = 2 * M_PI + angle;
579 float ResizeBetween(TransInfo *t, float p1[3], float p2[3])
581 float d1[3], d2[3], center[3];
583 VECCOPY(center, t->center);
584 if(t->flag & (T_EDIT|T_POSE)) {
585 Object *ob= t->obedit?t->obedit:t->poseobj;
586 Mat4MulVecfl(ob->obmat, center);
589 VecSubf(d1, p1, center);
590 VecSubf(d2, p2, center);
592 if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
593 Mat3MulVecfl(t->con.pmtx, d1);
594 Mat3MulVecfl(t->con.pmtx, d2);
597 return VecLength(d2) / VecLength(d1);
600 /********************** CALC **************************/
602 void CalcSnapGrid(TransInfo *t, float *vec)
604 snapGridAction(t, t->tsnap.snapPoint, BIG_GEARS);
607 void CalcSnapGeometry(TransInfo *t, float *vec)
609 if (t->spacetype == SPACE_VIEW3D)
615 int dist = SNAP_MIN_DISTANCE; // Use a user defined value here
617 mval[0] = t->mval[0];
618 mval[1] = t->mval[1];
620 if (t->settings->snap_mode == SCE_SNAP_MODE_VOLUME)
622 ListBase depth_peels;
624 float *last_p = NULL;
625 float dist = FLT_MAX;
628 depth_peels.first = depth_peels.last = NULL;
630 peelObjectsTransForm(t, &depth_peels, mval);
632 // if (LAST_SNAP_POINT_VALID)
634 // last_p = LAST_SNAP_POINT;
638 last_p = t->tsnap.snapPoint;
642 for (p1 = depth_peels.first; p1; p1 = p1->next)
652 /* if peeling objects, take the first and last from each object */
653 if (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT)
656 for (peel = p1->next; peel; peel = peel->next)
658 if (peel->ob == p1->ob)
665 /* otherwise, pair first with second and so on */
668 for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next)
670 /* nothing to do here */
678 VecAddf(vec, p1->p, p2->p);
693 new_dist = VecLenf(last_p, vec);
709 BLI_freelistN(&depth_peels);
713 found = snapObjectsTransform(t, mval, &dist, loc, no, t->tsnap.mode);
720 VecSubf(tangent, loc, t->tsnap.snapPoint);
723 if (Inpf(tangent, tangent) > 0)
725 VECCOPY(t->tsnap.snapTangent, tangent);
728 VECCOPY(t->tsnap.snapPoint, loc);
729 VECCOPY(t->tsnap.snapNormal, no);
731 t->tsnap.status |= POINT_INIT;
735 t->tsnap.status &= ~POINT_INIT;
738 else if (t->spacetype == SPACE_IMAGE && t->obedit != NULL && t->obedit->type==OB_MESH)
739 { /* same as above but for UV's */
740 /* same as above but for UV's */
741 Image *ima= ED_space_image(t->sa->spacedata.first);
742 float aspx, aspy, co[2];
744 UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], co, co+1);
746 if(ED_uvedit_nearest_uv(t->scene, t->obedit, ima, co, t->tsnap.snapPoint))
748 ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
749 t->tsnap.snapPoint[0] *= aspx;
750 t->tsnap.snapPoint[1] *= aspy;
752 Mat4MulVecfl(t->obedit->obmat, t->tsnap.snapPoint);
754 t->tsnap.status |= POINT_INIT;
758 t->tsnap.status &= ~POINT_INIT;
763 /********************** TARGET **************************/
765 void TargetSnapCenter(TransInfo *t)
767 // Only need to calculate once
768 if ((t->tsnap.status & TARGET_INIT) == 0)
770 VECCOPY(t->tsnap.snapTarget, t->center);
771 if(t->flag & (T_EDIT|T_POSE)) {
772 Object *ob= t->obedit?t->obedit:t->poseobj;
773 Mat4MulVecfl(ob->obmat, t->tsnap.snapTarget);
776 t->tsnap.status |= TARGET_INIT;
780 void TargetSnapActive(TransInfo *t)
782 // Only need to calculate once
783 if ((t->tsnap.status & TARGET_INIT) == 0)
785 TransData *td = NULL;
786 TransData *active_td = NULL;
789 for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
791 if (td->flag & TD_ACTIVE)
800 VECCOPY(t->tsnap.snapTarget, active_td->center);
802 if(t->flag & (T_EDIT|T_POSE)) {
803 Object *ob= t->obedit?t->obedit:t->poseobj;
804 Mat4MulVecfl(ob->obmat, t->tsnap.snapTarget);
807 t->tsnap.status |= TARGET_INIT;
809 /* No active, default to median */
812 t->tsnap.modeTarget = SNAP_MEDIAN;
813 t->tsnap.targetSnap = TargetSnapMedian;
819 void TargetSnapMedian(TransInfo *t)
821 // Only need to calculate once
822 if ((t->tsnap.status & TARGET_INIT) == 0)
824 TransData *td = NULL;
827 t->tsnap.snapTarget[0] = 0;
828 t->tsnap.snapTarget[1] = 0;
829 t->tsnap.snapTarget[2] = 0;
831 for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
833 VecAddf(t->tsnap.snapTarget, t->tsnap.snapTarget, td->center);
836 VecMulf(t->tsnap.snapTarget, 1.0 / i);
838 if(t->flag & (T_EDIT|T_POSE)) {
839 Object *ob= t->obedit?t->obedit:t->poseobj;
840 Mat4MulVecfl(ob->obmat, t->tsnap.snapTarget);
843 t->tsnap.status |= TARGET_INIT;
847 void TargetSnapClosest(TransInfo *t)
849 // Only valid if a snap point has been selected
850 if (t->tsnap.status & POINT_INIT)
852 TransData *closest = NULL, *td = NULL;
855 if (t->flag & T_OBJECT)
858 for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
860 struct BoundBox *bb = object_get_boundbox(td->ob);
862 /* use boundbox if possible */
867 for (j = 0; j < 8; j++) {
871 VECCOPY(loc, bb->vec[j]);
872 Mat4MulVecfl(td->ext->obmat, loc);
874 dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
876 if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist))
878 VECCOPY(t->tsnap.snapTarget, loc);
880 t->tsnap.dist = dist;
884 /* use element center otherwise */
890 VECCOPY(loc, td->center);
892 dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
894 if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist))
896 VECCOPY(t->tsnap.snapTarget, loc);
898 t->tsnap.dist = dist;
906 for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
911 VECCOPY(loc, td->center);
913 if(t->flag & (T_EDIT|T_POSE)) {
914 Object *ob= t->obedit?t->obedit:t->poseobj;
915 Mat4MulVecfl(ob->obmat, loc);
918 dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
920 if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist))
922 VECCOPY(t->tsnap.snapTarget, loc);
924 t->tsnap.dist = dist;
929 t->tsnap.status |= TARGET_INIT;
932 /*================================================================*/
934 int snapFace(ARegion *ar, float v1co[3], float v2co[3], float v3co[3], float *v4co, float mval[2], float ray_start[3], float ray_start_local[3], float ray_normal_local[3], float obmat[][4], float timat[][3], float *loc, float *no, int *dist, float *depth)
940 result = RayIntersectsTriangleThreshold(ray_start_local, ray_normal_local, v1co, v2co, v3co, &lambda, NULL, 0.001);
943 float location[3], normal[3];
949 VECCOPY(intersect, ray_normal_local);
950 VecMulf(intersect, lambda);
951 VecAddf(intersect, intersect, ray_start_local);
953 VECCOPY(location, intersect);
956 CalcNormFloat4(v1co, v2co, v3co, v4co, normal);
958 CalcNormFloat(v1co, v2co, v3co, normal);
960 Mat4MulVecfl(obmat, location);
962 new_depth = VecLenf(location, ray_start);
964 project_int(ar, location, screen_loc);
965 new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]);
967 if (new_dist <= *dist && new_depth < *depth)
972 VECCOPY(loc, location);
975 Mat3MulVecfl(timat, no);
985 int snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], short v2no[3], float mval[2], float ray_start[3], float ray_start_local[3], float ray_normal_local[3], float obmat[][4], float timat[][3], float *loc, float *no, int *dist, float *depth)
987 float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
991 VECCOPY(ray_end, ray_normal_local);
992 VecMulf(ray_end, 2000);
993 VecAddf(ray_end, ray_start_local, ray_end);
995 result = LineIntersectLine(v1co, v2co, ray_start_local, ray_end, intersect, dvec); /* dvec used but we don't care about result */
999 float edge_loc[3], vec[3];
1002 /* check for behind ray_start */
1003 VecSubf(dvec, intersect, ray_start_local);
1005 VecSubf(edge_loc, v1co, v2co);
1006 VecSubf(vec, intersect, v2co);
1008 mul = Inpf(vec, edge_loc) / Inpf(edge_loc, edge_loc);
1012 VECCOPY(intersect, v1co);
1016 VECCOPY(intersect, v2co);
1019 if (Inpf(ray_normal_local, dvec) > 0)
1026 VECCOPY(location, intersect);
1028 Mat4MulVecfl(obmat, location);
1030 new_depth = VecLenf(location, ray_start);
1032 project_int(ar, location, screen_loc);
1033 new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]);
1035 /* 10% threshold if edge is closer but a bit further
1036 * this takes care of series of connected edges a bit slanted w.r.t the viewport
1037 * otherwise, it would stick to the verts of the closest edge and not slide along merrily
1039 if (new_dist <= *dist && new_depth < *depth * 1.001)
1046 VecSubf(edge_loc, v1co, v2co);
1047 VecSubf(vec, intersect, v2co);
1049 mul = Inpf(vec, edge_loc) / Inpf(edge_loc, edge_loc);
1053 NormalShortToFloat(n1, v1no);
1054 NormalShortToFloat(n2, v2no);
1055 VecLerpf(no, n2, n1, mul);
1056 Mat3MulVecfl(timat, no);
1060 VECCOPY(loc, location);
1070 int snapVertex(ARegion *ar, float vco[3], short vno[3], float mval[2], float ray_start[3], float ray_start_local[3], float ray_normal_local[3], float obmat[][4], float timat[][3], float *loc, float *no, int *dist, float *depth)
1075 VecSubf(dvec, vco, ray_start_local);
1077 if (Inpf(ray_normal_local, dvec) > 0)
1084 VECCOPY(location, vco);
1086 Mat4MulVecfl(obmat, location);
1088 new_depth = VecLenf(location, ray_start);
1090 project_int(ar, location, screen_loc);
1091 new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]);
1093 if (new_dist <= *dist && new_depth < *depth)
1098 VECCOPY(loc, location);
1102 NormalShortToFloat(no, vno);
1103 Mat3MulVecfl(timat, no);
1114 int snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm, float obmat[][4], float ray_start[3], float ray_normal[3], float mval[2], float *loc, float *no, int *dist, float *depth)
1117 float ray_start_local[3], ray_normal_local[3];
1120 Mat4Invert(imat, obmat);
1122 VECCOPY(ray_start_local, ray_start);
1123 VECCOPY(ray_normal_local, ray_normal);
1125 Mat4MulVecfl(imat, ray_start_local);
1126 Mat4Mul3Vecfl(imat, ray_normal_local);
1132 for (eBone=arm->edbo->first; eBone; eBone=eBone->next) {
1133 if (eBone->layer & arm->layer) {
1134 /* skip hidden or moving (selected) bones */
1135 if ((eBone->flag & (BONE_HIDDEN_A|BONE_ROOTSEL|BONE_TIPSEL))==0) {
1138 case SCE_SNAP_MODE_VERTEX:
1139 retval |= snapVertex(ar, eBone->head, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
1140 retval |= snapVertex(ar, eBone->tail, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
1142 case SCE_SNAP_MODE_EDGE:
1143 retval |= snapEdge(ar, eBone->head, NULL, eBone->tail, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
1150 else if (ob->pose && ob->pose->chanbase.first)
1152 bPoseChannel *pchan;
1155 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1157 /* skip hidden bones */
1158 if (bone && !(bone->flag & (BONE_HIDDEN_P|BONE_HIDDEN_PG))) {
1159 float *head_vec = pchan->pose_head;
1160 float *tail_vec = pchan->pose_tail;
1164 case SCE_SNAP_MODE_VERTEX:
1165 retval |= snapVertex(ar, head_vec, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
1166 retval |= snapVertex(ar, tail_vec, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
1168 case SCE_SNAP_MODE_EDGE:
1169 retval |= snapEdge(ar, head_vec, NULL, tail_vec, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
1179 int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, EditMesh *em, float obmat[][4], float ray_start[3], float ray_normal[3], float mval[2], float *loc, float *no, int *dist, float *depth)
1182 int totvert = dm->getNumVerts(dm);
1183 int totface = dm->getNumFaces(dm);
1187 float timat[3][3]; /* transpose inverse matrix for normals */
1188 float ray_start_local[3], ray_normal_local[3];
1191 Mat4Invert(imat, obmat);
1193 Mat3CpyMat4(timat, imat);
1196 VECCOPY(ray_start_local, ray_start);
1197 VECCOPY(ray_normal_local, ray_normal);
1199 Mat4MulVecfl(imat, ray_start_local);
1200 Mat4Mul3Vecfl(imat, ray_normal_local);
1203 /* If number of vert is more than an arbitrary limit,
1204 * test against boundbox first
1207 struct BoundBox *bb = object_get_boundbox(ob);
1208 test = ray_hit_boundbox(bb, ray_start_local, ray_normal_local);
1215 case SCE_SNAP_MODE_FACE:
1217 MVert *verts = dm->getVertArray(dm);
1218 MFace *faces = dm->getFaceArray(dm);
1219 int *index_array = NULL;
1225 index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX);
1226 EM_init_index_arrays(em, 0, 0, 1);
1229 for( i = 0; i < totface; i++) {
1230 EditFace *efa = NULL;
1231 MFace *f = faces + i;
1233 test = 1; /* reset for every face */
1239 index = index_array[i];
1246 if (index == ORIGINDEX_NONE)
1252 efa = EM_get_face_for_index(index);
1254 if (efa && (efa->h || (efa->v1->f & SELECT) || (efa->v2->f & SELECT) || (efa->v3->f & SELECT) || (efa->v4 && efa->v4->f & SELECT)))
1269 v4co = verts[f->v4].co;
1272 result = snapFace(ar, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, v4co, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
1275 if (f->v4 && result == 0)
1277 retval |= snapFace(ar, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, verts[f->v2].co, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
1284 EM_free_index_arrays();
1288 case SCE_SNAP_MODE_VERTEX:
1290 MVert *verts = dm->getVertArray(dm);
1291 int *index_array = NULL;
1297 index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
1298 EM_init_index_arrays(em, 1, 0, 0);
1301 for( i = 0; i < totvert; i++) {
1302 EditVert *eve = NULL;
1303 MVert *v = verts + i;
1305 test = 1; /* reset for every vert */
1311 index = index_array[i];
1318 if (index == ORIGINDEX_NONE)
1324 eve = EM_get_vert_for_index(index);
1326 if (eve && (eve->h || (eve->f & SELECT)))
1336 retval |= snapVertex(ar, v->co, v->no, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
1342 EM_free_index_arrays();
1346 case SCE_SNAP_MODE_EDGE:
1348 MVert *verts = dm->getVertArray(dm);
1349 MEdge *edges = dm->getEdgeArray(dm);
1350 int totedge = dm->getNumEdges(dm);
1351 int *index_array = NULL;
1357 index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
1358 EM_init_index_arrays(em, 0, 1, 0);
1361 for( i = 0; i < totedge; i++) {
1362 EditEdge *eed = NULL;
1363 MEdge *e = edges + i;
1365 test = 1; /* reset for every vert */
1371 index = index_array[i];
1378 if (index == ORIGINDEX_NONE)
1384 eed = EM_get_edge_for_index(index);
1386 if (eed && (eed->h || (eed->v1->f & SELECT) || (eed->v2->f & SELECT)))
1396 retval |= snapEdge(ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
1402 EM_free_index_arrays();
1413 int snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, float obmat[][4], float ray_start[3], float ray_normal[3], float mval[2], float *loc, float *no, int *dist, float *depth)
1415 ToolSettings *ts= scene->toolsettings;
1418 if (ob->type == OB_MESH) {
1424 em = ((Mesh *)ob->data)->edit_mesh;
1425 dm = editmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH);
1430 dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
1433 retval = snapDerivedMesh(ts->snap_mode, ar, ob, dm, em, obmat, ray_start, ray_normal, mval, loc, no, dist, depth);
1437 else if (ob->type == OB_ARMATURE)
1439 retval = snapArmature(ts->snap_mode, ar, ob, ob->data, obmat, ray_start, ray_normal, mval, loc, no, dist, depth);
1445 int snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, float mval[2], int *dist, float *loc, float *no, SnapMode mode) {
1447 float depth = FLT_MAX;
1449 float ray_start[3], ray_normal[3];
1451 viewray(ar, v3d, mval, ray_start, ray_normal);
1453 if (mode == SNAP_ALL && obedit)
1455 Object *ob = obedit;
1457 retval |= snapObject(scene, ar, ob, 1, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth);
1461 for ( base = FIRSTBASE; base != NULL; base = base->next ) {
1462 if ( BASE_SELECTABLE(v3d, base) && (base->flag & (BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA)) == 0 && ((mode == SNAP_NOT_SELECTED && (base->flag & (SELECT|BA_WAS_SEL)) == 0) || (ELEM(mode, SNAP_ALL, SNAP_NOT_OBEDIT) && base != BASACT)) ) {
1463 Object *ob = base->object;
1465 if (ob->transflag & OB_DUPLI)
1467 DupliObject *dupli_ob;
1468 ListBase *lb = object_duplilist(scene, ob);
1470 for(dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next)
1472 Object *ob = dupli_ob->ob;
1474 retval |= snapObject(scene, ar, ob, 0, dupli_ob->mat, ray_start, ray_normal, mval, loc, no, dist, &depth);
1477 free_object_duplilist(lb);
1480 retval |= snapObject(scene, ar, ob, 0, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth);
1487 int snapObjectsTransform(TransInfo *t, float mval[2], int *dist, float *loc, float *no, SnapMode mode)
1489 return snapObjects(t->scene, t->view, t->ar, t->obedit, mval, dist, loc, no, mode);
1492 int snapObjectsContext(bContext *C, float mval[2], int *dist, float *loc, float *no, SnapMode mode)
1494 ScrArea *sa = CTX_wm_area(C);
1495 View3D *v3d = sa->spacedata.first;
1497 return snapObjects(CTX_data_scene(C), v3d, CTX_wm_region(C), CTX_data_edit_object(C), mval, dist, loc, no, mode);
1500 /******************** PEELING *********************************/
1503 int cmpPeel(void *arg1, void *arg2)
1505 DepthPeel *p1 = arg1;
1506 DepthPeel *p2 = arg2;
1509 if (p1->depth < p2->depth)
1513 else if (p1->depth > p2->depth)
1521 void removeDoublesPeel(ListBase *depth_peels)
1525 for (peel = depth_peels->first; peel; peel = peel->next)
1527 DepthPeel *next_peel = peel->next;
1529 if (peel && next_peel && ABS(peel->depth - next_peel->depth) < 0.0015)
1531 peel->next = next_peel->next;
1533 if (next_peel->next)
1535 next_peel->next->prev = peel;
1538 MEM_freeN(next_peel);
1543 void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float no[3], Object *ob)
1545 DepthPeel *peel = MEM_callocN(sizeof(DepthPeel), "DepthPeel");
1547 peel->depth = depth;
1549 VECCOPY(peel->p, p);
1550 VECCOPY(peel->no, no);
1552 BLI_addtail(depth_peels, peel);
1557 int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_start[3], float ray_normal[3], float mval[2], ListBase *depth_peels)
1560 int totvert = dm->getNumVerts(dm);
1561 int totface = dm->getNumFaces(dm);
1565 float timat[3][3]; /* transpose inverse matrix for normals */
1566 float ray_start_local[3], ray_normal_local[3];
1569 Mat4Invert(imat, obmat);
1571 Mat3CpyMat4(timat, imat);
1574 VECCOPY(ray_start_local, ray_start);
1575 VECCOPY(ray_normal_local, ray_normal);
1577 Mat4MulVecfl(imat, ray_start_local);
1578 Mat4Mul3Vecfl(imat, ray_normal_local);
1581 /* If number of vert is more than an arbitrary limit,
1582 * test against boundbox first
1585 struct BoundBox *bb = object_get_boundbox(ob);
1586 test = ray_hit_boundbox(bb, ray_start_local, ray_normal_local);
1590 MVert *verts = dm->getVertArray(dm);
1591 MFace *faces = dm->getFaceArray(dm);
1594 for( i = 0; i < totface; i++) {
1595 MFace *f = faces + i;
1600 result = RayIntersectsTriangleThreshold(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL, 0.001);
1603 float location[3], normal[3];
1607 VECCOPY(intersect, ray_normal_local);
1608 VecMulf(intersect, lambda);
1609 VecAddf(intersect, intersect, ray_start_local);
1611 VECCOPY(location, intersect);
1614 CalcNormFloat4(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co, normal);
1616 CalcNormFloat(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, normal);
1618 Mat4MulVecfl(obmat, location);
1620 new_depth = VecLenf(location, ray_start);
1622 Mat3MulVecfl(timat, normal);
1625 addDepthPeel(depth_peels, new_depth, location, normal, ob);
1628 if (f->v4 && result == 0)
1630 result = RayIntersectsTriangleThreshold(ray_start_local, ray_normal_local, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, &lambda, NULL, 0.001);
1633 float location[3], normal[3];
1637 VECCOPY(intersect, ray_normal_local);
1638 VecMulf(intersect, lambda);
1639 VecAddf(intersect, intersect, ray_start_local);
1641 VECCOPY(location, intersect);
1644 CalcNormFloat4(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co, normal);
1646 CalcNormFloat(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, normal);
1648 Mat4MulVecfl(obmat, location);
1650 new_depth = VecLenf(location, ray_start);
1652 Mat3MulVecfl(timat, normal);
1655 addDepthPeel(depth_peels, new_depth, location, normal, ob);
1665 int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase *depth_peels, float mval[2])
1669 float ray_start[3], ray_normal[3];
1671 viewray(ar, v3d, mval, ray_start, ray_normal);
1673 for ( base = scene->base.first; base != NULL; base = base->next ) {
1674 if ( BASE_SELECTABLE(v3d, base) ) {
1675 Object *ob = base->object;
1677 if (ob->transflag & OB_DUPLI)
1679 DupliObject *dupli_ob;
1680 ListBase *lb = object_duplilist(scene, ob);
1682 for(dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next)
1684 Object *ob = dupli_ob->ob;
1686 if (ob->type == OB_MESH) {
1688 DerivedMesh *dm = NULL;
1693 dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
1695 val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
1699 em = ((Mesh *)ob->data)->edit_mesh;
1700 dm = editmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
1702 val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
1705 retval = retval || val;
1711 free_object_duplilist(lb);
1714 if (ob->type == OB_MESH) {
1716 DerivedMesh *dm = NULL;
1721 dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
1723 val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
1727 em = ((Mesh *)ob->data)->edit_mesh;
1728 dm = editmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
1730 val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
1733 retval = retval || val;
1740 BLI_sortlist(depth_peels, cmpPeel);
1741 removeDoublesPeel(depth_peels);
1746 int peelObjectsTransForm(TransInfo *t, ListBase *depth_peels, float mval[2])
1748 return peelObjects(t->scene, t->view, t->ar, t->obedit, depth_peels, mval);
1751 int peelObjectsContext(bContext *C, ListBase *depth_peels, float mval[2])
1753 ScrArea *sa = CTX_wm_area(C);
1754 View3D *v3d = sa->spacedata.first;
1756 return peelObjects(CTX_data_scene(C), v3d, CTX_wm_region(C), CTX_data_edit_object(C), depth_peels, mval);
1759 /*================================================================*/
1761 static void applyGrid(TransInfo *t, float *val, int max_index, float fac[3], GearsType action);
1764 void snapGridAction(TransInfo *t, float *val, GearsType action) {
1767 fac[NO_GEARS] = t->snap[0];
1768 fac[BIG_GEARS] = t->snap[1];
1769 fac[SMALL_GEARS] = t->snap[2];
1771 applyGrid(t, val, t->idx_max, fac, action);
1775 void snapGrid(TransInfo *t, float *val) {
1779 // Only do something if using Snap to Grid
1780 if (t->tsnap.modePoint != SNAP_GRID)
1783 if(t->mode==TFM_ROTATION || t->mode==TFM_WARP || t->mode==TFM_TILT || t->mode==TFM_TRACKBALL || t->mode==TFM_BONE_ROLL)
1784 invert = U.flag & USER_AUTOROTGRID;
1785 else if(t->mode==TFM_RESIZE || t->mode==TFM_SHEAR || t->mode==TFM_BONESIZE || t->mode==TFM_SHRINKFATTEN || t->mode==TFM_CURVE_SHRINKFATTEN)
1786 invert = U.flag & USER_AUTOSIZEGRID;
1788 invert = U.flag & USER_AUTOGRABGRID;
1791 action = (t->modifiers & MOD_SNAP_GEARS) ? NO_GEARS: BIG_GEARS;
1794 action = (t->modifiers & MOD_SNAP_GEARS) ? BIG_GEARS : NO_GEARS;
1797 if (action == BIG_GEARS && (t->modifiers & MOD_PRECISION)) {
1798 action = SMALL_GEARS;
1801 snapGridAction(t, val, action);
1805 static void applyGrid(TransInfo *t, float *val, int max_index, float fac[3], GearsType action)
1808 float asp[3] = {1.0f, 1.0f, 1.0f}; // TODO: Remove hard coded limit here (3)
1810 // Early bailing out if no need to snap
1811 if (fac[action] == 0.0)
1814 /* evil hack - snapping needs to be adapted for image aspect ratio */
1815 if((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
1816 ED_space_image_uv_aspect(t->sa->spacedata.first, asp, asp+1);
1819 for (i=0; i<=max_index; i++) {
1820 val[i]= fac[action]*asp[i]*(float)floor(val[i]/(fac[action]*asp[i]) +.5);