Blender V2.61 - r43446

transform_snap.c

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