Merge 16964:17122
authorMartin Poirier <theeth@yahoo.com>
Mon, 20 Oct 2008 00:27:33 +0000 (00:27 +0000)
committerMartin Poirier <theeth@yahoo.com>
Mon, 20 Oct 2008 00:27:33 +0000 (00:27 +0000)
15 files changed:
source/blender/blenkernel/BKE_global.h
source/blender/blenlib/BLI_arithb.h
source/blender/blenlib/intern/arithb.c
source/blender/include/BDR_sketch.h [new file with mode: 0644]
source/blender/include/BIF_editarmature.h
source/blender/include/BIF_sketch.h [new file with mode: 0644]
source/blender/include/BIF_space.h
source/blender/makesdna/DNA_scene_types.h
source/blender/src/drawview.c
source/blender/src/edit.c
source/blender/src/editarmature.c
source/blender/src/editarmature_sketch.c [new file with mode: 0644]
source/blender/src/header_view3d.c
source/blender/src/space.c
source/blender/src/view.c

index 3a2dca525b8d484e23b2a6020dd6c48e8ce7eab8..bb474d3f8c8c072d57d0234949868e17d6aa51bf 100644 (file)
@@ -151,7 +151,6 @@ typedef struct Global {
        
        /* confusing... G.f and G.flags */
        int flags;
-
 } Global;
 
 /* **************** GLOBAL ********************* */
index e2e71a2fb1a7e67cde095a0f5886eee2e2f78bd9..3c8d2915cf98c8a863a1866f6b04678f0e23d359 100644 (file)
@@ -388,6 +388,7 @@ void tubemap(float x, float y, float z, float *u, float *v);
 void spheremap(float x, float y, float z, float *u, float *v);
 
 int LineIntersectLine(float v1[3], float v2[3], float v3[3], float v4[3], float i1[3], float i2[3]);
+int LineIntersectLineStrict(float v1[3], float v2[3], float v3[3], float v4[3], float vi[3], float *lambda);
 int LineIntersectsTriangle(float p1[3], float p2[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv);
 int RayIntersectsTriangle(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv);
 int SweepingSphereIntersectsTriangleUV(float p1[3], float p2[3], float radius, float v0[3], float v1[3], float v2[3], float *lambda, float *ipoint);
index 79517c4fde4038819f4cfd3e0035415ec5b22bb3..54e1bd5fc57f1a5036c8f24115a98df9de9e00f8 100644 (file)
@@ -4221,6 +4221,67 @@ int LineIntersectLine(float v1[3], float v2[3], float v3[3], float v4[3], float
        }
 } 
 
+/* Intersection point strictly between the two lines
+ * 0 when no intersection is found 
+ * */
+int LineIntersectLineStrict(float v1[3], float v2[3], float v3[3], float v4[3], float vi[3], float *lambda)
+{
+       float a[3], b[3], c[3], ab[3], cb[3], ca[3], dir1[3], dir2[3];
+       float d;
+       float d1;
+       
+       VecSubf(c, v3, v1);
+       VecSubf(a, v2, v1);
+       VecSubf(b, v4, v3);
+
+       VecCopyf(dir1, a);
+       Normalize(dir1);
+       VecCopyf(dir2, b);
+       Normalize(dir2);
+       d = Inpf(dir1, dir2);
+       if (d == 1.0f || d == -1.0f || d == 0) {
+               /* colinear or one vector is zero-length*/
+               return 0;
+       }
+       
+       d1 = d;
+
+       Crossf(ab, a, b);
+       d = Inpf(c, ab);
+
+       /* test if the two lines are coplanar */
+       if (d > -0.000001f && d < 0.000001f) {
+               float f1, f2;
+               Crossf(cb, c, b);
+               Crossf(ca, c, a);
+
+               f1 = Inpf(cb, ab) / Inpf(ab, ab);
+               f2 = Inpf(ca, ab) / Inpf(ab, ab);
+               
+               if (f1 >= 0 && f1 <= 1 &&
+                       f2 >= 0 && f2 <= 1)
+               {
+                       VecMulf(a, f1);
+                       VecAddf(vi, v1, a);
+                       
+                       if (lambda != NULL)
+                       {
+                               *lambda = f1;
+                       }
+                       
+                       return 1; /* intersection found */
+               }
+               else
+               {
+                       return 0;
+               }
+       }
+       else
+       {
+               return 0;
+       }
+} 
+
 int AabbIntersectAabb(float min1[3], float max1[3], float min2[3], float max2[3])
 {
        return (min1[0]<max2[0] && min1[1]<max2[1] && min1[2]<max2[2] &&
diff --git a/source/blender/include/BDR_sketch.h b/source/blender/include/BDR_sketch.h
new file mode 100644 (file)
index 0000000..55d6e1d
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+ * $Id:  $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_SKETCH_H
+#define BDR_SKETCH_H
+
+void BDR_queueDrawSketch();
+void BDR_drawSketch();
+void BDR_drawSketchNames();
+
+#endif /* BDR_SKETCH_H */
index d390b96f61f5bccc4dd103ff9ae9db3b274a9480..7211d71fcb626cdb20125aeb4233d04f40939238 100644 (file)
@@ -68,6 +68,7 @@ typedef struct EditBone
 
 } EditBone;
 
+EditBone *addEditBone(char *name, struct ListBase *ebones, struct bArmature *arm);
 
 void   adduplicate_armature(void);
 void   addvert_armature(void);
diff --git a/source/blender/include/BIF_sketch.h b/source/blender/include/BIF_sketch.h
new file mode 100644 (file)
index 0000000..b9fd5d3
--- /dev/null
@@ -0,0 +1,33 @@
+/**
+ * $Id:  $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_SKETCH_H
+#define BIF_SKETCH_H
+
+int BIF_paintSketch(short mbut);
+void BIF_endStrokeSketch();
+void BIF_convertSketch();
+void BIF_deleteSketch();
+void BIF_selectAllSketch(int mode); /* -1: deselect, 0: select, 1: toggle */
+int BIF_validSketchMode();
+
+#endif /* BIF_SKETCH_H */
index c7d0f4a1ada462beaa0938206ff15e6c8e3626c4..a52b499e936cd78c009f0840198b61d4c8f88006 100644 (file)
@@ -54,6 +54,7 @@ struct SpaceOops;
 #define VIEW3D_HANDLER_MULTIRES         5
 #define VIEW3D_HANDLER_TRANSFORM       6
 #define VIEW3D_HANDLER_GREASEPENCIL 7
+#define VIEW3D_HANDLER_BONESKETCH 8
 
 /* ipo handler codes */
 #define IPO_HANDLER_PROPERTIES 20
index a5eaf222941eee3bf93a4b90a77c6aecf4646287..3dec57680c769fbd7df338151785277ebb577a2d 100644 (file)
@@ -438,9 +438,12 @@ typedef struct ToolSettings {
        char  skgen_postpro_passes;
        char  skgen_subdivisions[3];
        
+       /* Skeleton Sketching */
+       char bone_sketching;
+       
        /* Alt+RMB option */
        char edge_mode;
-       char pad3[4];
+       char pad3[3];
 } ToolSettings;
 
 /* Used by all brushes to store their properties, which can be directly set
@@ -854,6 +857,9 @@ typedef struct Scene {
 #define SKGEN_AVERAGE                  1
 #define SKGEN_SHARPEN                  2
 
+/* toolsettings->bone_sketching */
+#define BONE_SKETCHING         1
+
 #ifdef __cplusplus
 }
 #endif
index 8f2623575aa75a4c4d00db3e55bf7c91fa6686af..386cf30b61fd9c185fd0ba6ed6ab028e27198bde 100644 (file)
 #include "BIF_resources.h"
 #include "BIF_retopo.h"
 #include "BIF_screen.h"
+#include "BIF_sketch.h"
 #include "BIF_space.h"
 
 #ifdef WITH_VERSE
 #include "BDR_vpaint.h"
 #include "BDR_sculptmode.h"
 #include "BDR_gpencil.h"
+#include "BDR_sketch.h"
 
 #include "BSE_drawview.h"
 #include "BSE_filesel.h"
@@ -2267,6 +2269,58 @@ static void view3d_panel_transform_spaces(short cntrl)
        if(yco < 0) uiNewPanelHeight(block, height-yco);
 }
 
+static void delete_sketch_armature(void *arg1, void *arg2)
+{
+       BIF_deleteSketch();
+}
+
+static void convert_sketch_armature(void *arg1, void *arg2)
+{
+       BIF_convertSketch();
+}
+
+static void view3d_panel_bonesketch_spaces(short cntrl)
+{
+       uiBlock *block;
+       uiBut *but;
+       int yco = 70, height = 140;
+//     int index;
+
+       /* replace with check call to sketching lib */
+       if (G.obedit && G.obedit->type == OB_ARMATURE)
+       {
+               block= uiNewBlock(&curarea->uiblocks, "view3d_panel_transform", UI_EMBOSS, UI_HELV, curarea->win);
+               uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE  | cntrl);
+               uiSetPanelHandler(VIEW3D_HANDLER_TRANSFORM);  // for close and esc
+       
+               if(uiNewPanel(curarea, block, "Bone Sketching", "View3d", 10, 230, 318, height)==0) return;
+       
+               uiNewPanelHeight(block, height);
+       
+               uiBlockBeginAlign(block);
+               
+               /* use real flag instead of 1 */
+               uiDefButBitC(block, TOG, BONE_SKETCHING, B_REDR, "Use Bone Sketching", 10, 225, 150, 20, &G.scene->toolsettings->bone_sketching, 0, 0, 0, 0, "Use sketching to create and edit bones");
+               but = uiDefBut(block, BUT, B_REDR, "Convert", 10,205,150,20, 0, 0, 0, 0, 0, "Convert sketch to armature");
+               uiButSetFunc(but, convert_sketch_armature, NULL, NULL);
+               but = uiDefBut(block, BUT, B_REDR, "Delete", 10,185,150,20, 0, 0, 0, 0, 0, "Delete sketch");
+               uiButSetFunc(but, delete_sketch_armature, NULL, NULL);
+               
+               uiBlockEndAlign(block);
+
+               uiBlockBeginAlign(block);
+
+               uiDefButBitS(block, TOG, SKGEN_CUT_LENGTH, B_DIFF,              "Length",               10, 155, 60, 19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0,                             "Subdivide arcs in bones of equal length");
+               uiDefButF(block, NUM, B_DIFF,                                                   "L:",                   70, 155, 90, 19, &G.scene->toolsettings->skgen_length_limit,0.1,50.0, 10, 0,            "Maximum length of the bones when subdividing");
+
+               uiDefButBitS(block, TOG, SKGEN_CUT_CORRELATION, B_DIFF, "Correlation",  10, 135, 60, 19, &G.scene->toolsettings->skgen_options, 0, 0, 0, 0,                                     "Subdivide arcs based on correlation");
+               uiDefButF(block, NUM, B_DIFF,                                                   "T:",                   70, 135, 90, 19, &G.scene->toolsettings->skgen_correlation_limit,0.0, 1.0, 0.01, 0,     "Specify the threshold correlation for subdivision");
+       
+               uiBlockEndAlign(block);
+               
+               if(yco < 0) uiNewPanelHeight(block, height-yco);
+       }
+}
 
 static void view3d_panel_object(short cntrl)   // VIEW3D_HANDLER_OBJECT
 {
@@ -2658,6 +2712,9 @@ static void view3d_blockhandlers(ScrArea *sa)
                case VIEW3D_HANDLER_GREASEPENCIL:
                        view3d_panel_gpencil(v3d->blockhandler[a+1]);
                        break;
+               case VIEW3D_HANDLER_BONESKETCH:
+                       view3d_panel_bonesketch_spaces(v3d->blockhandler[a+1]);
+                       break;
                }
                /* clear action value for event */
                v3d->blockhandler[a+1]= 0;
@@ -3264,6 +3321,8 @@ void drawview3dspace(ScrArea *sa, void *spacedata)
        /* draw grease-pencil stuff */
        if (v3d->flag2 & V3D_DISPGP)
                draw_gpencil_3dview(sa, 1);
+               
+       BDR_drawSketch();
        
        persp(PERSP_WIN);  // set ortho
 
index a80e7b6c3602a34aa38410d744ca35b10a267164..651bfc854d9d72038465b243387cafc41a7aae0e 100644 (file)
@@ -99,6 +99,7 @@
 #include "BIF_space.h"
 #include "BIF_screen.h"
 #include "BIF_toolbox.h"
+#include "BIF_sketch.h"
 
 #ifdef WITH_VERSE
 #include "BIF_verse.h"
@@ -1838,7 +1839,11 @@ void mergemenu(void)
 
 void delete_context_selected(void) 
 {
-       if(G.obedit) {
+       if(BIF_validSketchMode())
+       {
+               BIF_deleteSketch();
+       }
+       else if(G.obedit) {
                if(G.obedit->type==OB_MESH) delete_mesh();
                else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) delNurb();
                else if(G.obedit->type==OB_MBALL) delete_mball();
index d5e5b5a1c4a2ad846cc460a1ab41f3f816810e9e..2ab585126570bee371b9d78d96c6823277943c7d 100644 (file)
@@ -1969,17 +1969,14 @@ void undo_push_armature(char *name)
 /* **************** END EditMode stuff ********************** */
 /* *************** Adding stuff in editmode *************** */
 
-/* default bone add, returns it selected, but without tail set */
-static EditBone *add_editbone(char *name)
+EditBone *addEditBone(char *name, ListBase *ebones, bArmature *arm)
 {
-       bArmature *arm= G.obedit->data;
-       
        EditBone *bone= MEM_callocN(sizeof(EditBone), "eBone");
        
        BLI_strncpy(bone->name, name, 32);
-       unique_editbone_name(&G.edbo, bone->name);
+       unique_editbone_name(ebones, bone->name);
        
-       BLI_addtail(&G.edbo, bone);
+       BLI_addtail(ebones, bone);
        
        bone->flag |= BONE_TIPSEL;
        bone->weight= 1.0F;
@@ -1996,6 +1993,14 @@ static EditBone *add_editbone(char *name)
        return bone;
 }
 
+/* default bone add, returns it selected, but without tail set */
+static EditBone *add_editbone(char *name)
+{
+       bArmature *arm= G.obedit->data;
+       
+       return addEditBone(name, &G.edbo, arm);
+}
+
 static void add_primitive_bone(Object *ob, short newob)
 {
        float           obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
diff --git a/source/blender/src/editarmature_sketch.c b/source/blender/src/editarmature_sketch.c
new file mode 100644 (file)
index 0000000..07bdddf
--- /dev/null
@@ -0,0 +1,2177 @@
+/**
+ * $Id: $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_armature_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_object.h"
+#include "BKE_anim.h"
+
+#include "BSE_view.h"
+
+#include "BIF_gl.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_mywindow.h"
+#include "BIF_editarmature.h"
+#include "BIF_sketch.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+typedef enum SK_PType
+{
+       PT_CONTINUOUS,
+       PT_EXACT,
+} SK_PType;
+
+typedef enum SK_PMode
+{
+       PT_EMBED,
+       PT_SNAP,
+       PT_PROJECT,
+} SK_PMode;
+
+typedef struct SK_Point
+{
+       float p[3];
+       SK_PType type;
+       SK_PMode mode;
+} SK_Point;
+
+typedef struct SK_Stroke
+{
+       struct SK_Stroke *next, *prev;
+
+       SK_Point *points;
+       int nb_points;
+       int buf_size;
+       int selected;
+} SK_Stroke;
+
+#define SK_Stroke_BUFFER_INIT_SIZE 20
+
+typedef struct SK_DrawData
+{
+       short mval[2];
+       short previous_mval[2];
+       SK_PType type;
+} SK_DrawData;
+
+typedef struct SK_Intersection
+{
+       struct SK_Intersection *next, *prev;
+       SK_Stroke *stroke;
+       int                     start;
+       int                     end;
+       float           p[3];
+} SK_Intersection;
+
+typedef struct SK_Sketch
+{
+       ListBase        strokes;
+       SK_Stroke       *active_stroke;
+       SK_Stroke       *gesture;
+       SK_Point        next_point;
+} SK_Sketch;
+
+SK_Sketch *GLOBAL_sketch = NULL;
+SK_Point boneSnap;
+
+#define SNAP_MIN_DISTANCE 12
+
+/******************** PROTOTYPES ******************************/
+
+void sk_freeStroke(SK_Stroke *stk);
+void sk_freeSketch(SK_Sketch *sketch);
+
+/******************** PEELING *********************************/
+
+typedef struct SK_DepthPeel
+{
+       struct SK_DepthPeel *next, *prev;
+       
+       float depth;
+       float p[3];
+       float no[3];
+       Object *ob;
+       int flag;
+} SK_DepthPeel;
+
+int cmpPeel(void *arg1, void *arg2)
+{
+       SK_DepthPeel *p1 = arg1;
+       SK_DepthPeel *p2 = arg2;
+       int val = 0;
+       
+       if (p1->depth < p2->depth)
+       {
+               val = -1;
+       }
+       else if (p1->depth > p2->depth)
+       {
+               val = 1;
+       }
+       
+       return val;
+}
+
+void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float no[3], Object *ob)
+{
+       SK_DepthPeel *peel = MEM_callocN(sizeof(SK_DepthPeel), "DepthPeel");
+       
+       peel->depth = depth;
+       peel->ob = ob;
+       VECCOPY(peel->p, p);
+       VECCOPY(peel->no, no);
+       
+       BLI_addtail(depth_peels, peel);
+       
+       peel->flag = 0;
+}
+
+int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], ListBase *depth_peels)
+{
+       int retval = 0;
+       int totvert = dm->getNumVerts(dm);
+       int totface = dm->getNumFaces(dm);
+       
+       if (totvert > 0) {
+               float imat[4][4];
+               float timat[3][3]; /* transpose inverse matrix for normals */
+               float ray_start_local[3], ray_normal_local[3];
+               int test = 1;
+
+               Mat4Invert(imat, obmat);
+
+               Mat3CpyMat4(timat, imat);
+               Mat3Transp(timat);
+               
+               VECCOPY(ray_start_local, ray_start);
+               VECCOPY(ray_normal_local, ray_normal);
+               
+               Mat4MulVecfl(imat, ray_start_local);
+               Mat4Mul3Vecfl(imat, ray_normal_local);
+               
+               
+               /* If number of vert is more than an arbitrary limit, 
+                * test against boundbox first
+                * */
+               if (totface > 16) {
+                       struct BoundBox *bb = object_get_boundbox(ob);
+                       test = ray_hit_boundbox(bb, ray_start_local, ray_normal_local);
+               }
+               
+               if (test == 1) {
+                       MVert *verts = dm->getVertArray(dm);
+                       MFace *faces = dm->getFaceArray(dm);
+                       int i;
+                       
+                       for( i = 0; i < totface; i++) {
+                               MFace *f = faces + i;
+                               float lambda;
+                               int result;
+                               
+                               
+                               result = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL);
+                               
+                               if (result) {
+                                       float location[3], normal[3];
+                                       float intersect[3];
+                                       float new_depth;
+                                       
+                                       VECCOPY(intersect, ray_normal_local);
+                                       VecMulf(intersect, lambda);
+                                       VecAddf(intersect, intersect, ray_start_local);
+                                       
+                                       VECCOPY(location, intersect);
+                                       
+                                       if (f->v4)
+                                               CalcNormFloat4(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co, normal);
+                                       else
+                                               CalcNormFloat(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, normal);
+
+                                       Mat4MulVecfl(obmat, location);
+                                       
+                                       new_depth = VecLenf(location, ray_start);                                       
+                                       
+                                       Mat3MulVecfl(timat, normal);
+                                       Normalize(normal);
+
+                                       addDepthPeel(depth_peels, new_depth, location, normal, ob);
+                               }
+               
+                               if (f->v4 && result == 0)
+                               {
+                                       result = RayIntersectsTriangle(ray_start_local, ray_normal_local, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, &lambda, NULL);
+                                       
+                                       if (result) {
+                                               float location[3], normal[3];
+                                               float intersect[3];
+                                               float new_depth;
+                                               
+                                               VECCOPY(intersect, ray_normal_local);
+                                               VecMulf(intersect, lambda);
+                                               VecAddf(intersect, intersect, ray_start_local);
+                                               
+                                               VECCOPY(location, intersect);
+                                               
+                                               if (f->v4)
+                                                       CalcNormFloat4(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co, normal);
+                                               else
+                                                       CalcNormFloat(verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, normal);
+
+                                               Mat4MulVecfl(obmat, location);
+                                               
+                                               new_depth = VecLenf(location, ray_start);                                       
+                                               
+                                               Mat3MulVecfl(timat, normal);
+                                               Normalize(normal);
+       
+                                               addDepthPeel(depth_peels, new_depth, location, normal, ob);
+                                       } 
+                               }
+                       }
+               }
+       }
+
+       return retval;
+} 
+
+int peelObjects(ListBase *depth_peels, short mval[2])
+{
+       Base *base;
+       int retval = 0;
+       float ray_start[3], ray_normal[3];
+       
+       viewray(mval, ray_start, ray_normal);
+
+       base= FIRSTBASE;
+       for ( base = FIRSTBASE; base != NULL; base = base->next ) {
+               if ( BASE_SELECTABLE(base) ) {
+                       Object *ob = base->object;
+                       
+                       if (ob->transflag & OB_DUPLI)
+                       {
+                               DupliObject *dupli_ob;
+                               ListBase *lb = object_duplilist(G.scene, ob);
+                               
+                               for(dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next)
+                               {
+                                       Object *ob = dupli_ob->ob;
+                                       
+                                       if (ob->type == OB_MESH) {
+                                               DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+                                               int val;
+                                               
+                                               val = peelDerivedMesh(ob, dm, dupli_ob->mat, ray_start, ray_normal, mval, depth_peels);
+       
+                                               retval = retval || val;
+       
+                                               dm->release(dm);
+                                       }
+                               }
+                               
+                               free_object_duplilist(lb);
+                       }
+                       
+                       if (ob->type == OB_MESH) {
+                               DerivedMesh *dm = NULL;
+                               int val;
+
+                               if (ob != G.obedit)
+                               {
+                                       dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+                                       
+                                       val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
+                               }
+                               else
+                               {
+                                       dm = editmesh_get_derived_cage(CD_MASK_BAREMESH);
+                                       
+                                       val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
+                               }
+                                       
+                               retval = retval || val;
+                               
+                               dm->release(dm);
+                       }
+               }
+       }
+       
+       BLI_sortlist(depth_peels, cmpPeel);
+       
+       return retval;
+}
+
+/**************************************************************/
+
+void sk_freeSketch(SK_Sketch *sketch)
+{
+       SK_Stroke *stk, *next;
+       
+       for (stk = sketch->strokes.first; stk; stk = next)
+       {
+               next = stk->next;
+               
+               sk_freeStroke(stk);
+       }
+       
+       MEM_freeN(sketch);
+}
+
+SK_Sketch* sk_createSketch()
+{
+       SK_Sketch *sketch;
+       
+       sketch = MEM_callocN(sizeof(SK_Sketch), "SK_Sketch");
+       
+       sketch->active_stroke = NULL;
+       sketch->gesture = NULL;
+
+       sketch->strokes.first = NULL;
+       sketch->strokes.last = NULL;
+       
+       return sketch;
+}
+
+void sk_allocStrokeBuffer(SK_Stroke *stk)
+{
+       stk->points = MEM_callocN(sizeof(SK_Point) * stk->buf_size, "SK_Point buffer");
+}
+
+void sk_freeStroke(SK_Stroke *stk)
+{
+       MEM_freeN(stk->points);
+       MEM_freeN(stk);
+}
+
+SK_Stroke* sk_createStroke()
+{
+       SK_Stroke *stk;
+       
+       stk = MEM_callocN(sizeof(SK_Stroke), "SK_Stroke");
+       
+       stk->selected = 0;
+       stk->nb_points = 0;
+       stk->buf_size = SK_Stroke_BUFFER_INIT_SIZE;
+       
+       sk_allocStrokeBuffer(stk);
+       
+       return stk;
+}
+
+void sk_shrinkStrokeBuffer(SK_Stroke *stk)
+{
+       if (stk->nb_points < stk->buf_size)
+       {
+               SK_Point *old_points = stk->points;
+               
+               stk->buf_size = stk->nb_points;
+
+               sk_allocStrokeBuffer(stk);              
+               
+               memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
+               
+               MEM_freeN(old_points);
+       }
+}
+
+void sk_growStrokeBuffer(SK_Stroke *stk)
+{
+       if (stk->nb_points == stk->buf_size)
+       {
+               SK_Point *old_points = stk->points;
+               
+               stk->buf_size *= 2;
+               
+               sk_allocStrokeBuffer(stk);
+               
+               memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
+               
+               MEM_freeN(old_points);
+       }
+}
+
+void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n)
+{
+       memcpy(stk->points + n, pt, sizeof(SK_Point));
+}
+
+void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n)
+{
+       int size = stk->nb_points - n;
+       
+       sk_growStrokeBuffer(stk);
+       
+       memmove(stk->points + n + 1, stk->points + n, size * sizeof(SK_Point));
+       
+       memcpy(stk->points + n, pt, sizeof(SK_Point));
+       
+       stk->nb_points++;
+}
+
+void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt)
+{
+       sk_growStrokeBuffer(stk);
+       
+       memcpy(stk->points + stk->nb_points, pt, sizeof(SK_Point));
+       
+       stk->nb_points++;
+}
+
+void sk_trimStroke(SK_Stroke *stk, int start, int end)
+{
+       int size = end - start + 1;
+       
+       if (start > 0)
+       {
+               memmove(stk->points, stk->points + start, size * sizeof(SK_Point));
+       }
+       
+       stk->nb_points = size;
+}
+
+/* Apply reverse Chaikin filter to simplify the polyline
+ * */
+void sk_filterStroke(SK_Stroke *stk, int start, int end)
+{
+       SK_Point *old_points = stk->points;
+       int nb_points = stk->nb_points;
+       int i, j;
+       
+       if (start == -1)
+       {
+               start = 0;
+               end = stk->nb_points - 1;
+       }
+
+       sk_allocStrokeBuffer(stk);
+       stk->nb_points = 0;
+       
+       /* adding points before range */
+       for (i = 0; i < start; i++)
+       {
+               sk_appendStrokePoint(stk, old_points + i);
+       }
+       
+       for (i = start, j = start; i <= end; i++)
+       {
+               if (i - j == 3)
+               {
+                       SK_Point pt;
+                       float vec[3];
+                       
+                       pt.type = PT_CONTINUOUS;
+                       pt.p[0] = 0;
+                       pt.p[1] = 0;
+                       pt.p[2] = 0;
+                       
+                       VECCOPY(vec, old_points[j].p);
+                       VecMulf(vec, -0.25);
+                       VecAddf(pt.p, pt.p, vec);
+                       
+                       VECCOPY(vec, old_points[j+1].p);
+                       VecMulf(vec,  0.75);
+                       VecAddf(pt.p, pt.p, vec);
+
+                       VECCOPY(vec, old_points[j+2].p);
+                       VecMulf(vec,  0.75);
+                       VecAddf(pt.p, pt.p, vec);
+
+                       VECCOPY(vec, old_points[j+3].p);
+                       VecMulf(vec, -0.25);
+                       VecAddf(pt.p, pt.p, vec);
+                       
+                       sk_appendStrokePoint(stk, &pt);
+
+                       j += 2;
+               }
+               
+               /* this might be uneeded when filtering last continuous stroke */
+               if (old_points[i].type == PT_EXACT)
+               {
+                       sk_appendStrokePoint(stk, old_points + i);
+                       j = i;
+               }
+       } 
+       
+       /* adding points after range */
+       for (i = end + 1; i < nb_points; i++)
+       {
+               sk_appendStrokePoint(stk, old_points + i);
+       }
+
+       MEM_freeN(old_points);
+
+       sk_shrinkStrokeBuffer(stk);
+}
+
+void sk_filterLastContinuousStroke(SK_Stroke *stk)
+{
+       int start, end;
+       
+       end = stk->nb_points -1;
+       
+       for (start = end - 1; start > 0 && stk->points[start].type == PT_CONTINUOUS; start--)
+       {
+               /* nothing to do here*/
+       }
+       
+       if (end - start > 1)
+       {
+               sk_filterStroke(stk, start, end);
+       }
+}
+
+SK_Point *sk_lastStrokePoint(SK_Stroke *stk)
+{
+       SK_Point *pt = NULL;
+       
+       if (stk->nb_points > 0)
+       {
+               pt = stk->points + (stk->nb_points - 1);
+       }
+       
+       return pt;
+}
+
+void sk_drawStroke(SK_Stroke *stk, int id, float color[3])
+{
+       float rgb[3];
+       int i;
+       
+       if (id != -1)
+       {
+               glLoadName(id);
+               
+               glBegin(GL_LINE_STRIP);
+               
+               for (i = 0; i < stk->nb_points; i++)
+               {
+                       glVertex3fv(stk->points[i].p);
+               }
+               
+               glEnd();
+               
+       }
+       else
+       {
+               float d_rgb[3] = {1, 1, 1};
+               
+               VECCOPY(rgb, color);
+               VecSubf(d_rgb, d_rgb, rgb);
+               VecMulf(d_rgb, 1.0f / (float)stk->nb_points);
+               
+               glBegin(GL_LINE_STRIP);
+
+               for (i = 0; i < stk->nb_points; i++)
+               {
+                       glColor3fv(rgb);
+                       glVertex3fv(stk->points[i].p);
+                       VecAddf(rgb, rgb, d_rgb);
+               }
+               
+               glEnd();
+       
+               glColor3f(0, 0, 0);
+               glBegin(GL_POINTS);
+       
+               for (i = 0; i < stk->nb_points; i++)
+               {
+                       if (stk->points[i].type == PT_EXACT)
+                       {
+                               glVertex3fv(stk->points[i].p);
+                       }
+               }
+               
+               glEnd();
+       }
+
+//     glColor3f(1, 1, 1);
+//     glBegin(GL_POINTS);
+//
+//     for (i = 0; i < stk->nb_points; i++)
+//     {
+//             if (stk->points[i].type == PT_CONTINUOUS)
+//             {
+//                     glVertex3fv(stk->points[i].p);
+//             }
+//     }
+//
+//     glEnd();
+}
+
+SK_Point *sk_snapPointStroke(SK_Stroke *stk, short mval[2], int *dist)
+{
+       SK_Point *pt = NULL;
+       int i;
+       
+       for (i = 0; i < stk->nb_points; i++)
+       {
+               if (stk->points[i].type == PT_EXACT)
+               {
+                       short pval[2];
+                       int pdist;
+                       
+                       project_short_noclip(stk->points[i].p, pval);
+                       
+                       pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
+                       
+                       if (pdist < *dist)
+                       {
+                               *dist = pdist;
+                               pt = stk->points + i;
+                       }
+               }
+       }
+       
+       return pt;
+}
+
+SK_Point *sk_snapPointArmature(ListBase *ebones, short mval[2], int *dist)
+{
+       SK_Point *pt = NULL;
+       EditBone *bone;
+       
+       for (bone = ebones->first; bone; bone = bone->next)
+       {
+               short pval[2];
+               int pdist;
+               
+               if ((bone->flag & BONE_CONNECTED) == 0)
+               {
+                       project_short_noclip(bone->head, pval);
+                       
+                       pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
+                       
+                       if (pdist < *dist)
+                       {
+                               *dist = pdist;
+                               pt = &boneSnap;
+                               VECCOPY(pt->p, bone->head);
+                               pt->type = PT_EXACT;
+                       }
+               }
+               
+               
+               project_short_noclip(bone->tail, pval);
+               
+               pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
+               
+               if (pdist < *dist)
+               {
+                       *dist = pdist;
+                       pt = &boneSnap;
+                       VECCOPY(pt->p, bone->tail);
+                       pt->type = PT_EXACT;
+               }
+       }
+       
+       return pt;
+}
+
+void sk_startStroke(SK_Sketch *sketch)
+{
+       SK_Stroke *stk = sk_createStroke();
+       
+       BLI_addtail(&sketch->strokes, stk);
+       sketch->active_stroke = stk;
+}
+
+void sk_endStroke(SK_Sketch *sketch)
+{
+       sk_shrinkStrokeBuffer(sketch->active_stroke);
+       sketch->active_stroke = NULL;
+}
+
+void sk_updateDrawData(SK_DrawData *dd)
+{
+       dd->type = PT_CONTINUOUS;
+       
+       dd->previous_mval[0] = dd->mval[0];
+       dd->previous_mval[1] = dd->mval[1];
+}
+
+float sk_distanceDepth(float p1[3], float p2[3])
+{
+       float vec[3];
+       float distance;
+       
+       VecSubf(vec, p1, p2);
+       
+       Projf(vec, vec, G.vd->viewinv[2]);
+       
+       distance = VecLength(vec);
+       
+       if (Inpf(G.vd->viewinv[2], vec) > 0)
+       {
+               distance *= -1;
+       }
+       
+       return distance; 
+}
+
+void sk_interpolateDepth(SK_Stroke *stk, int start, int end, float length, float distance)
+{
+       float progress = 0;
+       int i;
+       
+       progress = VecLenf(stk->points[start].p, stk->points[start - 1].p);
+       
+       for (i = start; i <= end; i++)
+       {
+               float ray_start[3], ray_normal[3];
+               float delta = VecLenf(stk->points[i].p, stk->points[i + 1].p);
+               short pval[2];
+               
+               project_short_noclip(stk->points[i].p, pval);
+               viewray(pval, ray_start, ray_normal);
+               
+               VecMulf(ray_normal, distance * progress / length);
+               VecAddf(stk->points[i].p, stk->points[i].p, ray_normal);
+
+               progress += delta ;
+       }
+}
+
+void sk_projectDrawPoint(float vec[3], SK_Stroke *stk, SK_DrawData *dd)
+{
+       /* copied from grease pencil, need fixing */    
+       SK_Point *last = sk_lastStrokePoint(stk);
+       short cval[2];
+       //float *fp = give_cursor();
+       float fp[3] = {0, 0, 0};
+       float dvec[3];
+       
+       if (last != NULL)
+       {
+               VECCOPY(fp, last->p);
+       }
+       
+       initgrabz(fp[0], fp[1], fp[2]);
+       
+       /* method taken from editview.c - mouse_cursor() */
+       project_short_noclip(fp, cval);
+       window_to_3d(dvec, cval[0] - dd->mval[0], cval[1] - dd->mval[1]);
+       VecSubf(vec, fp, dvec);
+}
+
+int sk_getStrokeDrawPoint(SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
+{
+       pt->type = dd->type;
+       pt->mode = PT_PROJECT;
+       sk_projectDrawPoint(pt->p, stk, dd);
+       
+       return 1;
+}
+
+int sk_addStrokeDrawPoint(SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
+{
+       SK_Point pt;
+       
+       sk_getStrokeDrawPoint(&pt, sketch, stk, dd);
+
+       sk_appendStrokePoint(stk, &pt);
+       
+       return 1;
+}
+
+
+int sk_getStrokeSnapPoint(SK_Point *pt, SK_Sketch *sketch, SK_Stroke *source_stk, SK_DrawData *dd)
+{
+       SK_Stroke *stk;
+       int dist = SNAP_MIN_DISTANCE;
+       int point_added = 0;
+       
+       for (stk = sketch->strokes.first; stk; stk = stk->next)
+       {
+               SK_Point *spt = sk_snapPointStroke(stk, dd->mval, &dist);
+               
+               if (spt != NULL)
+               {
+                       VECCOPY(pt->p, spt->p);
+                       point_added = 1;
+               }
+       }
+       
+       /* check on bones */
+       {
+               SK_Point *spt = sk_snapPointArmature(&G.edbo, dd->mval, &dist);
+               
+               if (spt != NULL)
+               {
+                       VECCOPY(pt->p, spt->p);
+                       point_added = 1;
+               }
+       }
+       
+       if (point_added)
+       {
+               pt->type = PT_EXACT;
+               pt->mode = PT_SNAP;
+       }
+       
+       return point_added;
+}
+
+int sk_addStrokeSnapPoint(SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
+{
+       SK_Point pt;
+       int point_added = 0;
+       
+       point_added = sk_getStrokeSnapPoint(&pt, sketch, stk, dd);
+
+       if (point_added)
+       {
+               float final_p[3];
+               float distance;
+               float length;
+               int i, total;
+               
+               VECCOPY(final_p, pt.p);
+
+               sk_projectDrawPoint(pt.p, stk, dd);
+               sk_appendStrokePoint(stk, &pt);
+               
+               /* update all previous point to give smooth Z progresion */
+               total = 0;
+               length = 0;
+               for (i = stk->nb_points - 2; i > 0; i--)
+               {
+                       length += VecLenf(stk->points[i].p, stk->points[i + 1].p);
+                       total++;
+                       if (stk->points[i].type == PT_EXACT)
+                       {
+                               break;
+                       }
+               }
+               
+               if (total > 1)
+               {
+                       distance = sk_distanceDepth(final_p, stk->points[i].p);
+                       
+                       sk_interpolateDepth(stk, i + 1, stk->nb_points - 2, length, distance);
+               }
+       
+               VECCOPY(stk->points[stk->nb_points - 1].p, final_p);
+       }
+       
+       return point_added;
+}
+
+int sk_getStrokeEmbedPoint(SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
+{
+       ListBase depth_peels;
+       SK_DepthPeel *p1, *p2;
+       SK_Point *last_pt = NULL;
+       float dist = FLT_MAX;
+       float p[3];
+       int point_added = 0;
+       
+       depth_peels.first = depth_peels.last = NULL;
+       
+       peelObjects(&depth_peels, dd->mval);
+       
+       if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS)
+       {
+               last_pt = stk->points + (stk->nb_points - 1);
+       }
+       
+       
+       for (p1 = depth_peels.first; p1; p1 = p1->next)
+       {
+               if (p1->flag == 0)
+               {
+                       float vec[3];
+                       float new_dist;
+                       
+                       p1->flag = 0;
+                       
+                       for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next)
+                       {
+                               /* nothing to do here */
+                       }
+                       
+                       
+                       if (p2)
+                       {
+                               p2->flag = 1;
+                               
+                               VecAddf(vec, p1->p, p2->p);
+                               VecMulf(vec, 0.5f);
+                       }
+                       else
+                       {
+                               VECCOPY(vec, p1->p);
+                       }
+                       
+                       if (last_pt == NULL)
+                       {
+                               VECCOPY(p, vec);
+                               dist = 0;
+                               break;
+                       }
+                       
+                       new_dist = VecLenf(last_pt->p, vec);
+                       
+                       if (new_dist < dist)
+                       {
+                               VECCOPY(p, vec);
+                               dist = new_dist;
+                       }
+               }
+       }
+       
+       if (dist != FLT_MAX)
+       {
+               pt->type = dd->type;
+               pt->mode = PT_EMBED;
+               VECCOPY(pt->p, p);
+               
+               point_added = 1;
+       }
+       
+       BLI_freelistN(&depth_peels);
+       
+       return point_added;
+}
+
+int sk_addStrokeEmbedPoint(SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd)
+{
+       SK_Point pt;
+       int point_added;
+       
+       point_added = sk_getStrokeEmbedPoint(&pt, sketch, stk, dd);
+       
+       if (point_added)
+       {
+               float final_p[3];
+               float length, distance;
+               int total;
+               int i;
+               
+               VECCOPY(final_p, pt.p);
+               
+               sk_projectDrawPoint(pt.p, stk, dd);
+               sk_appendStrokePoint(stk, &pt);
+               
+               /* update all previous point to give smooth Z progresion */
+               total = 0;
+               length = 0;
+               for (i = stk->nb_points - 2; i > 0; i--)
+               {
+                       length += VecLenf(stk->points[i].p, stk->points[i + 1].p);
+                       total++;
+                       if (stk->points[i].mode == PT_EMBED || stk->points[i].type == PT_EXACT)
+                       {
+                               break;
+                       }
+               }
+               
+               if (total > 1)
+               {
+                       distance = sk_distanceDepth(final_p, stk->points[i].p);
+                       
+                       sk_interpolateDepth(stk, i + 1, stk->nb_points - 2, length, distance);
+               }
+               
+               VECCOPY(stk->points[stk->nb_points - 1].p, final_p);
+               
+               point_added = 1;
+       }
+       
+       return point_added;
+}
+
+void sk_addStrokePoint(SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short qual)
+{
+       int point_added = 0;
+       
+       if (qual & LR_CTRLKEY)
+       {
+               point_added = sk_addStrokeSnapPoint(sketch, stk, dd);
+       }
+       
+       if (point_added == 0 && qual & LR_SHIFTKEY)
+       {
+               point_added = sk_addStrokeEmbedPoint(sketch, stk, dd);
+       }
+       
+       if (point_added == 0)
+       {
+               point_added = sk_addStrokeDrawPoint(sketch, stk, dd);
+       }       
+}
+
+void sk_getStrokePoint(SK_Point *pt, SK_Sketch *sketch, SK_Stroke *stk, SK_DrawData *dd, short qual)
+{
+       int point_added = 0;
+       
+       if (qual & LR_CTRLKEY)
+       {
+               point_added = sk_getStrokeSnapPoint(pt, sketch, stk, dd);
+       }
+       
+       if (point_added == 0 && qual & LR_SHIFTKEY)
+       {
+               point_added = sk_getStrokeEmbedPoint(pt, sketch, stk, dd);
+       }
+       
+       if (point_added == 0)
+       {
+               point_added = sk_getStrokeDrawPoint(pt, sketch, stk, dd);
+       }       
+}
+
+void sk_endContinuousStroke(SK_Stroke *stk)
+{
+       stk->points[stk->nb_points - 1].type = PT_EXACT;
+}
+
+void sk_updateNextPoint(SK_Sketch *sketch)
+{
+       if (sketch->active_stroke)
+       {
+               SK_Stroke *stk = sketch->active_stroke;
+               memcpy(&sketch->next_point, stk->points[stk->nb_points - 1].p, sizeof(SK_Point));
+       }
+}
+
+int sk_stroke_filtermval(SK_DrawData *dd)
+{
+       int retval = 0;
+       if (dd->mval[0] != dd->previous_mval[0] || dd->mval[1] != dd->previous_mval[1])
+       {
+               retval = 1;
+       }
+       
+       return retval;
+}
+
+void sk_initDrawData(SK_DrawData *dd)
+{
+       getmouseco_areawin(dd->mval);
+       dd->previous_mval[0] = -1;
+       dd->previous_mval[1] = -1;
+       dd->type = PT_EXACT;
+}
+/********************************************/
+
+float calcStrokeCorrelation(SK_Stroke *stk, int start, int end, float v0[3], float n[3])
+{
+       int len = 2 + abs(end - start);
+       
+       if (len > 2)
+       {
+               float avg_t = 0.0f;
+               float s_t = 0.0f;
+               float s_xyz = 0.0f;
+               int i;
+               
+               /* First pass, calculate average */
+               for (i = start; i <= end; i++)
+               {
+                       float v[3];
+                       
+                       VecSubf(v, stk->points[i].p, v0);
+                       avg_t += Inpf(v, n);
+               }
+               
+               avg_t /= Inpf(n, n);
+               avg_t += 1.0f; /* adding start (0) and end (1) values */
+               avg_t /= len;
+               
+               /* Second pass, calculate s_xyz and s_t */
+               for (i = start; i <= end; i++)
+               {
+                       float v[3], d[3];
+                       float dt;
+                       
+                       VecSubf(v, stk->points[i].p, v0);
+                       Projf(d, v, n);
+                       VecSubf(v, v, d);
+                       
+                       dt = VecLength(d) - avg_t;
+                       
+                       s_t += dt * dt;
+                       s_xyz += Inpf(v, v);
+               }
+               
+               /* adding start(0) and end(1) values to s_t */
+               s_t += (avg_t * avg_t) + (1 - avg_t) * (1 - avg_t);
+               
+               return 1.0f - s_xyz / s_t; 
+       }
+       else
+       {
+               return 1.0f;
+       }
+}
+
+EditBone * subdivideStrokeByCorrelation(SK_Stroke *stk, int start, int end, float invmat[][4])
+{
+       bArmature *arm= G.obedit->data;
+       EditBone *lastBone = NULL;
+       float n[3];
+       float CORRELATION_THRESHOLD = G.scene->toolsettings->skgen_correlation_limit;
+       
+       if (G.scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION)
+       {
+               EditBone *child = NULL;
+               EditBone *parent = NULL;
+               int boneStart = start;
+               int i;
+
+               parent = addEditBone("Bone", &G.edbo, arm);
+               VECCOPY(parent->head, stk->points[start].p);
+               Mat4MulVecfl(invmat, parent->head);
+               
+               for (i = start + 1; i < end; i++)
+               {
+                       /* Calculate normal */
+                       VecSubf(n, stk->points[i].p, parent->head);
+
+                       if (calcStrokeCorrelation(stk, boneStart, i, parent->head, n) < CORRELATION_THRESHOLD)
+                       {
+                               VECCOPY(parent->tail, stk->points[i - 1].p);
+                               Mat4MulVecfl(invmat, parent->tail);
+
+                               child = addEditBone("Bone", &G.edbo, arm);
+                               VECCOPY(child->head, parent->tail);
+                               child->parent = parent;
+                               child->flag |= BONE_CONNECTED;
+                               
+                               parent = child; // new child is next parent
+                               boneStart = i; // start next bone from current index
+                       }
+               }
+
+               VECCOPY(parent->tail, stk->points[end].p);
+               Mat4MulVecfl(invmat, parent->tail);
+               lastBone = parent;
+       }
+       
+       return lastBone;
+}
+
+EditBone * subdivideStrokeByLength(SK_Stroke *stk, int start, int end, float invmat[][4])
+{
+       bArmature *arm= G.obedit->data;
+       EditBone *lastBone = NULL;
+       
+       if (G.scene->toolsettings->skgen_options & SKGEN_CUT_LENGTH)
+       {
+               EditBone *child = NULL;
+               EditBone *parent = NULL;
+               float lengthLimit = G.scene->toolsettings->skgen_length_limit;
+               int i;
+               int same = 0;
+               
+               parent = addEditBone("Bone", &G.edbo, arm);
+               VECCOPY(parent->head, stk->points[start].p);
+
+               i = start + 1;
+               while (i < end)
+               {
+                       float *vec0 = stk->points[i - 1].p;
+                       float *vec1 = stk->points[i].p;
+
+                       /* If lengthLimit hits the current segment */
+                       if (VecLenf(vec1, parent->head) > lengthLimit)
+                       {
+                               if (same == 0)
+                               {
+                                       float dv[3], off[3];
+                                       float a, b, c, f;
+                                       
+                                       /* Solve quadratic distance equation */
+                                       VecSubf(dv, vec1, vec0);
+                                       a = Inpf(dv, dv);
+                                       
+                                       VecSubf(off, vec0, parent->head);
+                                       b = 2 * Inpf(dv, off);
+                                       
+                                       c = Inpf(off, off) - (lengthLimit * lengthLimit);
+                                       
+                                       f = (-b + (float)sqrt(b * b - 4 * a * c)) / (2 * a);
+                                       
+                                       //printf("a %f, b %f, c %f, f %f\n", a, b, c, f);
+                                       
+                                       if (isnan(f) == 0 && f < 1.0f)
+                                       {
+                                               VECCOPY(parent->tail, dv);
+                                               VecMulf(parent->tail, f);
+                                               VecAddf(parent->tail, parent->tail, vec0);
+                                       }
+                                       else
+                                       {
+                                               VECCOPY(parent->tail, vec1);
+                                       }
+                               }
+                               else
+                               {
+                                       float dv[3];
+                                       
+                                       VecSubf(dv, vec1, vec0);
+                                       Normalize(dv);
+                                        
+                                       VECCOPY(parent->tail, dv);
+                                       VecMulf(parent->tail, lengthLimit);
+                                       VecAddf(parent->tail, parent->tail, parent->head);
+                               }
+                               
+                               /* put head in correct space */
+                               Mat4MulVecfl(invmat, parent->head);
+                               
+                               child = addEditBone("Bone", &G.edbo, arm);
+                               VECCOPY(child->head, parent->tail);
+                               child->parent = parent;
+                               child->flag |= BONE_CONNECTED;
+                               
+                               parent = child; // new child is next parent
+                               
+                               same = 1; // mark as same
+                       }
+                       else
+                       {
+                               i++;
+                               same = 0; // Reset same
+                       }
+               }
+               VECCOPY(parent->tail, stk->points[end].p);
+               Mat4MulVecfl(invmat, parent->tail);
+               lastBone = parent;
+       }
+       
+       return lastBone;
+}
+
+void sk_convertStroke(SK_Stroke *stk)
+{
+       bArmature *arm= G.obedit->data;
+       SK_Point *head;
+       EditBone *parent = NULL;
+       float invmat[4][4]; /* move in caller function */
+       int head_index = 0;
+       int i;
+       
+       head = NULL;
+       
+       Mat4Invert(invmat, G.obedit->obmat);
+       
+       for (i = 0; i < stk->nb_points; i++)
+       {
+               SK_Point *pt = stk->points + i;
+               
+               if (pt->type == PT_EXACT)
+               {
+                       if (head == NULL)
+                       {
+                               head_index = i;
+                               head = pt;
+                       }
+                       else
+                       {
+                               EditBone *bone = NULL;
+                               EditBone *new_parent;
+                               
+                               if (i - head_index > 1)
+                               {
+                                       bone = subdivideStrokeByCorrelation(stk, head_index, i, invmat);
+                                       
+                                       if (bone == NULL)
+                                       {
+                                               bone = subdivideStrokeByLength(stk, head_index, i, invmat);
+                                       }
+                               }
+                               
+                               if (bone == NULL)
+                               {
+                                       bone = addEditBone("Bone", &G.edbo, arm);
+                                       
+                                       VECCOPY(bone->head, head->p);
+                                       VECCOPY(bone->tail, pt->p);
+                                       
+                                       Mat4MulVecfl(invmat, bone->head);
+                                       Mat4MulVecfl(invmat, bone->tail);
+                               }
+                               
+                               new_parent = bone;
+                               bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
+                               
+                               /* move to end of chain */
+                               while (bone->parent != NULL)
+                               {
+                                       bone = bone->parent;
+                                       bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
+                               }
+
+                               if (parent != NULL)
+                               {
+                                       bone->parent = parent;
+                                       bone->flag |= BONE_CONNECTED;                                   
+                               }
+                               
+                               parent = new_parent;
+                               head_index = i;
+                               head = pt;
+                       }
+               }
+       }
+}
+
+void sk_convert(SK_Sketch *sketch)
+{
+       SK_Stroke *stk;
+       
+       for (stk = sketch->strokes.first; stk; stk = stk->next)
+       {
+               if (stk->selected == 1)
+               {
+                       sk_convertStroke(stk);
+               }
+       }
+}
+/******************* GESTURE *************************/
+
+
+/* returns the number of self intersections */
+int sk_getSelfIntersections(ListBase *list, SK_Stroke *gesture)
+{
+       int added = 0;
+       int s_i;
+
+       for (s_i = 0; s_i < gesture->nb_points - 1; s_i++)
+       {
+               float s_p1[3] = {0, 0, 0};
+               float s_p2[3] = {0, 0, 0};
+               int g_i;
+               
+               project_float(gesture->points[s_i].p, s_p1);
+               project_float(gesture->points[s_i + 1].p, s_p2);
+
+               /* start checking from second next, because two consecutive cannot intersect */
+               for (g_i = s_i + 2; g_i < gesture->nb_points - 1; g_i++)
+               {
+                       float g_p1[3] = {0, 0, 0};
+                       float g_p2[3] = {0, 0, 0};
+                       float vi[3];
+                       float lambda;
+                       
+                       project_float(gesture->points[g_i].p, g_p1);
+                       project_float(gesture->points[g_i + 1].p, g_p2);
+                       
+                       if (LineIntersectLineStrict(s_p1, s_p2, g_p1, g_p2, vi, &lambda))
+                       {
+                               SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection");
+                               
+                               isect->start = s_i;
+                               isect->end = g_i + 1;
+                               isect->stroke = gesture;
+                               
+                               VecSubf(isect->p, gesture->points[s_i + 1].p, gesture->points[s_i].p);
+                               VecMulf(isect->p, lambda);
+                               VecAddf(isect->p, isect->p, gesture->points[s_i].p);
+                               
+                               BLI_addtail(list, isect);
+
+                               added++;
+                       }
+               }
+       }
+       
+       return added;
+}
+
+
+/* returns the maximum number of intersections per stroke */
+int sk_getIntersections(ListBase *list, SK_Sketch *sketch, SK_Stroke *gesture)
+{
+       SK_Stroke *stk;
+       int added = 0;
+
+       for (stk = sketch->strokes.first; stk; stk = stk->next)
+       {
+               int s_added = 0;
+               int s_i;
+               
+               for (s_i = 0; s_i < stk->nb_points - 1; s_i++)
+               {
+                       float s_p1[3] = {0, 0, 0};
+                       float s_p2[3] = {0, 0, 0};
+                       int g_i;
+                       
+                       project_float(stk->points[s_i].p, s_p1);
+                       project_float(stk->points[s_i + 1].p, s_p2);
+
+                       for (g_i = 0; g_i < gesture->nb_points - 1; g_i++)
+                       {
+                               float g_p1[3] = {0, 0, 0};
+                               float g_p2[3] = {0, 0, 0};
+                               float vi[3];
+                               float lambda;
+                               
+                               project_float(gesture->points[g_i].p, g_p1);
+                               project_float(gesture->points[g_i + 1].p, g_p2);
+                               
+                               if (LineIntersectLineStrict(s_p1, s_p2, g_p1, g_p2, vi, &lambda))
+                               {
+                                       SK_Intersection *isect = MEM_callocN(sizeof(SK_Intersection), "Intersection");
+                                       float ray_start[3], ray_end[3];
+                                       short mval[2];
+                                       
+                                       isect->start = s_i;
+                                       isect->end = s_i + 1;
+                                       isect->stroke = stk;
+                                       
+                                       mval[0] = (short)(vi[0]);
+                                       mval[1] = (short)(vi[1]);
+                                       viewline(mval, ray_start, ray_end);
+                                       
+                                       LineIntersectLine(      stk->points[s_i].p,
+                                                                               stk->points[s_i + 1].p,
+                                                                               ray_start,
+                                                                               ray_end,
+                                                                               isect->p,
+                                                                               vi);
+                                       
+                                       BLI_addtail(list, isect);
+
+                                       s_added++;
+                               }
+                       }
+               }
+               
+               added = MAX2(s_added, added);
+       }
+       
+       
+       return added;
+}
+
+int sk_getSegments(SK_Stroke *segments, SK_Stroke *gesture)
+{
+       float CORRELATION_THRESHOLD = 0.995f;
+       float *vec;
+       int i, j;
+       
+       sk_appendStrokePoint(segments, &gesture->points[0]);
+       vec = segments->points[segments->nb_points - 1].p;
+
+       for (i = 1, j = 0; i < gesture->nb_points; i++)
+       { 
+               float n[3];
+               
+               /* Calculate normal */
+               VecSubf(n, gesture->points[i].p, vec);
+               
+               if (calcStrokeCorrelation(gesture, j, i, vec, n) < CORRELATION_THRESHOLD)
+               {
+                       j = i - 1;
+                       sk_appendStrokePoint(segments, &gesture->points[j]);
+                       vec = segments->points[segments->nb_points - 1].p;
+                       segments->points[segments->nb_points - 1].type = PT_EXACT;
+               }
+       }
+
+       sk_appendStrokePoint(segments, &gesture->points[gesture->nb_points - 1]);
+       
+       return segments->nb_points - 1;
+}
+
+void sk_applyCutGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+       SK_Intersection *isect;
+       
+       for (isect = list->first; isect; isect = isect->next)
+       {
+               SK_Point pt;
+               
+               pt.type = PT_EXACT;
+               pt.mode = PT_PROJECT; /* take mode from neighbouring points */
+               VECCOPY(pt.p, isect->p);
+               
+               sk_insertStrokePoint(isect->stroke, &pt, isect->end);
+       }
+}
+
+int sk_detectTrimGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+       float s1[3], s2[3];
+       float angle;
+       
+       VecSubf(s1, segments->points[1].p, segments->points[0].p);
+       VecSubf(s2, segments->points[2].p, segments->points[1].p);
+       
+       angle = VecAngle2(s1, s2);
+       
+       if (angle > 60 && angle < 120)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+void sk_applyTrimGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+       SK_Intersection *isect;
+       float trim_dir[3];
+       
+       VecSubf(trim_dir, segments->points[2].p, segments->points[1].p);
+       
+       for (isect = list->first; isect; isect = isect->next)
+       {
+               SK_Point pt;
+               float stroke_dir[3];
+               
+               pt.type = PT_EXACT;
+               pt.mode = PT_PROJECT; /* take mode from neighbouring points */
+               VECCOPY(pt.p, isect->p);
+               
+               VecSubf(stroke_dir, isect->stroke->points[isect->end].p, isect->stroke->points[isect->start].p);
+               
+               /* same direction, trim end */
+               if (Inpf(stroke_dir, trim_dir) > 0)
+               {
+                       sk_replaceStrokePoint(isect->stroke, &pt, isect->end);
+                       sk_trimStroke(isect->stroke, 0, isect->end);
+               }
+               /* else, trim start */
+               else
+               {
+                       sk_replaceStrokePoint(isect->stroke, &pt, isect->start);
+                       sk_trimStroke(isect->stroke, isect->start, isect->stroke->nb_points - 1);
+               }
+       
+       }
+}
+
+int sk_detectDeleteGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+       float s1[3], s2[3];
+       float angle;
+       
+       VecSubf(s1, segments->points[1].p, segments->points[0].p);
+       VecSubf(s2, segments->points[2].p, segments->points[1].p);
+       
+       angle = VecAngle2(s1, s2);
+       
+       if (angle > 120)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+void sk_applyDeleteGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+       SK_Intersection *isect;
+       
+       for (isect = list->first; isect; isect = isect->next)
+       {
+               /* only delete strokes that are crossed twice */
+               if (isect->next && isect->next->stroke == isect->stroke)
+               {
+                       isect = isect->next;
+                       
+                       BLI_remlink(&sketch->strokes, isect->stroke);
+                       sk_freeStroke(isect->stroke);
+               }
+       }
+}
+
+int sk_detectMergeGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+       short start_val[2], end_val[2];
+       short dist;
+       
+       project_short_noclip(gesture->points[0].p, start_val);
+       project_short_noclip(gesture->points[gesture->nb_points - 1].p, end_val);
+       
+       dist = MAX2(ABS(start_val[0] - end_val[0]), ABS(start_val[1] - end_val[1]));
+       
+       /* if gesture is a circle */
+       if ( dist <= 20 )
+       {
+               SK_Intersection *isect;
+               
+               /* check if it circled around an exact point */
+               for (isect = list->first; isect; isect = isect->next)
+               {
+                       /* only delete strokes that are crossed twice */
+                       if (isect->next && isect->next->stroke == isect->stroke)
+                       {
+                               int start_index, end_index;
+                               int i;
+                               
+                               start_index = MIN2(isect->end, isect->next->end);
+                               end_index = MAX2(isect->start, isect->next->start);
+
+                               for (i = start_index; i <= end_index; i++)
+                               {
+                                       if (isect->stroke->points[i].type == PT_EXACT)
+                                       {
+                                               return 1; /* at least one exact point found, stop detect here */
+                                       }
+                               }
+
+                               /* skip next */                         
+                               isect = isect->next;
+                       }
+               }
+                       
+               return 0;
+       }
+       else
+       {
+               return 0;
+       }
+}
+
+void sk_applyMergeGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+       SK_Intersection *isect;
+       
+       /* check if it circled around an exact point */
+       for (isect = list->first; isect; isect = isect->next)
+       {
+               /* only delete strokes that are crossed twice */
+               if (isect->next && isect->next->stroke == isect->stroke)
+               {
+                       int start_index, end_index;
+                       int i;
+                       
+                       start_index = MIN2(isect->end, isect->next->end);
+                       end_index = MAX2(isect->start, isect->next->start);
+
+                       for (i = start_index; i <= end_index; i++)
+                       {
+                               /* if exact, switch to continuous */
+                               if (isect->stroke->points[i].type == PT_EXACT)
+                               {
+                                       isect->stroke->points[i].type = PT_CONTINUOUS;
+                               }
+                       }
+
+                       /* skip next */                         
+                       isect = isect->next;
+               }
+       }
+}
+
+void sk_applyGesture(SK_Sketch *sketch)
+{
+       ListBase intersections;
+       ListBase self_intersections;
+       SK_Stroke *segments = sk_createStroke();
+       int nb_self_intersections, nb_intersections, nb_segments;
+       
+       intersections.first = intersections.last = NULL;
+       self_intersections.first = self_intersections.last = NULL;
+       
+       nb_self_intersections = sk_getSelfIntersections(&self_intersections, sketch->gesture);
+       nb_intersections = sk_getIntersections(&intersections, sketch, sketch->gesture);
+       nb_segments = sk_getSegments(segments, sketch->gesture);
+       
+       /* detect and apply */
+       if (nb_segments == 1 && nb_intersections == 1)
+       {
+               sk_applyCutGesture(sketch, sketch->gesture, &intersections, segments);
+       }
+       else if (nb_segments == 2 && nb_intersections == 1 && sk_detectTrimGesture(sketch, sketch->gesture, &intersections, segments))
+       {
+               sk_applyTrimGesture(sketch, sketch->gesture, &intersections, segments);
+       }
+       else if (nb_segments == 2 && nb_intersections == 2 && sk_detectDeleteGesture(sketch, sketch->gesture, &intersections, segments))
+       {
+               sk_applyDeleteGesture(sketch, sketch->gesture, &intersections, segments);
+       }
+       else if (nb_segments > 2 && nb_intersections == 2 && sk_detectMergeGesture(sketch, sketch->gesture, &intersections, segments))
+       {
+               sk_applyMergeGesture(sketch, sketch->gesture, &intersections, segments);
+       }
+       else if (nb_segments > 2 && nb_self_intersections == 1)
+       {
+               sk_convert(sketch);
+               BIF_undo_push("Convert Sketch");
+               allqueue(REDRAWBUTSEDIT, 0);
+       }
+       
+       sk_freeStroke(segments);
+       BLI_freelistN(&intersections);
+       BLI_freelistN(&self_intersections);
+}
+
+/********************************************/
+
+void sk_deleteStrokes(SK_Sketch *sketch)
+{
+       SK_Stroke *stk, *next;
+       
+       for (stk = sketch->strokes.first; stk; stk = next)
+       {
+               next = stk->next;
+               
+               if (stk->selected == 1)
+               {
+                       BLI_remlink(&sketch->strokes, stk);
+                       sk_freeStroke(stk);
+               }
+       }
+}
+
+void sk_selectAllSketch(SK_Sketch *sketch, int mode)
+{
+       SK_Stroke *stk = NULL;
+       
+       if (mode == -1)
+       {
+               for (stk = sketch->strokes.first; stk; stk = stk->next)
+               {
+                       stk->selected = 0;
+               }
+       }
+       else if (mode == 0)
+       {
+               for (stk = sketch->strokes.first; stk; stk = stk->next)
+               {
+                       stk->selected = 1;
+               }
+       }
+       else if (mode == 1)
+       {
+               int selected = 1;
+               
+               for (stk = sketch->strokes.first; stk; stk = stk->next)
+               {
+                       selected &= stk->selected;
+               }
+               
+               selected ^= 1;
+
+               for (stk = sketch->strokes.first; stk; stk = stk->next)
+               {
+                       stk->selected = selected;
+               }
+       }
+}
+
+void sk_selectStroke(SK_Sketch *sketch)
+{
+       unsigned int buffer[MAXPICKBUF];
+       short hits, mval[2];
+
+       persp(PERSP_VIEW);
+
+       getmouseco_areawin(mval);
+       hits = view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-5, mval[1]-5, mval[0]+5, mval[1]+5);
+       if(hits==0)
+               hits = view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-12, mval[1]-12, mval[0]+12, mval[1]+12);
+               
+       if (hits>0)
+       {
+               int besthitresult = -1;
+                       
+               if(hits == 1) {
+                       besthitresult = buffer[3];
+               }
+               else {
+                       besthitresult = buffer[3];
+                       /* loop and get best hit */
+               }
+               
+               if (besthitresult > 0)
+               {
+                       SK_Stroke *selected_stk = BLI_findlink(&sketch->strokes, besthitresult - 1);
+                       
+                       if ((G.qual & LR_SHIFTKEY) == 0)
+                       {
+                               sk_selectAllSketch(sketch, -1);
+                               
+                               selected_stk->selected = 1;
+                       }
+                       else
+                       {
+                               selected_stk->selected ^= 1;
+                       }
+                       
+                       
+               }
+       }
+}
+
+void sk_queueRedrawSketch(SK_Sketch *sketch)
+{
+       if (sketch->active_stroke != NULL)
+       {
+               SK_Point *last = sk_lastStrokePoint(sketch->active_stroke);
+               
+               if (last != NULL)
+               {
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+       }
+}
+
+void sk_drawSketch(SK_Sketch *sketch, int with_names)
+{
+       SK_Stroke *stk;
+       
+       glDisable(GL_DEPTH_TEST);
+
+       glLineWidth(BIF_GetThemeValuef(TH_VERTEX_SIZE));
+       glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
+       
+       if (with_names)
+       {
+               int id;
+               for (id = 1, stk = sketch->strokes.first; stk; id++, stk = stk->next)
+               {
+                       sk_drawStroke(stk, id, NULL);
+               }
+               
+               glLoadName(-1);
+       }
+       else
+       {
+               float selected_rgb[3] = {1, 0, 0};
+               float unselected_rgb[3] = {1, 0.5, 0};
+               
+               for (stk = sketch->strokes.first; stk; stk = stk->next)
+               {
+                       sk_drawStroke(stk, -1, (stk->selected==1?selected_rgb:unselected_rgb));
+               }
+       
+               /* only draw gesture in active area */
+               if (sketch->gesture != NULL && area_is_active_area(G.vd->area))
+               {
+                       float gesture_rgb[3] = {0, 0.5, 1};
+                       sk_drawStroke(sketch->gesture, -1, gesture_rgb);
+               }
+               
+               if (sketch->active_stroke != NULL)
+               {
+                       SK_Point *last = sk_lastStrokePoint(sketch->active_stroke);
+                       
+                       if (last != NULL)
+                       {
+                               /* update point if in active area */
+                               if (area_is_active_area(G.vd->area))
+                               {
+                                       SK_DrawData dd;
+                                       
+                                       sk_initDrawData(&dd);
+                                       sk_getStrokePoint(&sketch->next_point, sketch, sketch->active_stroke, &dd, G.qual);
+                               }
+                               
+                               glEnable(GL_LINE_STIPPLE);
+                               glColor3f(1, 0.5, 0);
+                               glBegin(GL_LINE_STRIP);
+                               
+                                       glVertex3fv(last->p);
+                                       glVertex3fv(sketch->next_point.p);
+                               
+                               glEnd();
+                               
+                               glDisable(GL_LINE_STIPPLE);
+       
+                               switch (sketch->next_point.mode)
+                               {
+                                       case PT_SNAP:
+                                               glColor3f(0, 0.5, 1);
+                                               break;
+                                       case PT_EMBED:
+                                               glColor3f(0, 1, 0);
+                                               break;
+                                       case PT_PROJECT:
+                                               glColor3f(0, 0, 0);
+                                               break;
+                               }
+                               
+                               glBegin(GL_POINTS);
+                               
+                                       glVertex3fv(sketch->next_point.p);
+                               
+                               glEnd();
+                       }
+               }
+       }
+       
+       glLineWidth(1.0);
+       glPointSize(1.0);
+
+       glEnable(GL_DEPTH_TEST);
+}
+
+int sk_paint(SK_Sketch *sketch, short mbut)
+{
+       int retval = 1;
+       
+       if (mbut == LEFTMOUSE)
+       {
+               SK_DrawData dd;
+               if (sketch->active_stroke == NULL)
+               {
+                       sk_startStroke(sketch);
+               }
+
+               sk_initDrawData(&dd);
+               
+               /* paint loop */
+               do {
+                       /* get current user input */
+                       getmouseco_areawin(dd.mval);
+                       
+                       /* only add current point to buffer if mouse moved (otherwise wait until it does) */
+                       if (sk_stroke_filtermval(&dd)) {
+
+                               sk_addStrokePoint(sketch, sketch->active_stroke, &dd, G.qual);
+                               sk_updateDrawData(&dd);
+                               force_draw(0);
+                       }
+                       else
+                       {
+                               BIF_wait_for_statechange();
+                       }
+                       
+                       while( qtest() ) {
+                               short event, val;
+                               event = extern_qread(&val);
+                       }
+                       
+                       /* do mouse checking at the end, so don't check twice, and potentially
+                        * miss a short tap 
+                        */
+               } while (get_mbut() & L_MOUSE);
+               
+               sk_endContinuousStroke(sketch->active_stroke);
+               sk_filterLastContinuousStroke(sketch->active_stroke);
+               sk_updateNextPoint(sketch);
+       }
+       else if (mbut == RIGHTMOUSE)
+       {
+               if (sketch->active_stroke != NULL)
+               {
+                       sk_endStroke(sketch);
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+               else
+               {
+                       SK_DrawData dd;
+                       sketch->gesture = sk_createStroke();
+       
+                       sk_initDrawData(&dd);
+                       
+                       /* paint loop */
+                       do {
+                               /* get current user input */
+                               getmouseco_areawin(dd.mval);
+                               
+                               /* only add current point to buffer if mouse moved (otherwise wait until it does) */
+                               if (sk_stroke_filtermval(&dd)) {
+
+                                       sk_addStrokeDrawPoint(sketch, sketch->gesture, &dd);
+                                       sk_updateDrawData(&dd);
+                                       
+                                       /* draw only if mouse has moved */
+                                       if (sketch->gesture->nb_points > 1)
+                                       {
+                                               force_draw(0);
+                                       }
+                               }
+                               else
+                               {
+                                       BIF_wait_for_statechange();
+                               }
+                               
+                               while( qtest() ) {
+                                       short event, val;
+                                       event = extern_qread(&val);
+                               }
+                               
+                               /* do mouse checking at the end, so don't check twice, and potentially
+                                * miss a short tap 
+                                */
+                       } while (get_mbut() & R_MOUSE);
+                       
+                       sk_endContinuousStroke(sketch->gesture);
+                       sk_filterLastContinuousStroke(sketch->gesture);
+                       sk_filterLastContinuousStroke(sketch->gesture);
+                       sk_filterLastContinuousStroke(sketch->gesture);
+       
+                       if (sketch->gesture->nb_points == 1)            
+                       {
+                               sk_selectStroke(sketch);
+                       }
+                       else
+                       {
+                               /* apply gesture here */
+                               sk_applyGesture(sketch);
+                       }
+       
+                       sk_freeStroke(sketch->gesture);
+                       sketch->gesture = NULL;
+                       
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+       }
+       
+       return retval;
+}
+
+void BDR_drawSketchNames()
+{
+       if (BIF_validSketchMode())
+       {
+               if (GLOBAL_sketch != NULL)
+               {
+                       sk_drawSketch(GLOBAL_sketch, 1);
+               }
+       }
+}
+
+void BDR_drawSketch()
+{
+       if (BIF_validSketchMode())
+       {
+               if (GLOBAL_sketch != NULL)
+               {
+                       sk_drawSketch(GLOBAL_sketch, 0);
+               }
+       }
+}
+
+void BIF_endStrokeSketch()
+{
+       if (BIF_validSketchMode())
+       {
+               if (GLOBAL_sketch != NULL)
+               {
+                       sk_endStroke(GLOBAL_sketch);
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+       }
+}
+
+void BIF_deleteSketch()
+{
+       if (BIF_validSketchMode())
+       {
+               if (GLOBAL_sketch != NULL)
+               {
+                       sk_deleteStrokes(GLOBAL_sketch);
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+       }
+}
+
+void BIF_convertSketch()
+{
+       if (BIF_validSketchMode())
+       {
+               if (GLOBAL_sketch != NULL)
+               {
+                       sk_convert(GLOBAL_sketch);
+                       BIF_undo_push("Convert Sketch");
+                       allqueue(REDRAWVIEW3D, 0);
+                       allqueue(REDRAWBUTSEDIT, 0);
+               }
+       }
+}
+
+int BIF_paintSketch(short mbut)
+{
+       if (BIF_validSketchMode())
+       {
+               if (GLOBAL_sketch == NULL)
+               {
+                       GLOBAL_sketch = sk_createSketch();
+               }
+               
+               return sk_paint(GLOBAL_sketch, mbut);
+       }
+       else
+       {
+               return 0;
+       }
+}
+       
+
+void BDR_queueDrawSketch()
+{
+       if (BIF_validSketchMode())
+       {
+               if (GLOBAL_sketch != NULL)
+               {
+                       sk_queueRedrawSketch(GLOBAL_sketch);
+               }
+       }
+}
+
+void BIF_selectAllSketch(int mode)
+{
+       if (BIF_validSketchMode())
+       {
+               if (GLOBAL_sketch != NULL)
+               {
+                       sk_selectAllSketch(GLOBAL_sketch, mode);
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+       }
+}
+
+int BIF_validSketchMode()
+{
+       if (G.obedit && 
+               G.obedit->type == OB_ARMATURE && 
+               G.scene->toolsettings->bone_sketching & BONE_SKETCHING)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
index 5c215dcdd46153b938f3c10044c5045a94005f60..c16e2001ff9b98946f30c9d02cbf6b17478e6f35 100644 (file)
@@ -3951,6 +3951,9 @@ static void do_view3d_edit_armaturemenu(void *arg, int event)
        case 22: /* separate */
                separate_armature();
                break;
+       case 23: /* bone sketching panel */
+               add_blockhandler(curarea, VIEW3D_HANDLER_BONESKETCH, UI_PNL_UNSTOW);
+               break;
        }
        
        allqueue(REDRAWVIEW3D, 0);
@@ -4027,6 +4030,7 @@ static uiBlock *view3d_edit_armaturemenu(void *arg_unused)
        uiDefBut(block, SEPR, 0, "",                            0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
        
        uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+       uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Bone Sketching|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 23, "");
        uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
        uiDefIconTextBlockBut(block, view3d_edit_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, menuwidth, 19, "");
        uiDefIconTextBlockBut(block, view3d_edit_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 19, "");
index 6cd573c580ddf2be9c6e39db644a92bc1e7ee731..71c31fea209f043266bf281f9b568d2c2aa63025 100644 (file)
 #include "BIF_toolbox.h"
 #include "BIF_usiblender.h"
 #include "BIF_previewrender.h"
+#include "BIF_sketch.h"
 
 #include "BSE_edit.h"
 #include "BSE_view.h"
 #include "BDR_sculptmode.h"
 #include "BDR_unwrapper.h"
 #include "BDR_gpencil.h"
+#include "BDR_sketch.h"
 
 #include "BLO_readfile.h" /* for BLO_blendhandle_close */
 
@@ -1254,11 +1256,13 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                        return; /* return if event was processed (swallowed) by handler(s) */
                        }
                        
+                       if(BIF_paintSketch(LEFTMOUSE)) return;
                        if(gpencil_do_paint(sa, L_MOUSE)) return;
                        if(BIF_do_manipulator(sa)) return;
                }
                else if(event==RIGHTMOUSE) {
                        if(gpencil_do_paint(sa, R_MOUSE)) return;
+                       if(BIF_paintSketch(RIGHTMOUSE)) return;
                }
                
                /* swap mouse buttons based on user preference */
@@ -1301,6 +1305,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                        }
                                }
                        }
+                       
+                       BDR_queueDrawSketch();
 
                        /* Handle retopo painting */
                        if(retopo_mesh_paint_check()) {
@@ -1901,7 +1907,16 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                                else if(G.obedit->type==OB_LATTICE)
                                                        deselectall_Latt();
                                                else if(G.obedit->type==OB_ARMATURE)
-                                                       deselectall_armature(1, 1);     /* 1 == toggle */
+                                               {
+                                                       if (G.scene->toolsettings->bone_sketching & BONE_SKETCHING)
+                                                       {
+                                                               BIF_selectAllSketch(1);
+                                                       }
+                                                       else
+                                                       {
+                                                               deselectall_armature(1, 1);     /* 1 == toggle */
+                                                       }
+                                               }
                                        }
                                        else if (ob && (ob->flag & OB_POSEMODE)){
                                                deselectall_posearmature(ob, 1, 1);
@@ -1969,6 +1984,10 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                else if(G.qual==LR_ALTKEY) {
                                        if(ob && (ob->flag & OB_POSEMODE))
                                                pose_clear_constraints();       /* poseobject.c */
+                                       else if (BIF_validSketchMode())
+                                       {
+                                               BIF_convertSketch();
+                                       }
                                        else
                                                convertmenu();  /* editobject.c */
                                }
@@ -2776,7 +2795,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                        case DELKEY:
                                if(G.qual==0 || G.qual==LR_SHIFTKEY)
                                        delete_context_selected();
-                               if(G.qual==LR_ALTKEY)
+                               else if(G.qual==LR_ALTKEY)
                                        gpencil_delete_menu();
                                break;
                        case YKEY:
@@ -2938,7 +2957,11 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                break;
 
                        case ESCKEY:
-                               if(G.qual==0) {
+                               if (G.qual == 0 && BIF_validSketchMode())
+                               {
+                                       BIF_endStrokeSketch();
+                               }
+                               else if(G.qual==0) {
                                        if (G.vd->flag & V3D_DISPIMAGE) {
                                                G.vd->flag &= ~V3D_DISPIMAGE;
                                                doredraw= 1;
index 66af3539e88e8aebbaec4d2cb7caa53ec9d16ca9..0687faaeec843a9aabbd98ff0e1bf5921dff9169 100644 (file)
@@ -83,6 +83,7 @@
 #include "BDR_drawobject.h"    /* For draw_object */
 #include "BDR_editface.h"      /* For minmax_tface */
 #include "BDR_sculptmode.h"
+#include "BDR_sketch.h"
 
 #include "mydevice.h"
 #include "blendef.h"
@@ -1884,7 +1885,14 @@ short  view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1
                draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
        }
        else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
-               draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
+               if (G.scene->toolsettings->bone_sketching & BONE_SKETCHING)
+               {
+                       BDR_drawSketchNames();
+               }
+               else
+               {
+                       draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
+               }
        }
        else {
                Base *base;