Blender  V2.59
transform_snap.c
Go to the documentation of this file.
00001 /*
00002  * $Id: transform_snap.c 38773 2011-07-28 02:15:58Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): Martin Poirier
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #include <stdlib.h>
00036 #include <math.h>
00037 #include <float.h>
00038 #include <stdio.h>
00039 
00040 #include "PIL_time.h"
00041 
00042 #include "DNA_armature_types.h"
00043 #include "DNA_scene_types.h"
00044 #include "DNA_object_types.h"
00045 #include "DNA_meshdata_types.h" // Temporary, for snapping to other unselected meshes
00046 #include "DNA_space_types.h"
00047 #include "DNA_screen_types.h"
00048 #include "DNA_view3d_types.h"
00049 #include "DNA_windowmanager_types.h"
00050 
00051 #include "RNA_access.h"
00052 
00053 #include "BLI_math.h"
00054 #include "BLI_editVert.h"
00055 #include "BLI_blenlib.h"
00056 #include "BLI_utildefines.h"
00057 
00058 //#include "BDR_drawobject.h"
00059 //
00060 //#include "editmesh.h"
00061 //#include "BIF_editsima.h"
00062 #include "BIF_gl.h"
00063 //#include "BIF_mywindow.h"
00064 //#include "BIF_screen.h"
00065 //#include "BIF_editsima.h"
00066 //#include "BIF_drawimage.h"
00067 //#include "BIF_editmesh.h"
00068 
00069 #include "BKE_DerivedMesh.h"
00070 #include "BKE_object.h"
00071 #include "BKE_anim.h" /* for duplis */
00072 #include "BKE_context.h"
00073 
00074 #include "ED_armature.h"
00075 #include "ED_image.h"
00076 #include "ED_mesh.h"
00077 #include "ED_uvedit.h"
00078 #include "ED_view3d.h"
00079 
00080 #include "WM_types.h"
00081 
00082 #include "UI_resources.h"
00083 #include "UI_view2d.h"
00084 
00085 #include "MEM_guardedalloc.h"
00086 
00087 #include "transform.h"
00088 
00089 //#include "blendef.h" /* for selection modes */
00090 
00091 #define USE_BVH_FACE_SNAP
00092 
00093 /********************* PROTOTYPES ***********************/
00094 
00095 void setSnappingCallback(TransInfo *t);
00096 
00097 void ApplySnapTranslation(TransInfo *t, float vec[3]);
00098 void ApplySnapRotation(TransInfo *t, float *vec);
00099 void ApplySnapResize(TransInfo *t, float *vec);
00100 
00101 void CalcSnapGrid(TransInfo *t, float *vec);
00102 void CalcSnapGeometry(TransInfo *t, float *vec);
00103 
00104 void TargetSnapMedian(TransInfo *t);
00105 void TargetSnapCenter(TransInfo *t);
00106 void TargetSnapClosest(TransInfo *t);
00107 void TargetSnapActive(TransInfo *t);
00108 
00109 float RotationBetween(TransInfo *t, float p1[3], float p2[3]);
00110 float TranslationBetween(TransInfo *t, float p1[3], float p2[3]);
00111 float ResizeBetween(TransInfo *t, float p1[3], float p2[3]);
00112 
00113 
00114 /****************** IMPLEMENTATIONS *********************/
00115 
00116 #if 0
00117 int BIF_snappingSupported(Object *obedit)
00118 {
00119         int status = 0;
00120         
00121         if (obedit == NULL || ELEM4(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE)) /* only support object mesh, armature, curves */
00122         {
00123                 status = 1;
00124         }
00125         
00126         return status;
00127 }
00128 #endif
00129 
00130 int validSnap(TransInfo *t)
00131 {
00132         return (t->tsnap.status & (POINT_INIT|TARGET_INIT)) == (POINT_INIT|TARGET_INIT) ||
00133                         (t->tsnap.status & (MULTI_POINTS|TARGET_INIT)) == (MULTI_POINTS|TARGET_INIT);
00134 }
00135 
00136 int activeSnap(TransInfo *t)
00137 {
00138         return (t->modifiers & (MOD_SNAP|MOD_SNAP_INVERT)) == MOD_SNAP || (t->modifiers & (MOD_SNAP|MOD_SNAP_INVERT)) == MOD_SNAP_INVERT;
00139 }
00140 
00141 void drawSnapping(const struct bContext *C, TransInfo *t)
00142 {
00143         if (validSnap(t) && activeSnap(t))
00144                 {
00145                 
00146                 unsigned char col[4];
00147                 UI_GetThemeColor3ubv(TH_TRANSFORM, col);
00148                 col[3]= 128;
00149                 glColor4ubv(col);
00150                 
00151                 if (t->spacetype == SPACE_VIEW3D) {
00152                         TransSnapPoint *p;
00153                         View3D *v3d = CTX_wm_view3d(C);
00154                         RegionView3D *rv3d = CTX_wm_region_view3d(C);
00155                         float imat[4][4];
00156                         float size;
00157                         
00158                         glDisable(GL_DEPTH_TEST);
00159         
00160                         size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
00161 
00162                         invert_m4_m4(imat, rv3d->viewmat);
00163 
00164                         for (p = t->tsnap.points.first; p; p = p->next) {
00165                                 drawcircball(GL_LINE_LOOP, p->co, ED_view3d_pixel_size(rv3d, p->co) * size, imat);
00166                         }
00167 
00168                         if (t->tsnap.status & POINT_INIT) {
00169                                 drawcircball(GL_LINE_LOOP, t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat);
00170                         }
00171                         
00172                         /* draw normal if needed */
00173                         if (usingSnappingNormal(t) && validSnappingNormal(t))
00174                         {
00175                                 glBegin(GL_LINES);
00176                                         glVertex3f(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]);
00177                                         glVertex3f(     t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0],
00178                                                                 t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1],
00179                                                                 t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]);
00180                                 glEnd();
00181                         }
00182                         
00183                         if(v3d->zbuf)
00184                                 glEnable(GL_DEPTH_TEST);
00185                 }
00186                 else if (t->spacetype==SPACE_IMAGE)
00187                 {
00188                         /*This will not draw, and Im nor sure why - campbell */
00189                         
00190                         /*                      
00191                         float xuser_asp, yuser_asp;
00192                         int wi, hi;
00193                         float w, h;
00194                         
00195                         calc_image_view(G.sima, 'f');   // float
00196                         myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
00197                         glLoadIdentity();
00198                         
00199                         ED_space_image_aspect(t->sa->spacedata.first, &xuser_aspx, &yuser_asp);
00200                         ED_space_image_width(t->sa->spacedata.first, &wi, &hi);
00201                         w = (((float)wi)/256.0f)*G.sima->zoom * xuser_asp;
00202                         h = (((float)hi)/256.0f)*G.sima->zoom * yuser_asp;
00203                         
00204                         cpack(0xFFFFFF);
00205                         glTranslatef(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], 0.0f);
00206                         
00207                         //glRectf(0,0,1,1);
00208                         
00209                         setlinestyle(0);
00210                         cpack(0x0);
00211                         fdrawline(-0.020/w, 0, -0.1/w, 0);
00212                         fdrawline(0.1/w, 0, .020/w, 0);
00213                         fdrawline(0, -0.020/h, 0, -0.1/h);
00214                         fdrawline(0, 0.1/h, 0, 0.020/h);
00215                         
00216                         glTranslatef(-t->tsnap.snapPoint[0], -t->tsnap.snapPoint[1], 0.0f);
00217                         setlinestyle(0);
00218                         */
00219                         
00220                 }
00221         }
00222 }
00223 
00224 int  handleSnapping(TransInfo *UNUSED(t), wmEvent *UNUSED(event))
00225 {
00226         int status = 0;
00227 
00228 #if 0 // XXX need a proper selector for all snap mode
00229         if (BIF_snappingSupported(t->obedit) && event->type == TABKEY && event->shift)
00230         {
00231                 /* toggle snap and reinit */
00232                 t->settings->snap_flag ^= SCE_SNAP;
00233                 initSnapping(t, NULL);
00234                 status = 1;
00235         }
00236 #endif
00237         
00238         return status;
00239 }
00240 
00241 void applyProject(TransInfo *t)
00242 {
00243         /* XXX FLICKER IN OBJECT MODE */
00244         if ((t->tsnap.project) && activeSnap(t) && (t->flag & T_NO_PROJECT) == 0)
00245         {
00246                 TransData *td = t->data;
00247                 float tvec[3];
00248                 float imat[4][4];
00249                 int i;
00250         
00251                 if(t->flag & (T_EDIT|T_POSE)) {
00252                         Object *ob = t->obedit?t->obedit:t->poseobj;
00253                         invert_m4_m4(imat, ob->obmat);
00254                 }
00255 
00256                 for(i = 0 ; i < t->total; i++, td++) {
00257                         float iloc[3], loc[3], no[3];
00258                         float mval[2];
00259                         int dist = 1000;
00260                         
00261                         if (td->flag & TD_NOACTION)
00262                                 break;
00263                         
00264                         if (td->flag & TD_SKIP)
00265                                 continue;
00266                         
00267                         VECCOPY(iloc, td->loc);
00268                         if (t->flag & (T_EDIT|T_POSE))
00269                         {
00270                                 Object *ob = t->obedit?t->obedit:t->poseobj;
00271                                 mul_m4_v3(ob->obmat, iloc);
00272                         }
00273                         else if (t->flag & T_OBJECT)
00274                         {
00275                                 td->ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
00276                                 object_handle_update(t->scene, td->ob);
00277                                 VECCOPY(iloc, td->ob->obmat[3]);
00278                         }
00279                         
00280                         project_float(t->ar, iloc, mval);
00281                         
00282                         if (snapObjectsTransform(t, mval, &dist, loc, no, t->tsnap.modeSelect))
00283                         {
00284 //                              if(t->flag & (T_EDIT|T_POSE)) {
00285 //                                      mul_m4_v3(imat, loc);
00286 //                              }
00287 //                              
00288                                 sub_v3_v3v3(tvec, loc, iloc);
00289                                 
00290                                 mul_m3_v3(td->smtx, tvec);
00291                                 
00292                                 add_v3_v3(td->loc, tvec);
00293                         }
00294                         
00295                         //XXX constraintTransLim(t, td);
00296                 }
00297         }
00298 }
00299 
00300 void applySnapping(TransInfo *t, float *vec)
00301 {
00302         /* project is not applied this way */
00303         if (t->tsnap.project)
00304                 return;
00305         
00306         if (t->tsnap.status & SNAP_FORCED)
00307         {
00308                 t->tsnap.targetSnap(t);
00309         
00310                 t->tsnap.applySnap(t, vec);
00311         }
00312         else if ((t->tsnap.mode != SCE_SNAP_MODE_INCREMENT) && activeSnap(t))
00313         {
00314                 double current = PIL_check_seconds_timer();
00315                 
00316                 // Time base quirky code to go around findnearest slowness
00317                 /* !TODO! add exception for object mode, no need to slow it down then */
00318                 if (current - t->tsnap.last  >= 0.01)
00319                 {
00320                         t->tsnap.calcSnap(t, vec);
00321                         t->tsnap.targetSnap(t);
00322         
00323                         t->tsnap.last = current;
00324                 }
00325                 if (validSnap(t))
00326                 {
00327                         t->tsnap.applySnap(t, vec);
00328                 }
00329         }
00330 }
00331 
00332 void resetSnapping(TransInfo *t)
00333 {
00334         t->tsnap.status = 0;
00335         t->tsnap.align = 0;
00336         t->tsnap.project = 0;
00337         t->tsnap.mode = 0;
00338         t->tsnap.modeSelect = 0;
00339         t->tsnap.target = 0;
00340         t->tsnap.last = 0;
00341         t->tsnap.applySnap = NULL;
00342 
00343         t->tsnap.snapNormal[0] = 0;
00344         t->tsnap.snapNormal[1] = 0;
00345         t->tsnap.snapNormal[2] = 0;
00346 }
00347 
00348 int usingSnappingNormal(TransInfo *t)
00349 {
00350         return t->tsnap.align;
00351 }
00352 
00353 int validSnappingNormal(TransInfo *t)
00354 {
00355         if (validSnap(t))
00356         {
00357                 if (dot_v3v3(t->tsnap.snapNormal, t->tsnap.snapNormal) > 0)
00358                 {
00359                         return 1;
00360                 }
00361         }
00362         
00363         return 0;
00364 }
00365 
00366 static void initSnappingMode(TransInfo *t)
00367 {
00368         ToolSettings *ts = t->settings;
00369         Object *obedit = t->obedit;
00370         Scene *scene = t->scene;
00371 
00372         /* force project off when not supported */
00373         if (ts->snap_mode != SCE_SNAP_MODE_FACE)
00374         {
00375                 t->tsnap.project = 0;
00376         }
00377 
00378         t->tsnap.mode = ts->snap_mode;
00379 
00380         if ((t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) && // Only 3D view or UV
00381                         (t->flag & T_CAMERA) == 0) { // Not with camera selected in camera view
00382                 setSnappingCallback(t);
00383 
00384                 /* Edit mode */
00385                 if (t->tsnap.applySnap != NULL && // A snapping function actually exist
00386                         (obedit != NULL && ELEM4(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE)) ) // Temporary limited to edit mode meshes, armature, curves
00387                 {
00388                         /* Exclude editmesh if using proportional edit */
00389                         if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT))
00390                         {
00391                                 t->tsnap.modeSelect = SNAP_NOT_OBEDIT;
00392                         }
00393                         else
00394                         {
00395                                 t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_OBEDIT;
00396                         }
00397                 }
00398                 /* Particles edit mode*/
00399                 else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
00400                         (obedit == NULL && BASACT && BASACT->object && BASACT->object->mode & OB_MODE_PARTICLE_EDIT ))
00401                 {
00402                         t->tsnap.modeSelect = SNAP_ALL;
00403                 }
00404                 /* Object mode */
00405                 else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
00406                         (obedit == NULL) ) // Object Mode
00407                 {
00408                         t->tsnap.modeSelect = SNAP_NOT_SELECTED;
00409                 }
00410                 else
00411                 {
00412                         /* Grid if snap is not possible */
00413                         t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
00414                 }
00415         }
00416         else
00417         {
00418                 /* Always grid outside of 3D view */
00419                 t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
00420         }
00421 }
00422 
00423 void initSnapping(TransInfo *t, wmOperator *op)
00424 {
00425         ToolSettings *ts = t->settings;
00426         short snap_target = t->settings->snap_target;
00427         
00428         resetSnapping(t);
00429         
00430         /* if snap property exists */
00431         if (op && RNA_struct_find_property(op->ptr, "snap") && RNA_property_is_set(op->ptr, "snap"))
00432         {
00433                 if (RNA_boolean_get(op->ptr, "snap"))
00434                 {
00435                         t->modifiers |= MOD_SNAP;
00436 
00437                         if (RNA_property_is_set(op->ptr, "snap_target"))
00438                         {
00439                                 snap_target = RNA_enum_get(op->ptr, "snap_target");
00440                         }
00441                         
00442                         if (RNA_property_is_set(op->ptr, "snap_point"))
00443                         {
00444                                 RNA_float_get_array(op->ptr, "snap_point", t->tsnap.snapPoint);
00445                                 t->tsnap.status |= SNAP_FORCED|POINT_INIT;
00446                         }
00447                         
00448                         /* snap align only defined in specific cases */
00449                         if (RNA_struct_find_property(op->ptr, "snap_align"))
00450                         {
00451                                 t->tsnap.align = RNA_boolean_get(op->ptr, "snap_align");
00452                                 RNA_float_get_array(op->ptr, "snap_normal", t->tsnap.snapNormal);
00453                                 normalize_v3(t->tsnap.snapNormal);
00454                         }
00455 
00456                         if (RNA_struct_find_property(op->ptr, "use_snap_project"))
00457                         {
00458                                 t->tsnap.project = RNA_boolean_get(op->ptr, "use_snap_project");
00459                         }
00460 
00461                         if (RNA_struct_find_property(op->ptr, "use_snap_self"))
00462                         {
00463                                 t->tsnap.snap_self = RNA_boolean_get(op->ptr, "use_snap_self");
00464                         }
00465                 }
00466         }
00467         /* use scene defaults only when transform is modal */
00468         else if (t->flag & T_MODAL)
00469         {
00470                 if(ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE))
00471                 {
00472                         if (ts->snap_flag & SCE_SNAP) {
00473                                 t->modifiers |= MOD_SNAP;
00474                         }
00475 
00476                         t->tsnap.align = ((t->settings->snap_flag & SCE_SNAP_ROTATE) == SCE_SNAP_ROTATE);
00477                         t->tsnap.project = ((t->settings->snap_flag & SCE_SNAP_PROJECT) == SCE_SNAP_PROJECT);
00478                         t->tsnap.snap_self = !((t->settings->snap_flag & SCE_SNAP_NO_SELF) == SCE_SNAP_NO_SELF);
00479                         t->tsnap.peel = ((t->settings->snap_flag & SCE_SNAP_PROJECT) == SCE_SNAP_PROJECT);
00480                 }
00481         }
00482         
00483         t->tsnap.target = snap_target;
00484 
00485         initSnappingMode(t);
00486 }
00487 
00488 void setSnappingCallback(TransInfo *t)
00489 {
00490         t->tsnap.calcSnap = CalcSnapGeometry;
00491 
00492         switch(t->tsnap.target)
00493         {
00494                 case SCE_SNAP_TARGET_CLOSEST:
00495                         t->tsnap.targetSnap = TargetSnapClosest;
00496                         break;
00497                 case SCE_SNAP_TARGET_CENTER:
00498                         t->tsnap.targetSnap = TargetSnapCenter;
00499                         break;
00500                 case SCE_SNAP_TARGET_MEDIAN:
00501                         t->tsnap.targetSnap = TargetSnapMedian;
00502                         break;
00503                 case SCE_SNAP_TARGET_ACTIVE:
00504                         t->tsnap.targetSnap = TargetSnapActive;
00505                         break;
00506 
00507         }
00508 
00509         switch (t->mode)
00510         {
00511         case TFM_TRANSLATION:
00512                 t->tsnap.applySnap = ApplySnapTranslation;
00513                 t->tsnap.distance = TranslationBetween;
00514                 break;
00515         case TFM_ROTATION:
00516                 t->tsnap.applySnap = ApplySnapRotation;
00517                 t->tsnap.distance = RotationBetween;
00518                 
00519                 // Can't do TARGET_CENTER with rotation, use TARGET_MEDIAN instead
00520                 if (t->tsnap.target == SCE_SNAP_TARGET_CENTER) {
00521                         t->tsnap.target = SCE_SNAP_TARGET_MEDIAN;
00522                         t->tsnap.targetSnap = TargetSnapMedian;
00523                 }
00524                 break;
00525         case TFM_RESIZE:
00526                 t->tsnap.applySnap = ApplySnapResize;
00527                 t->tsnap.distance = ResizeBetween;
00528                 
00529                 // Can't do TARGET_CENTER with resize, use TARGET_MEDIAN instead
00530                 if (t->tsnap.target == SCE_SNAP_TARGET_CENTER) {
00531                         t->tsnap.target = SCE_SNAP_TARGET_MEDIAN;
00532                         t->tsnap.targetSnap = TargetSnapMedian;
00533                 }
00534                 break;
00535         default:
00536                 t->tsnap.applySnap = NULL;
00537                 break;
00538         }
00539 }
00540 
00541 void addSnapPoint(TransInfo *t)
00542 {
00543         if (t->tsnap.status & POINT_INIT) {
00544                 TransSnapPoint *p = MEM_callocN(sizeof(TransSnapPoint), "SnapPoint");
00545 
00546                 VECCOPY(p->co, t->tsnap.snapPoint);
00547 
00548                 BLI_addtail(&t->tsnap.points, p);
00549 
00550                 t->tsnap.status |= MULTI_POINTS;
00551         }
00552 }
00553 
00554 void removeSnapPoint(TransInfo *t)
00555 {
00556         if (t->tsnap.status & MULTI_POINTS) {
00557                 BLI_freelinkN(&t->tsnap.points, t->tsnap.points.last);
00558 
00559                 if (t->tsnap.points.first == NULL)
00560                         t->tsnap.status &= ~MULTI_POINTS;
00561         }
00562 }
00563 
00564 void getSnapPoint(TransInfo *t, float vec[3])
00565 {
00566         if (t->tsnap.points.first) {
00567                 TransSnapPoint *p;
00568                 int total = 0;
00569 
00570                 vec[0] = vec[1] = vec[2] = 0;
00571 
00572                 for (p = t->tsnap.points.first; p; p = p->next, total++) {
00573                         add_v3_v3(vec, p->co);
00574                 }
00575 
00576                 if (t->tsnap.status & POINT_INIT) {
00577                         add_v3_v3(vec, t->tsnap.snapPoint);
00578                         total++;
00579                 }
00580 
00581                 mul_v3_fl(vec, 1.0f / total);
00582         } else {
00583                 VECCOPY(vec, t->tsnap.snapPoint)
00584         }
00585 }
00586 
00587 /********************** APPLY **************************/
00588 
00589 void ApplySnapTranslation(TransInfo *t, float vec[3])
00590 {
00591         float point[3];
00592         getSnapPoint(t, point);
00593         sub_v3_v3v3(vec, point, t->tsnap.snapTarget);
00594 }
00595 
00596 void ApplySnapRotation(TransInfo *t, float *vec)
00597 {
00598         if (t->tsnap.target == SCE_SNAP_TARGET_CLOSEST) {
00599                 *vec = t->tsnap.dist;
00600         }
00601         else {
00602                 float point[3];
00603                 getSnapPoint(t, point);
00604                 *vec = RotationBetween(t, t->tsnap.snapTarget, point);
00605         }
00606 }
00607 
00608 void ApplySnapResize(TransInfo *t, float vec[3])
00609 {
00610         if (t->tsnap.target == SCE_SNAP_TARGET_CLOSEST) {
00611                 vec[0] = vec[1] = vec[2] = t->tsnap.dist;
00612         }
00613         else {
00614                 float point[3];
00615                 getSnapPoint(t, point);
00616                 vec[0] = vec[1] = vec[2] = ResizeBetween(t, t->tsnap.snapTarget, point);
00617         }
00618 }
00619 
00620 /********************** DISTANCE **************************/
00621 
00622 float TranslationBetween(TransInfo *UNUSED(t), float p1[3], float p2[3])
00623 {
00624         return len_v3v3(p1, p2);
00625 }
00626 
00627 float RotationBetween(TransInfo *t, float p1[3], float p2[3])
00628 {
00629         float angle, start[3], end[3], center[3];
00630         
00631         VECCOPY(center, t->center);     
00632         if(t->flag & (T_EDIT|T_POSE)) {
00633                 Object *ob= t->obedit?t->obedit:t->poseobj;
00634                 mul_m4_v3(ob->obmat, center);
00635         }
00636 
00637         sub_v3_v3v3(start, p1, center);
00638         sub_v3_v3v3(end, p2, center);   
00639                 
00640         // Angle around a constraint axis (error prone, will need debug)
00641         if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
00642                 float axis[3], tmp[3];
00643                 
00644                 t->con.applyRot(t, NULL, axis, NULL);
00645 
00646                 project_v3_v3v3(tmp, end, axis);
00647                 sub_v3_v3v3(end, end, tmp);
00648                 
00649                 project_v3_v3v3(tmp, start, axis);
00650                 sub_v3_v3v3(start, start, tmp);
00651                 
00652                 normalize_v3(end);
00653                 normalize_v3(start);
00654                 
00655                 cross_v3_v3v3(tmp, start, end);
00656                 
00657                 if (dot_v3v3(tmp, axis) < 0.0f)
00658                         angle = -acos(dot_v3v3(start, end));
00659                 else    
00660                         angle = acos(dot_v3v3(start, end));
00661         }
00662         else {
00663                 float mtx[3][3];
00664                 
00665                 copy_m3_m4(mtx, t->viewmat);
00666 
00667                 mul_m3_v3(mtx, end);
00668                 mul_m3_v3(mtx, start);
00669                 
00670                 angle = atan2(start[1],start[0]) - atan2(end[1],end[0]);
00671         }
00672         
00673         if (angle > (float)M_PI) {
00674                 angle = angle - 2 * (float)M_PI;
00675         }
00676         else if (angle < -((float)M_PI)) {
00677                 angle = 2.0f * (float)M_PI + angle;
00678         }
00679         
00680         return angle;
00681 }
00682 
00683 float ResizeBetween(TransInfo *t, float p1[3], float p2[3])
00684 {
00685         float d1[3], d2[3], center[3];
00686         
00687         VECCOPY(center, t->center);     
00688         if(t->flag & (T_EDIT|T_POSE)) {
00689                 Object *ob= t->obedit?t->obedit:t->poseobj;
00690                 mul_m4_v3(ob->obmat, center);
00691         }
00692 
00693         sub_v3_v3v3(d1, p1, center);
00694         sub_v3_v3v3(d2, p2, center);
00695         
00696         if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
00697                 mul_m3_v3(t->con.pmtx, d1);
00698                 mul_m3_v3(t->con.pmtx, d2);
00699         }
00700         
00701         return len_v3(d2) / len_v3(d1);
00702 }
00703 
00704 /********************** CALC **************************/
00705 
00706 void CalcSnapGrid(TransInfo *t, float *UNUSED(vec))
00707 {
00708         snapGridAction(t, t->tsnap.snapPoint, BIG_GEARS);
00709 }
00710 
00711 void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
00712 {
00713         if (t->spacetype == SPACE_VIEW3D)
00714         {
00715                 float loc[3];
00716                 float no[3];
00717                 float mval[2];
00718                 int found = 0;
00719                 int dist = SNAP_MIN_DISTANCE; // Use a user defined value here
00720                 
00721                 mval[0] = t->mval[0];
00722                 mval[1] = t->mval[1];
00723                 
00724                 if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME)
00725                 {
00726                         ListBase depth_peels;
00727                         DepthPeel *p1, *p2;
00728                         float *last_p = NULL;
00729                         float max_dist = FLT_MAX;
00730                         float p[3] = {0.0f, 0.0f, 0.0f};
00731                         
00732                         depth_peels.first = depth_peels.last = NULL;
00733                         
00734                         peelObjectsTransForm(t, &depth_peels, mval);
00735                         
00736 //                      if (LAST_SNAP_POINT_VALID)
00737 //                      {
00738 //                              last_p = LAST_SNAP_POINT;
00739 //                      }
00740 //                      else
00741 //                      {
00742                                 last_p = t->tsnap.snapPoint;
00743 //                      }
00744                         
00745                         
00746                         for (p1 = depth_peels.first; p1; p1 = p1->next)
00747                         {
00748                                 if (p1->flag == 0)
00749                                 {
00750                                         float vec[3];
00751                                         float new_dist;
00752                                         
00753                                         p2 = NULL;
00754                                         p1->flag = 1;
00755                 
00756                                         /* if peeling objects, take the first and last from each object */                      
00757                                         if (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT)
00758                                         {
00759                                                 DepthPeel *peel;
00760                                                 for (peel = p1->next; peel; peel = peel->next)
00761                                                 {
00762                                                         if (peel->ob == p1->ob)
00763                                                         {
00764                                                                 peel->flag = 1;
00765                                                                 p2 = peel;
00766                                                         }
00767                                                 }
00768                                         }
00769                                         /* otherwise, pair first with second and so on */
00770                                         else
00771                                         {
00772                                                 for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next)
00773                                                 {
00774                                                         /* nothing to do here */
00775                                                 }
00776                                         }
00777                                         
00778                                         if (p2)
00779                                         {
00780                                                 p2->flag = 1;
00781                                                 
00782                                                 add_v3_v3v3(vec, p1->p, p2->p);
00783                                                 mul_v3_fl(vec, 0.5f);
00784                                         }
00785                                         else
00786                                         {
00787                                                 VECCOPY(vec, p1->p);
00788                                         }
00789                                         
00790                                         if (last_p == NULL)
00791                                         {
00792                                                 VECCOPY(p, vec);
00793                                                 max_dist = 0;
00794                                                 break;
00795                                         }
00796                                         
00797                                         new_dist = len_v3v3(last_p, vec);
00798                                         
00799                                         if (new_dist < max_dist)
00800                                         {
00801                                                 VECCOPY(p, vec);
00802                                                 max_dist = new_dist;
00803                                         }
00804                                 }
00805                         }
00806                         
00807                         if (max_dist != FLT_MAX)
00808                         {
00809                                 VECCOPY(loc, p);
00810                                 /* XXX, is there a correct normal in this case ???, for now just z up */
00811                                 no[0]= 0.0;
00812                                 no[1]= 0.0;
00813                                 no[2]= 1.0;
00814                                 found = 1;
00815                         }
00816                         
00817                         BLI_freelistN(&depth_peels);
00818                 }
00819                 else
00820                 {
00821                         found = snapObjectsTransform(t, mval, &dist, loc, no, t->tsnap.modeSelect);
00822                 }
00823                 
00824                 if (found == 1)
00825                 {
00826                         float tangent[3];
00827                         
00828                         sub_v3_v3v3(tangent, loc, t->tsnap.snapPoint);
00829                         tangent[2] = 0; 
00830                         
00831                         if (dot_v3v3(tangent, tangent) > 0)
00832                         {
00833                                 VECCOPY(t->tsnap.snapTangent, tangent);
00834                         }
00835                         
00836                         VECCOPY(t->tsnap.snapPoint, loc);
00837                         VECCOPY(t->tsnap.snapNormal, no);
00838 
00839                         t->tsnap.status |=  POINT_INIT;
00840                 }
00841                 else
00842                 {
00843                         t->tsnap.status &= ~POINT_INIT;
00844                 }
00845         }
00846         else if (t->spacetype == SPACE_IMAGE && t->obedit != NULL && t->obedit->type==OB_MESH)
00847         {       /* same as above but for UV's */
00848                 /* same as above but for UV's */
00849                 Image *ima= ED_space_image(t->sa->spacedata.first);
00850                 float aspx, aspy, co[2];
00851                 
00852                 UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], co, co+1);
00853 
00854                 if(ED_uvedit_nearest_uv(t->scene, t->obedit, ima, co, t->tsnap.snapPoint))
00855                 {
00856                         ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
00857                         t->tsnap.snapPoint[0] *= aspx;
00858                         t->tsnap.snapPoint[1] *= aspy;
00859 
00860                         t->tsnap.status |=  POINT_INIT;
00861                 }
00862                 else
00863                 {
00864                         t->tsnap.status &= ~POINT_INIT;
00865                 }
00866         }
00867 }
00868 
00869 /********************** TARGET **************************/
00870 
00871 void TargetSnapCenter(TransInfo *t)
00872 {
00873         // Only need to calculate once
00874         if ((t->tsnap.status & TARGET_INIT) == 0)
00875         {
00876                 VECCOPY(t->tsnap.snapTarget, t->center);        
00877                 if(t->flag & (T_EDIT|T_POSE)) {
00878                         Object *ob= t->obedit?t->obedit:t->poseobj;
00879                         mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
00880                 }
00881                 
00882                 t->tsnap.status |= TARGET_INIT;         
00883         }
00884 }
00885 
00886 void TargetSnapActive(TransInfo *t)
00887 {
00888         // Only need to calculate once
00889         if ((t->tsnap.status & TARGET_INIT) == 0)
00890         {
00891                 TransData *td = NULL;
00892                 TransData *active_td = NULL;
00893                 int i;
00894 
00895                 for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
00896                 {
00897                         if (td->flag & TD_ACTIVE)
00898                         {
00899                                 active_td = td;
00900                                 break;
00901                         }
00902                 }
00903 
00904                 if (active_td)
00905                 {       
00906                         VECCOPY(t->tsnap.snapTarget, active_td->center);
00907                                 
00908                         if(t->flag & (T_EDIT|T_POSE)) {
00909                                 Object *ob= t->obedit?t->obedit:t->poseobj;
00910                                 mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
00911                         }
00912                         
00913                         t->tsnap.status |= TARGET_INIT;
00914                 }
00915                 /* No active, default to median */
00916                 else
00917                 {
00918                         t->tsnap.target = SCE_SNAP_TARGET_MEDIAN;
00919                         t->tsnap.targetSnap = TargetSnapMedian;
00920                         TargetSnapMedian(t);
00921                 }               
00922         }
00923 }
00924 
00925 void TargetSnapMedian(TransInfo *t)
00926 {
00927         // Only need to calculate once
00928         if ((t->tsnap.status & TARGET_INIT) == 0)
00929         {
00930                 TransData *td = NULL;
00931                 int i;
00932 
00933                 t->tsnap.snapTarget[0] = 0;
00934                 t->tsnap.snapTarget[1] = 0;
00935                 t->tsnap.snapTarget[2] = 0;
00936                 
00937                 for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
00938                 {
00939                         add_v3_v3(t->tsnap.snapTarget, td->center);
00940                 }
00941                 
00942                 mul_v3_fl(t->tsnap.snapTarget, 1.0 / i);
00943                 
00944                 if(t->flag & (T_EDIT|T_POSE)) {
00945                         Object *ob= t->obedit?t->obedit:t->poseobj;
00946                         mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
00947                 }
00948                 
00949                 t->tsnap.status |= TARGET_INIT;         
00950         }
00951 }
00952 
00953 void TargetSnapClosest(TransInfo *t)
00954 {
00955         // Only valid if a snap point has been selected
00956         if (t->tsnap.status & POINT_INIT)
00957         {
00958                 TransData *closest = NULL, *td = NULL;
00959                 
00960                 /* Object mode */
00961                 if (t->flag & T_OBJECT)
00962                 {
00963                         int i;
00964                         for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
00965                         {
00966                                 struct BoundBox *bb = object_get_boundbox(td->ob);
00967                                 
00968                                 /* use boundbox if possible */
00969                                 if (bb)
00970                                 {
00971                                         int j;
00972                                         
00973                                         for (j = 0; j < 8; j++) {
00974                                                 float loc[3];
00975                                                 float dist;
00976                                                 
00977                                                 VECCOPY(loc, bb->vec[j]);
00978                                                 mul_m4_v3(td->ext->obmat, loc);
00979                                                 
00980                                                 dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
00981                                                 
00982                                                 if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist))
00983                                                 {
00984                                                         VECCOPY(t->tsnap.snapTarget, loc);
00985                                                         closest = td;
00986                                                         t->tsnap.dist = dist; 
00987                                                 }
00988                                         }
00989                                 }
00990                                 /* use element center otherwise */
00991                                 else
00992                                 {
00993                                         float loc[3];
00994                                         float dist;
00995                                         
00996                                         VECCOPY(loc, td->center);
00997                                         
00998                                         dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
00999                                         
01000                                         if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist))
01001                                         {
01002                                                 VECCOPY(t->tsnap.snapTarget, loc);
01003                                                 closest = td;
01004                                                 t->tsnap.dist = dist; 
01005                                         }
01006                                 }
01007                         }
01008                 }
01009                 else
01010                 {
01011                         int i;
01012                         for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
01013                         {
01014                                 float loc[3];
01015                                 float dist;
01016                                 
01017                                 VECCOPY(loc, td->center);
01018                                 
01019                                 if(t->flag & (T_EDIT|T_POSE)) {
01020                                         Object *ob= t->obedit?t->obedit:t->poseobj;
01021                                         mul_m4_v3(ob->obmat, loc);
01022                                 }
01023                                 
01024                                 dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
01025                                 
01026                                 if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist))
01027                                 {
01028                                         VECCOPY(t->tsnap.snapTarget, loc);
01029                                         closest = td;
01030                                         t->tsnap.dist = dist; 
01031                                 }
01032                         }
01033                 }
01034                 
01035                 t->tsnap.status |= TARGET_INIT;
01036         }
01037 }
01038 /*================================================================*/
01039 #ifndef USE_BVH_FACE_SNAP
01040 static 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)
01041 {
01042         float lambda;
01043         int result;
01044         int retval = 0;
01045         
01046         result = isect_ray_tri_threshold_v3(ray_start_local, ray_normal_local, v1co, v2co, v3co, &lambda, NULL, 0.001);
01047         
01048         if (result) {
01049                 float location[3], normal[3];
01050                 float intersect[3];
01051                 float new_depth;
01052                 int screen_loc[2];
01053                 int new_dist;
01054                 
01055                 VECCOPY(intersect, ray_normal_local);
01056                 mul_v3_fl(intersect, lambda);
01057                 add_v3_v3(intersect, ray_start_local);
01058                 
01059                 VECCOPY(location, intersect);
01060                 
01061                 if (v4co)
01062                         normal_quad_v3( normal,v1co, v2co, v3co, v4co);
01063                 else
01064                         normal_tri_v3( normal,v1co, v2co, v3co);
01065 
01066                 mul_m4_v3(obmat, location);
01067                 
01068                 new_depth = len_v3v3(location, ray_start);                                      
01069                 
01070                 project_int(ar, location, screen_loc);
01071                 new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]);
01072                 
01073                 if (new_dist <= *dist && new_depth < *depth) 
01074                 {
01075                         *depth = new_depth;
01076                         retval = 1;
01077                         
01078                         VECCOPY(loc, location);
01079                         VECCOPY(no, normal);
01080                         
01081                         mul_m3_v3(timat, no);
01082                         normalize_v3(no);
01083 
01084                         *dist = new_dist;
01085                 } 
01086         }
01087         
01088         return retval;
01089 }
01090 #endif
01091 
01092 static 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)
01093 {
01094         float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
01095         int result;
01096         int retval = 0;
01097         
01098         VECCOPY(ray_end, ray_normal_local);
01099         mul_v3_fl(ray_end, 2000);
01100         add_v3_v3v3(ray_end, ray_start_local, ray_end);
01101         
01102         result = isect_line_line_v3(v1co, v2co, ray_start_local, ray_end, intersect, dvec); /* dvec used but we don't care about result */
01103         
01104         if (result)
01105         {
01106                 float edge_loc[3], vec[3];
01107                 float mul;
01108         
01109                 /* check for behind ray_start */
01110                 sub_v3_v3v3(dvec, intersect, ray_start_local);
01111                 
01112                 sub_v3_v3v3(edge_loc, v1co, v2co);
01113                 sub_v3_v3v3(vec, intersect, v2co);
01114                 
01115                 mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
01116                 
01117                 if (mul > 1) {
01118                         mul = 1;
01119                         VECCOPY(intersect, v1co);
01120                 }
01121                 else if (mul < 0) {
01122                         mul = 0;
01123                         VECCOPY(intersect, v2co);
01124                 }
01125 
01126                 if (dot_v3v3(ray_normal_local, dvec) > 0)
01127                 {
01128                         float location[3];
01129                         float new_depth;
01130                         int screen_loc[2];
01131                         int new_dist;
01132                         
01133                         VECCOPY(location, intersect);
01134                         
01135                         mul_m4_v3(obmat, location);
01136                         
01137                         new_depth = len_v3v3(location, ray_start);                                      
01138                         
01139                         project_int(ar, location, screen_loc);
01140                         new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]);
01141                         
01142                         /* 10% threshold if edge is closer but a bit further
01143                          * this takes care of series of connected edges a bit slanted w.r.t the viewport
01144                          * otherwise, it would stick to the verts of the closest edge and not slide along merrily 
01145                          * */
01146                         if (new_dist <= *dist && new_depth < *depth * 1.001f)
01147                         {
01148                                 float n1[3], n2[3];
01149                                 
01150                                 *depth = new_depth;
01151                                 retval = 1;
01152                                 
01153                                 sub_v3_v3v3(edge_loc, v1co, v2co);
01154                                 sub_v3_v3v3(vec, intersect, v2co);
01155                                 
01156                                 mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
01157                                 
01158                                 if (no)
01159                                 {
01160                                         normal_short_to_float_v3(n1, v1no);                                             
01161                                         normal_short_to_float_v3(n2, v2no);
01162                                         interp_v3_v3v3(no, n2, n1, mul);
01163                                         mul_m3_v3(timat, no);
01164                                         normalize_v3(no);
01165                                 }                       
01166 
01167                                 VECCOPY(loc, location);
01168                                 
01169                                 *dist = new_dist;
01170                         } 
01171                 }
01172         }
01173         
01174         return retval;
01175 }
01176 
01177 static 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)
01178 {
01179         int retval = 0;
01180         float dvec[3];
01181         
01182         sub_v3_v3v3(dvec, vco, ray_start_local);
01183         
01184         if (dot_v3v3(ray_normal_local, dvec) > 0)
01185         {
01186                 float location[3];
01187                 float new_depth;
01188                 int screen_loc[2];
01189                 int new_dist;
01190                 
01191                 VECCOPY(location, vco);
01192                 
01193                 mul_m4_v3(obmat, location);
01194                 
01195                 new_depth = len_v3v3(location, ray_start);                                      
01196                 
01197                 project_int(ar, location, screen_loc);
01198                 new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]);
01199                 
01200                 if (new_dist <= *dist && new_depth < *depth)
01201                 {
01202                         *depth = new_depth;
01203                         retval = 1;
01204                         
01205                         VECCOPY(loc, location);
01206                         
01207                         if (no)
01208                         {
01209                                 normal_short_to_float_v3(no, vno);
01210                                 mul_m3_v3(timat, no);
01211                                 normalize_v3(no);
01212                         }
01213 
01214                         *dist = new_dist;
01215                 } 
01216         }
01217         
01218         return retval;
01219 }
01220 
01221 static 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 *UNUSED(no), int *dist, float *depth)
01222 {
01223         float imat[4][4];
01224         float ray_start_local[3], ray_normal_local[3];
01225         int retval = 0;
01226 
01227         invert_m4_m4(imat, obmat);
01228 
01229         VECCOPY(ray_start_local, ray_start);
01230         VECCOPY(ray_normal_local, ray_normal);
01231         
01232         mul_m4_v3(imat, ray_start_local);
01233         mul_mat3_m4_v3(imat, ray_normal_local);
01234 
01235         if(arm->edbo)
01236         {
01237                 EditBone *eBone;
01238 
01239                 for (eBone=arm->edbo->first; eBone; eBone=eBone->next) {
01240                         if (eBone->layer & arm->layer) {
01241                                 /* skip hidden or moving (selected) bones */
01242                                 if ((eBone->flag & (BONE_HIDDEN_A|BONE_ROOTSEL|BONE_TIPSEL))==0) {
01243                                         switch (snap_mode)
01244                                         {
01245                                                 case SCE_SNAP_MODE_VERTEX:
01246                                                         retval |= snapVertex(ar, eBone->head, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
01247                                                         retval |= snapVertex(ar, eBone->tail, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
01248                                                         break;
01249                                                 case SCE_SNAP_MODE_EDGE:
01250                                                         retval |= snapEdge(ar, eBone->head, NULL, eBone->tail, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
01251                                                         break;
01252                                         }
01253                                 }
01254                         }
01255                 }
01256         }
01257         else if (ob->pose && ob->pose->chanbase.first)
01258         {
01259                 bPoseChannel *pchan;
01260                 Bone *bone;
01261                 
01262                 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
01263                         bone= pchan->bone;
01264                         /* skip hidden bones */
01265                         if (bone && !(bone->flag & (BONE_HIDDEN_P|BONE_HIDDEN_PG))) {
01266                                 float *head_vec = pchan->pose_head;
01267                                 float *tail_vec = pchan->pose_tail;
01268                                 
01269                                 switch (snap_mode)
01270                                 {
01271                                         case SCE_SNAP_MODE_VERTEX:
01272                                                 retval |= snapVertex(ar, head_vec, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
01273                                                 retval |= snapVertex(ar, tail_vec, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
01274                                                 break;
01275                                         case SCE_SNAP_MODE_EDGE:
01276                                                 retval |= snapEdge(ar, head_vec, NULL, tail_vec, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
01277                                                 break;
01278                                 }
01279                         }
01280                 }
01281         }
01282 
01283         return retval;
01284 }
01285 
01286 static 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)
01287 {
01288         int retval = 0;
01289         int totvert = dm->getNumVerts(dm);
01290         int totface = dm->getNumFaces(dm);
01291 
01292         if (totvert > 0) {
01293                 float imat[4][4];
01294                 float timat[3][3]; /* transpose inverse matrix for normals */
01295                 float ray_start_local[3], ray_normal_local[3];
01296                 int test = 1;
01297 
01298                 invert_m4_m4(imat, obmat);
01299 
01300                 copy_m3_m4(timat, imat);
01301                 transpose_m3(timat);
01302                 
01303                 VECCOPY(ray_start_local, ray_start);
01304                 VECCOPY(ray_normal_local, ray_normal);
01305                 
01306                 mul_m4_v3(imat, ray_start_local);
01307                 mul_mat3_m4_v3(imat, ray_normal_local);
01308                 
01309                 
01310                 /* If number of vert is more than an arbitrary limit, 
01311                  * test against boundbox first
01312                  * */
01313                 if (totface > 16) {
01314                         struct BoundBox *bb = object_get_boundbox(ob);
01315                         test = ray_hit_boundbox(bb, ray_start_local, ray_normal_local);
01316                 }
01317                 
01318                 if (test == 1) {
01319                         
01320                         switch (snap_mode)
01321                         {
01322                                 case SCE_SNAP_MODE_FACE:
01323                                 { 
01324 #ifdef USE_BVH_FACE_SNAP                                // Added for durian
01325                                         BVHTreeRayHit hit;
01326                                         BVHTreeFromMesh treeData;
01327 
01328                                         /* local scale in normal direction */
01329                                         float local_scale = len_v3(ray_normal_local);
01330 
01331                                         treeData.em_evil= em;
01332                                         bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 6);
01333 
01334                                         hit.index = -1;
01335                                         hit.dist = *depth * (*depth == FLT_MAX ? 1.0f : local_scale);
01336 
01337                                         if(treeData.tree && BLI_bvhtree_ray_cast(treeData.tree, ray_start_local, ray_normal_local, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1)
01338                                         {
01339                                                 if(hit.dist/local_scale <= *depth) {
01340                                                         *depth= hit.dist/local_scale;
01341                                                         copy_v3_v3(loc, hit.co);
01342                                                         copy_v3_v3(no, hit.no);
01343 
01344                                                         /* back to worldspace */
01345                                                         mul_m4_v3(obmat, loc);
01346                                                         copy_v3_v3(no, hit.no);
01347 
01348                                                         mul_m3_v3(timat, no);
01349                                                         normalize_v3(no);
01350 
01351                                                         retval |= 1;
01352                                                 }
01353                                         }
01354                                         break;
01355 
01356 #else
01357                                         MVert *verts = dm->getVertArray(dm);
01358                                         MFace *faces = dm->getFaceArray(dm);
01359                                         int *index_array = NULL;
01360                                         int index = 0;
01361                                         int i;
01362                                         
01363                                         if (em != NULL)
01364                                         {
01365                                                 index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX);
01366                                                 EM_init_index_arrays(em, 0, 0, 1);
01367                                         }
01368                                         
01369                                         for( i = 0; i < totface; i++) {
01370                                                 EditFace *efa = NULL;
01371                                                 MFace *f = faces + i;
01372                                                 
01373                                                 test = 1; /* reset for every face */
01374                                         
01375                                                 if (em != NULL)
01376                                                 {
01377                                                         if (index_array)
01378                                                         {
01379                                                                 index = index_array[i];
01380                                                         }
01381                                                         else
01382                                                         {
01383                                                                 index = i;
01384                                                         }
01385                                                         
01386                                                         if (index == ORIGINDEX_NONE)
01387                                                         {
01388                                                                 test = 0;
01389                                                         }
01390                                                         else
01391                                                         {
01392                                                                 efa = EM_get_face_for_index(index);
01393                                                                 
01394                                                                 if (efa && (efa->h || (efa->v1->f & SELECT) || (efa->v2->f & SELECT) || (efa->v3->f & SELECT) || (efa->v4 && efa->v4->f & SELECT)))
01395                                                                 {
01396                                                                         test = 0;
01397                                                                 }
01398                                                         }
01399                                                 }
01400                                                 
01401                                                 
01402                                                 if (test)
01403                                                 {
01404                                                         int result;
01405                                                         float *v4co = NULL;
01406                                                         
01407                                                         if (f->v4)
01408                                                         {
01409                                                                 v4co = verts[f->v4].co;
01410                                                         }
01411                                                         
01412                                                         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);
01413                                                         retval |= result;
01414 
01415                                                         if (f->v4 && result == 0)
01416                                                         {
01417                                                                 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);
01418                                                         }
01419                                                 }
01420                                         }
01421                                         
01422                                         if (em != NULL)
01423                                         {
01424                                                 EM_free_index_arrays();
01425                                         }
01426 #endif
01427                                         break;
01428                                 }
01429                                 case SCE_SNAP_MODE_VERTEX:
01430                                 {
01431                                         MVert *verts = dm->getVertArray(dm);
01432                                         int *index_array = NULL;
01433                                         int index = 0;
01434                                         int i;
01435                                         
01436                                         if (em != NULL)
01437                                         {
01438                                                 index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
01439                                                 EM_init_index_arrays(em, 1, 0, 0);
01440                                         }
01441                                         
01442                                         for( i = 0; i < totvert; i++) {
01443                                                 EditVert *eve = NULL;
01444                                                 MVert *v = verts + i;
01445                                                 
01446                                                 test = 1; /* reset for every vert */
01447                                         
01448                                                 if (em != NULL)
01449                                                 {
01450                                                         if (index_array)
01451                                                         {
01452                                                                 index = index_array[i];
01453                                                         }
01454                                                         else
01455                                                         {
01456                                                                 index = i;
01457                                                         }
01458                                                         
01459                                                         if (index == ORIGINDEX_NONE)
01460                                                         {
01461                                                                 test = 0;
01462                                                         }
01463                                                         else
01464                                                         {
01465                                                                 eve = EM_get_vert_for_index(index);
01466                                                                 
01467                                                                 if (eve && (eve->h || (eve->f & SELECT)))
01468                                                                 {
01469                                                                         test = 0;
01470                                                                 }
01471                                                         }
01472                                                 }
01473                                                 
01474                                                 
01475                                                 if (test)
01476                                                 {
01477                                                         retval |= snapVertex(ar, v->co, v->no, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
01478                                                 }
01479                                         }
01480 
01481                                         if (em != NULL)
01482                                         {
01483                                                 EM_free_index_arrays();
01484                                         }
01485                                         break;
01486                                 }
01487                                 case SCE_SNAP_MODE_EDGE:
01488                                 {
01489                                         MVert *verts = dm->getVertArray(dm);
01490                                         MEdge *edges = dm->getEdgeArray(dm);
01491                                         int totedge = dm->getNumEdges(dm);
01492                                         int *index_array = NULL;
01493                                         int index = 0;
01494                                         int i;
01495                                         
01496                                         if (em != NULL)
01497                                         {
01498                                                 index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
01499                                                 EM_init_index_arrays(em, 0, 1, 0);
01500                                         }
01501                                         
01502                                         for( i = 0; i < totedge; i++) {
01503                                                 EditEdge *eed = NULL;
01504                                                 MEdge *e = edges + i;
01505                                                 
01506                                                 test = 1; /* reset for every vert */
01507                                         
01508                                                 if (em != NULL)
01509                                                 {
01510                                                         if (index_array)
01511                                                         {
01512                                                                 index = index_array[i];
01513                                                         }
01514                                                         else
01515                                                         {
01516                                                                 index = i;
01517                                                         }
01518                                                         
01519                                                         if (index == ORIGINDEX_NONE)
01520                                                         {
01521                                                                 test = 0;
01522                                                         }
01523                                                         else
01524                                                         {
01525                                                                 eed = EM_get_edge_for_index(index);
01526                                                                 
01527                                                                 if (eed && (eed->h || (eed->v1->f & SELECT) || (eed->v2->f & SELECT)))
01528                                                                 {
01529                                                                         test = 0;
01530                                                                 }
01531                                                         }
01532                                                 }
01533                                                 
01534                                                 
01535                                                 if (test)
01536                                                 {
01537                                                         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);
01538                                                 }
01539                                         }
01540 
01541                                         if (em != NULL)
01542                                         {
01543                                                 EM_free_index_arrays();
01544                                         }
01545                                         break;
01546                                 }
01547                         }
01548                 }
01549         }
01550 
01551         return retval;
01552 } 
01553 
01554 static 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)
01555 {
01556         ToolSettings *ts= scene->toolsettings;
01557         int retval = 0;
01558         
01559         if (ob->type == OB_MESH) {
01560                 EditMesh *em;
01561                 DerivedMesh *dm;
01562                 
01563                 if (editobject)
01564                 {
01565                         em = ((Mesh *)ob->data)->edit_mesh;
01566                         /* dm = editmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); */
01567                         dm = editmesh_get_derived_base(ob, em); /* limitation, em & dm MUST have the same number of faces */
01568                 }
01569                 else
01570                 {
01571                         em = NULL;
01572                         dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
01573                 }
01574                 
01575                 retval = snapDerivedMesh(ts->snap_mode, ar, ob, dm, em, obmat, ray_start, ray_normal, mval, loc, no, dist, depth);
01576 
01577                 dm->release(dm);
01578         }
01579         else if (ob->type == OB_ARMATURE)
01580         {
01581                 retval = snapArmature(ts->snap_mode, ar, ob, ob->data, obmat, ray_start, ray_normal, mval, loc, no, dist, depth);
01582         }
01583         
01584         return retval;
01585 }
01586 
01587 static int snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, float mval[2], int *dist, float *loc, float *no, SnapMode mode) {
01588         Base *base;
01589         float depth = FLT_MAX;
01590         int retval = 0;
01591         float ray_start[3], ray_normal[3];
01592         
01593         ED_view3d_win_to_ray(ar, v3d, mval, ray_start, ray_normal);
01594 
01595         if (mode == SNAP_ALL && obedit)
01596         {
01597                 Object *ob = obedit;
01598 
01599                 retval |= snapObject(scene, ar, ob, 1, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth);
01600         }
01601 
01602         /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
01603          * which makes the loop skip it, even the derived mesh will never change
01604          *
01605          * To solve that problem, we do it first as an exception. 
01606          * */
01607         base= BASACT;
01608         if(base && base->object && base->object->mode & OB_MODE_PARTICLE_EDIT)
01609         {
01610                 Object *ob = base->object;
01611                 retval |= snapObject(scene, ar, ob, 0, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth);
01612         }
01613 
01614         for ( base = FIRSTBASE; base != NULL; base = base->next ) {
01615                 if ( BASE_VISIBLE(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)) ) {
01616                         Object *ob = base->object;
01617                         
01618                         if (ob->transflag & OB_DUPLI)
01619                         {
01620                                 DupliObject *dupli_ob;
01621                                 ListBase *lb = object_duplilist(scene, ob);
01622                                 
01623                                 for(dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next)
01624                                 {
01625                                         Object *dob = dupli_ob->ob;
01626                                         
01627                                         retval |= snapObject(scene, ar, dob, 0, dupli_ob->mat, ray_start, ray_normal, mval, loc, no, dist, &depth);
01628                                 }
01629                                 
01630                                 free_object_duplilist(lb);
01631                         }
01632                         
01633                         retval |= snapObject(scene, ar, ob, 0, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth);
01634                 }
01635         }
01636         
01637         return retval;
01638 }
01639 
01640 int snapObjectsTransform(TransInfo *t, float mval[2], int *dist, float *loc, float *no, SnapMode mode)
01641 {
01642         return snapObjects(t->scene, t->view, t->ar, t->obedit, mval, dist, loc, no, mode);
01643 }
01644 
01645 int snapObjectsContext(bContext *C, float mval[2], int *dist, float *loc, float *no, SnapMode mode)
01646 {
01647         ScrArea *sa = CTX_wm_area(C);
01648         View3D *v3d = sa->spacedata.first;
01649 
01650         return snapObjects(CTX_data_scene(C), v3d, CTX_wm_region(C), CTX_data_edit_object(C), mval, dist, loc, no, mode);
01651 }
01652 
01653 /******************** PEELING *********************************/
01654 
01655 
01656 static int cmpPeel(void *arg1, void *arg2)
01657 {
01658         DepthPeel *p1 = arg1;
01659         DepthPeel *p2 = arg2;
01660         int val = 0;
01661         
01662         if (p1->depth < p2->depth)
01663         {
01664                 val = -1;
01665         }
01666         else if (p1->depth > p2->depth)
01667         {
01668                 val = 1;
01669         }
01670         
01671         return val;
01672 }
01673 
01674 static void removeDoublesPeel(ListBase *depth_peels)
01675 {
01676         DepthPeel *peel;
01677         
01678         for (peel = depth_peels->first; peel; peel = peel->next)
01679         {
01680                 DepthPeel *next_peel = peel->next;
01681                 
01682                 if (next_peel && ABS(peel->depth - next_peel->depth) < 0.0015f)
01683                 {
01684                         peel->next = next_peel->next;
01685                         
01686                         if (next_peel->next)
01687                         {
01688                                 next_peel->next->prev = peel;
01689                         }
01690                         
01691                         MEM_freeN(next_peel);
01692                 }
01693         }
01694 }
01695 
01696 static void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float no[3], Object *ob)
01697 {
01698         DepthPeel *peel = MEM_callocN(sizeof(DepthPeel), "DepthPeel");
01699         
01700         peel->depth = depth;
01701         peel->ob = ob;
01702         VECCOPY(peel->p, p);
01703         VECCOPY(peel->no, no);
01704         
01705         BLI_addtail(depth_peels, peel);
01706         
01707         peel->flag = 0;
01708 }
01709 
01710 static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_start[3], float ray_normal[3], float UNUSED(mval[2]), ListBase *depth_peels)
01711 {
01712         int retval = 0;
01713         int totvert = dm->getNumVerts(dm);
01714         int totface = dm->getNumFaces(dm);
01715         
01716         if (totvert > 0) {
01717                 float imat[4][4];
01718                 float timat[3][3]; /* transpose inverse matrix for normals */
01719                 float ray_start_local[3], ray_normal_local[3];
01720                 int test = 1;
01721 
01722                 invert_m4_m4(imat, obmat);
01723 
01724                 copy_m3_m4(timat, imat);
01725                 transpose_m3(timat);
01726                 
01727                 VECCOPY(ray_start_local, ray_start);
01728                 VECCOPY(ray_normal_local, ray_normal);
01729                 
01730                 mul_m4_v3(imat, ray_start_local);
01731                 mul_mat3_m4_v3(imat, ray_normal_local);
01732                 
01733                 
01734                 /* If number of vert is more than an arbitrary limit, 
01735                  * test against boundbox first
01736                  * */
01737                 if (totface > 16) {
01738                         struct BoundBox *bb = object_get_boundbox(ob);
01739                         test = ray_hit_boundbox(bb, ray_start_local, ray_normal_local);
01740                 }
01741                 
01742                 if (test == 1) {
01743                         MVert *verts = dm->getVertArray(dm);
01744                         MFace *faces = dm->getFaceArray(dm);
01745                         int i;
01746                         
01747                         for( i = 0; i < totface; i++) {
01748                                 MFace *f = faces + i;
01749                                 float lambda;
01750                                 int result;
01751                                 
01752                                 
01753                                 result = isect_ray_tri_threshold_v3(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL, 0.001);
01754                                 
01755                                 if (result) {
01756                                         float location[3], normal[3];
01757                                         float intersect[3];
01758                                         float new_depth;
01759                                         
01760                                         VECCOPY(intersect, ray_normal_local);
01761                                         mul_v3_fl(intersect, lambda);
01762                                         add_v3_v3(intersect, ray_start_local);
01763                                         
01764                                         VECCOPY(location, intersect);
01765                                         
01766                                         if (f->v4)
01767                                                 normal_quad_v3( normal,verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co);
01768                                         else
01769                                                 normal_tri_v3( normal,verts[f->v1].co, verts[f->v2].co, verts[f->v3].co);
01770 
01771                                         mul_m4_v3(obmat, location);
01772                                         
01773                                         new_depth = len_v3v3(location, ray_start);                                      
01774                                         
01775                                         mul_m3_v3(timat, normal);
01776                                         normalize_v3(normal);
01777 
01778                                         addDepthPeel(depth_peels, new_depth, location, normal, ob);
01779                                 }
01780                 
01781                                 if (f->v4 && result == 0)
01782                                 {
01783                                         result = isect_ray_tri_threshold_v3(ray_start_local, ray_normal_local, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, &lambda, NULL, 0.001);
01784                                         
01785                                         if (result) {
01786                                                 float location[3], normal[3];
01787                                                 float intersect[3];
01788                                                 float new_depth;
01789                                                 
01790                                                 VECCOPY(intersect, ray_normal_local);
01791                                                 mul_v3_fl(intersect, lambda);
01792                                                 add_v3_v3(intersect, ray_start_local);
01793                                                 
01794                                                 VECCOPY(location, intersect);
01795                                                 
01796                                                 if (f->v4)
01797                                                         normal_quad_v3( normal,verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co);
01798                                                 else
01799                                                         normal_tri_v3( normal,verts[f->v1].co, verts[f->v2].co, verts[f->v3].co);
01800 
01801                                                 mul_m4_v3(obmat, location);
01802                                                 
01803                                                 new_depth = len_v3v3(location, ray_start);                                      
01804                                                 
01805                                                 mul_m3_v3(timat, normal);
01806                                                 normalize_v3(normal);
01807         
01808                                                 addDepthPeel(depth_peels, new_depth, location, normal, ob);
01809                                         } 
01810                                 }
01811                         }
01812                 }
01813         }
01814 
01815         return retval;
01816 } 
01817 
01818 static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase *depth_peels, float mval[2])
01819 {
01820         Base *base;
01821         int retval = 0;
01822         float ray_start[3], ray_normal[3];
01823         
01824         ED_view3d_win_to_ray(ar, v3d, mval, ray_start, ray_normal);
01825 
01826         for ( base = scene->base.first; base != NULL; base = base->next ) {
01827                 if ( BASE_SELECTABLE(v3d, base) ) {
01828                         Object *ob = base->object;
01829                         
01830                         if (ob->transflag & OB_DUPLI)
01831                         {
01832                                 DupliObject *dupli_ob;
01833                                 ListBase *lb = object_duplilist(scene, ob);
01834                                 
01835                                 for(dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next)
01836                                 {
01837                                         Object *dob = dupli_ob->ob;
01838                                         
01839                                         if (dob->type == OB_MESH) {
01840                                                 EditMesh *em;
01841                                                 DerivedMesh *dm = NULL;
01842                                                 int val;
01843 
01844                                                 if (dob != obedit)
01845                                                 {
01846                                                         dm = mesh_get_derived_final(scene, dob, CD_MASK_BAREMESH);
01847                                                         
01848                                                         val = peelDerivedMesh(dob, dm, dob->obmat, ray_start, ray_normal, mval, depth_peels);
01849                                                 }
01850                                                 else
01851                                                 {
01852                                                         em = ((Mesh *)dob->data)->edit_mesh;
01853                                                         dm = editmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
01854                                                         
01855                                                         val = peelDerivedMesh(dob, dm, dob->obmat, ray_start, ray_normal, mval, depth_peels);
01856                                                 }
01857 
01858                                                 retval = retval || val;
01859                                                 
01860                                                 dm->release(dm);
01861                                         }
01862                                 }
01863                                 
01864                                 free_object_duplilist(lb);
01865                         }
01866                         
01867                         if (ob->type == OB_MESH) {
01868                                 EditMesh *em;
01869                                 DerivedMesh *dm = NULL;
01870                                 int val;
01871 
01872                                 if (ob != obedit)
01873                                 {
01874                                         dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
01875                                         
01876                                         val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
01877                                 }
01878                                 else
01879                                 {
01880                                         em = ((Mesh *)ob->data)->edit_mesh;
01881                                         dm = editmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
01882                                         
01883                                         val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
01884                                 }
01885                                         
01886                                 retval = retval || val;
01887                                 
01888                                 dm->release(dm);
01889                         }
01890                 }
01891         }
01892         
01893         BLI_sortlist(depth_peels, cmpPeel);
01894         removeDoublesPeel(depth_peels);
01895         
01896         return retval;
01897 }
01898 
01899 int peelObjectsTransForm(TransInfo *t, ListBase *depth_peels, float mval[2])
01900 {
01901         return peelObjects(t->scene, t->view, t->ar, t->obedit, depth_peels, mval);
01902 }
01903 
01904 int peelObjectsContext(bContext *C, ListBase *depth_peels, float mval[2])
01905 {
01906         ScrArea *sa = CTX_wm_area(C);
01907         View3D *v3d = sa->spacedata.first;
01908 
01909         return peelObjects(CTX_data_scene(C), v3d, CTX_wm_region(C), CTX_data_edit_object(C), depth_peels, mval);
01910 }
01911 
01912 /*================================================================*/
01913 
01914 static void applyGrid(TransInfo *t, float *val, int max_index, float fac[3], GearsType action);
01915 
01916 
01917 void snapGridAction(TransInfo *t, float *val, GearsType action) {
01918         float fac[3];
01919 
01920         fac[NO_GEARS]    = t->snap[0];
01921         fac[BIG_GEARS]   = t->snap[1];
01922         fac[SMALL_GEARS] = t->snap[2];
01923         
01924         applyGrid(t, val, t->idx_max, fac, action);
01925 }
01926 
01927 
01928 void snapGrid(TransInfo *t, float *val) {
01929         GearsType action;
01930 
01931         // Only do something if using Snap to Grid
01932         if (t->tsnap.mode != SCE_SNAP_MODE_INCREMENT)
01933                 return;
01934 
01935         action = activeSnap(t) ? BIG_GEARS : NO_GEARS;
01936 
01937         if (action == BIG_GEARS && (t->modifiers & MOD_PRECISION)) {
01938                 action = SMALL_GEARS;
01939         }
01940 
01941         snapGridAction(t, val, action);
01942 }
01943 
01944 
01945 static void applyGrid(TransInfo *t, float *val, int max_index, float fac[3], GearsType action)
01946 {
01947         int i;
01948         float asp[3] = {1.0f, 1.0f, 1.0f}; // TODO: Remove hard coded limit here (3)
01949 
01950         if(max_index > 2) {
01951                 printf("applyGrid: invalid index %d, clamping\n", max_index);
01952                 max_index= 2;
01953         }
01954 
01955         // Early bailing out if no need to snap
01956         if (fac[action] == 0.0f)
01957                 return;
01958         
01959         /* evil hack - snapping needs to be adapted for image aspect ratio */
01960         if((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
01961                 ED_space_image_uv_aspect(t->sa->spacedata.first, asp, asp+1);
01962         }
01963 
01964         for (i=0; i<=max_index; i++) {
01965                 val[i]= fac[action]*asp[i]*(float)floor(val[i]/(fac[action]*asp[i]) +0.5f);
01966         }
01967 }