merging trunk 17457:17485
authorMartin Poirier <theeth@yahoo.com>
Mon, 17 Nov 2008 22:19:05 +0000 (22:19 +0000)
committerMartin Poirier <theeth@yahoo.com>
Mon, 17 Nov 2008 22:19:05 +0000 (22:19 +0000)
27 files changed:
source/blender/blenkernel/BKE_blender.h
source/blender/blenkernel/BKE_global.h
source/blender/blenkernel/intern/object.c
source/blender/blenlib/BLI_arithb.h
source/blender/blenlib/intern/arithb.c
source/blender/blenlib/intern/graph.c
source/blender/blenloader/intern/readfile.c
source/blender/include/BDR_sketch.h [new file with mode: 0644]
source/blender/include/BIF_editarmature.h
source/blender/include/BIF_retarget.h [new file with mode: 0644]
source/blender/include/BIF_sketch.h [new file with mode: 0644]
source/blender/include/BIF_space.h
source/blender/include/reeb.h
source/blender/makesdna/DNA_scene_types.h
source/blender/python/api2_2x/Armature.c
source/blender/python/api2_2x/Bone.c
source/blender/src/buttons_editing.c
source/blender/src/drawview.c
source/blender/src/edit.c
source/blender/src/editarmature.c
source/blender/src/editarmature_retarget.c [moved from source/blender/src/autoarmature.c with 77% similarity]
source/blender/src/editarmature_sketch.c [new file with mode: 0644]
source/blender/src/gpencil.c
source/blender/src/header_view3d.c
source/blender/src/space.c
source/blender/src/usiblender.c
source/blender/src/view.c

index f392d57521cb9e94285f7b4c376b07863ff3395d..a6334e665d1076a438ed9853f473e20175599520 100644 (file)
@@ -41,7 +41,7 @@ struct ListBase;
 struct MemFile;
 
 #define BLENDER_VERSION                        248
-#define BLENDER_SUBVERSION             1
+#define BLENDER_SUBVERSION             2
 
 #define BLENDER_MINVERSION             245
 #define BLENDER_MINSUBVERSION  15
index 3a2dca525b8d484e23b2a6020dd6c48e8ce7eab8..bb474d3f8c8c072d57d0234949868e17d6aa51bf 100644 (file)
@@ -151,7 +151,6 @@ typedef struct Global {
        
        /* confusing... G.f and G.flags */
        int flags;
-
 } Global;
 
 /* **************** GLOBAL ********************* */
index a25afeafaef5fb3edd115b3ff865439c82d6cecb..0b153c3c065a9b1ec4400d492a55cfcd7c1248bc 100644 (file)
@@ -521,6 +521,7 @@ void unlink_object(Object *ob)
        while(sce) {
                if(sce->id.lib==NULL) {
                        if(sce->camera==ob) sce->camera= NULL;
+                       if(sce->toolsettings->skgen_template==ob) sce->toolsettings->skgen_template = NULL;
                }
                sce= sce->id.next;
        }
index e4b983d9ba307f2bf78132d204e388b45762855b..1d4b5cf16b29efd2f86f8b11bf7e3242a5d3a2e7 100644 (file)
@@ -390,6 +390,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 e606092f72d58300607216785f0ea821420d36df..783acb9cc971d24e5ab822f48754a936516cf5c2 100644 (file)
@@ -4238,6 +4238,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] &&
index 8f35b38379e6c0b83f21f909ee286566b5a363ce..e2ed8f11ee289ac56d76dcd4dd2dbcd5f8b29e25 100644 (file)
@@ -1033,6 +1033,11 @@ void BLI_markdownSymmetry(BGraph *graph, BNode *root_node, float limit)
        BNode *node;
        BArc *arc;
        
+       if (root_node == NULL)
+       {
+               return;
+       }
+       
        if (BLI_isGraphCyclic(graph))
        {
                return;
index 423d050c8622d5b67929e6097a5f4e4e69f790a4..18dff78c050d3c1c92ee769f0b0e30fae2da307e 100644 (file)
@@ -3476,6 +3476,9 @@ static void lib_link_scene(FileData *fd, Main *main)
                        sce->toolsettings->imapaint.brush=
                                newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.brush);
 
+       
+                       sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template);
+
                        /* Sculptdata textures */
                        for(a=0; a<MAX_MTEX; ++a) {
                                MTex *mtex= sce->sculptdata.mtex[a];
@@ -7386,47 +7389,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                                ima->flag |= IMA_DO_PREMUL;
                        }
                }
-
-               if (main->versionfile < 245 || main->subversionfile < 12)
-               {
-                       /* initialize skeleton generation toolsettings */
-                       for(sce=main->scene.first; sce; sce = sce->id.next)
-                       {
-                               sce->toolsettings->skgen_resolution = 50;
-                               sce->toolsettings->skgen_threshold_internal     = 0.01f;
-                               sce->toolsettings->skgen_threshold_external     = 0.01f;
-                               sce->toolsettings->skgen_angle_limit                    = 45.0f;
-                               sce->toolsettings->skgen_length_ratio                   = 1.3f;
-                               sce->toolsettings->skgen_length_limit                   = 1.5f;
-                               sce->toolsettings->skgen_correlation_limit              = 0.98f;
-                               sce->toolsettings->skgen_symmetry_limit                 = 0.1f;
-                               sce->toolsettings->skgen_postpro = SKGEN_SMOOTH;
-                               sce->toolsettings->skgen_postpro_passes = 1;
-                               sce->toolsettings->skgen_options = SKGEN_FILTER_INTERNAL|SKGEN_FILTER_EXTERNAL|SKGEN_SUB_CORRELATION;
-                               sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
-                               sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
-                               sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
-                       }
-               }
-       }
-       
-       /* sanity check for skgen
-        * */
-       {
-               Scene *sce;
-               for(sce=main->scene.first; sce; sce = sce->id.next)
-               {
-                       if (sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[1] ||
-                               sce->toolsettings->skgen_subdivisions[0] == sce->toolsettings->skgen_subdivisions[2] ||
-                               sce->toolsettings->skgen_subdivisions[1] == sce->toolsettings->skgen_subdivisions[2])
-                       {
-                                       sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
-                                       sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
-                                       sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
-                       }
-               }
        }
-       
 
        if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 2)) {
                Image *ima;
@@ -8007,6 +7970,40 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                }
        }
        
+       if (main->versionfile < 248 || main->subversionfile < 2)
+       {
+               Scene *sce;
+               
+               /* initialize skeleton generation toolsettings */
+               for(sce=main->scene.first; sce; sce = sce->id.next)
+               {
+                       sce->toolsettings->skgen_resolution = 250;
+                       sce->toolsettings->skgen_threshold_internal     = 0.1f;
+                       sce->toolsettings->skgen_threshold_external     = 0.1f;
+                       sce->toolsettings->skgen_angle_limit                    = 30.0f;
+                       sce->toolsettings->skgen_length_ratio                   = 1.3f;
+                       sce->toolsettings->skgen_length_limit                   = 1.5f;
+                       sce->toolsettings->skgen_correlation_limit              = 0.98f;
+                       sce->toolsettings->skgen_symmetry_limit                 = 0.1f;
+                       sce->toolsettings->skgen_postpro = SKGEN_SMOOTH;
+                       sce->toolsettings->skgen_postpro_passes = 3;
+                       sce->toolsettings->skgen_options = SKGEN_FILTER_INTERNAL|SKGEN_FILTER_EXTERNAL|SKGEN_FILTER_SMART|SKGEN_SUB_CORRELATION|SKGEN_HARMONIC;
+                       sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
+                       sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
+                       sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
+
+                       
+                       sce->toolsettings->skgen_retarget_angle_weight = 1.0f;
+                       sce->toolsettings->skgen_retarget_length_weight = 1.0f;
+                       sce->toolsettings->skgen_retarget_distance_weight = 1.0f;
+       
+                       /* Skeleton Sketching */
+                       sce->toolsettings->bone_sketching = 0;
+                       sce->toolsettings->skgen_retarget_roll = SK_RETARGET_ROLL_VIEW;
+               }
+       }
+
+       
        /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
        /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */
 
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 ce275563a873a6eb46713e9f7b0b47ba259d32a1..ad3623cad60a7ce96dda16593e4bf55a86f8b14d 100644 (file)
@@ -68,6 +68,23 @@ typedef struct EditBone
 
 } EditBone;
 
+EditBone *addEditBone(char *name, struct ListBase *ebones, struct bArmature *arm);
+
+/* duplicate method */
+void preEditBoneDuplicate(struct ListBase *editbones);
+EditBone *duplicateEditBone(EditBone *curBone, char *name, struct ListBase *editbones, struct Object *ob);
+void updateDuplicateSubtarget(EditBone *dupBone, struct ListBase *editbones, struct Object *ob);
+
+/* duplicate method (cross objects */
+
+/* editbones is the target list */
+EditBone *duplicateEditBoneObjects(EditBone *curBone, char *name, struct ListBase *editbones, struct Object *src_ob, struct Object *dst_ob);
+
+/* editbones is the source list */
+void updateDuplicateSubtargetObjects(EditBone *dupBone, struct ListBase *editbones, struct Object *src_ob, struct Object *dst_ob);
+
+/* -- */
+
 float  rollBoneToVector(EditBone *bone, float new_up_axis[3]);
 
 void   make_boneList(struct ListBase *list, struct ListBase *bones, EditBone *parent);
@@ -117,7 +134,7 @@ void        selectconnected_posearmature(void);
 void   armature_select_hierarchy(short direction, short add_to_sel);
 
 void   setflag_armature(short mode);
-void    unique_editbone_name (struct ListBase *ebones, char *name);
+void   unique_editbone_name (struct ListBase *ebones, char *name, EditBone *bone); /* if bone is already in list, pass it as param to ignore it */
 
 void   auto_align_armature(short mode);
 void   switch_direction_armature(void);
diff --git a/source/blender/include/BIF_retarget.h b/source/blender/include/BIF_retarget.h
new file mode 100644 (file)
index 0000000..26c673d
--- /dev/null
@@ -0,0 +1,147 @@
+/**
+ * $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_RETARGET_H
+#define BIF_RETARGET_H
+
+#include "DNA_listBase.h"
+
+#include "BLI_graph.h"
+#include "BLI_ghash.h"
+#include "BLI_threads.h"
+
+#include "reeb.h"
+
+struct EditBone;
+
+struct RigJoint;
+struct RigGraph;
+struct RigNode;
+struct RigArc;
+struct RigEdge;
+
+#define USE_THREADS
+
+typedef struct RigGraph {
+       ListBase        arcs;
+       ListBase        nodes;
+
+       float length;
+       
+       FreeArc                 free_arc;
+       FreeNode                free_node;
+       RadialSymmetry  radial_symmetry;
+       AxialSymmetry   axial_symmetry;
+       /*********************************/
+
+       ListBase        controls;
+       ListBase*       editbones;
+       
+       struct RigNode *head;
+       ReebGraph *link_mesh;
+       
+       
+       struct ThreadedWorker *worker;
+       
+       GHash *bones_map;       /* map of editbones by name */
+       GHash *controls_map;    /* map of rigcontrols by bone pointer */
+       
+       Object *ob;
+} RigGraph;
+
+typedef struct RigNode {
+       void *next, *prev;
+       float p[3];
+       int flag;
+
+       int degree;
+       struct BArc **arcs;
+
+       int subgraph_index;
+
+       int symmetry_level;
+       int symmetry_flag;
+       float symmetry_axis[3];
+       /*********************************/
+
+       ReebNode *link_mesh;
+} RigNode;
+
+typedef struct RigArc {
+       void *next, *prev;
+       RigNode *head, *tail;
+       int flag;
+
+       float length;
+
+       int symmetry_level;
+       int symmetry_group;
+       int symmetry_flag;
+       /*********************************/
+       
+       ListBase edges;
+       int count;
+       ReebArc *link_mesh;
+} RigArc;
+
+typedef struct RigEdge {
+       struct RigEdge *next, *prev;
+       float head[3], tail[3];
+       float length;
+       float angle; /* angle to next edge */
+       float up_angle; /* angle between up_axis and the joint normal (defined as Previous edge CrossProduct Current edge */
+       EditBone *bone;
+       float up_axis[3];
+} RigEdge;
+
+/* Control flags */
+#define RIG_CTRL_HEAD_DONE             1
+#define RIG_CTRL_TAIL_DONE             2
+#define RIG_CTRL_PARENT_DEFORM 4
+#define RIG_CTRL_FIT_ROOT              8
+#define RIG_CTRL_FIT_BONE              16
+
+#define RIG_CTRL_DONE  (RIG_CTRL_HEAD_DONE|RIG_CTRL_TAIL_DONE)
+
+/* Control tail flags */
+typedef enum {
+       TL_NONE = 0,
+       TL_TAIL,
+       TL_HEAD
+} LinkTailMode;
+
+typedef struct RigControl {
+       struct RigControl *next, *prev;
+       float head[3], tail[3];
+       EditBone *bone;
+       EditBone *link;
+       EditBone *link_tail;
+       float   up_axis[3];
+       float   offset[3];
+       float   qrot[4]; /* for dual linked bones, store the rotation of the linked bone for the finalization */
+       int             flag;
+       LinkTailMode tail_mode;
+} RigControl;
+
+void BIF_retargetArc(ReebArc *earc);
+
+#endif /* BIF_RETARGET_H */
diff --git a/source/blender/include/BIF_sketch.h b/source/blender/include/BIF_sketch.h
new file mode 100644 (file)
index 0000000..6295ce4
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * $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();
+int BIF_fullSketchMode(); /* full sketch turned on (not Quick) */
+void BIF_cancelStrokeSketch();
+
+void  BIF_makeListTemplates();
+char *BIF_listTemplates();
+int   BIF_currentTemplate();
+void  BIF_freeTemplates();
+void  BIF_setTemplate(int);    
+
+#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 57f7d1b60cf599814fb4c0f64642e18d3e2db6d6..927eded62d445c920515ff699272f6f8a0236444 100644 (file)
@@ -63,6 +63,7 @@ typedef struct EmbedBucket {
        float val;
        int       nv;
        float p[3];
+       float no[3]; /* if non-null, normal of the bucket */
 } EmbedBucket;
 
 typedef struct ReebNode {
@@ -79,6 +80,8 @@ typedef struct ReebNode {
        int symmetry_flag;
        float symmetry_axis[3];
        /*********************************/
+       
+       float no[3];
 
        int index;
        float weight;
@@ -185,6 +188,7 @@ ReebNode *BIF_lowestLevelNode(ReebNode *node);
 ReebGraph *BIF_graphForMultiNode(ReebGraph *rg, ReebNode *node);
 
 void REEB_freeGraph(ReebGraph *rg);
+void REEB_freeArc(BArc *barc);
 void REEB_exportGraph(ReebGraph *rg, int count);
 void REEB_draw();
 
index c1c164f136f4427708581acfaa031be5be1af20a..10e8c534ab2e31d7dfc288fc635f1a64c58fa28a 100644 (file)
@@ -441,12 +441,20 @@ typedef struct ToolSettings {
        char  skgen_postpro_passes;
        char  skgen_subdivisions[3];
        char  skgen_multi_level;
-       char  skgen_optimisation_method;
        
-       char tpad[6];
+       /* Skeleton Sketching */
+       struct Object *skgen_template;
+       char bone_sketching;
+       char bone_sketching_convert;
+       char skgen_subdivision_number;
+       char skgen_retarget_options;
+       char skgen_retarget_roll;
+       char skgen_side_string[8];
+       char skgen_num_string[8];
        
        /* Alt+RMB option */
        char edge_mode;
+       char pad3[2];
 } ToolSettings;
 
 /* Used by all brushes to store their properties, which can be directly set
@@ -869,6 +877,24 @@ typedef struct Scene {
 #define SKGEN_AVERAGE                  1
 #define SKGEN_SHARPEN                  2
 
+/* toolsettings->bone_sketching */
+#define BONE_SKETCHING                 1
+#define BONE_SKETCHING_QUICK   2
+
+/* toolsettings->bone_sketching_convert */
+#define        SK_CONVERT_CUT_FIXED                    1
+#define        SK_CONVERT_CUT_LENGTH                   2
+#define        SK_CONVERT_CUT_CORRELATION              3
+#define        SK_CONVERT_RETARGET                             4
+
+/* toolsettings->skgen_retarget_options */
+#define        SK_RETARGET_AUTONAME                    1
+
+/* toolsettings->skgen_retarget_roll */
+#define        SK_RETARGET_ROLL_VIEW                   1
+#define        SK_RETARGET_ROLL_JOINT                  2
+
+
 #ifdef __cplusplus
 }
 #endif
index 99a4398ec89c3fe010d05109658cd3f5170178fc..2ef0c2b4afe71fc7f44f03d14aabd5c3d781b4ce 100644 (file)
@@ -280,7 +280,7 @@ static int BonesDict_SetItem(BPy_BonesDict *self, PyObject *key, PyObject *value
                //create a new editbone
                editbone = MEM_callocN(sizeof(EditBone), "eBone");
                BLI_strncpy(editbone->name, key_str, 32);
-               unique_editbone_name(NULL, editbone->name);
+               unique_editbone_name(NULL, editbone->name, NULL);
                editbone->dist = ((BPy_EditBone*)value)->dist;
                editbone->ease1 = ((BPy_EditBone*)value)->ease1;
                editbone->ease2 = ((BPy_EditBone*)value)->ease2;
index 948eb007803d25bb3e07ac249fe98d04f5f2ab74..cacb358434435d9c9ce43d7a545f3c569bc1ab9f 100644 (file)
@@ -832,7 +832,7 @@ static PyObject *EditBone_new(PyTypeObject *type, PyObject *args, PyObject *kwds
        //otherwise this will act as a py_object
        py_editBone->editbone = NULL;
 
-       unique_editbone_name(NULL, name);
+       unique_editbone_name(NULL, name, NULL);
        BLI_strncpy(py_editBone->name, name, 32);
        py_editBone->parent = NULL;
        py_editBone->weight= 1.0f;
index b6dfd29d62a85b7c9c53bbe32913663f28f192f7..429c05feadc2b94eb4a09b54c0f3dc000282e3b4 100644 (file)
@@ -5252,7 +5252,6 @@ static void editing_panel_mesh_skgen_retarget(Object *ob, Mesh *me)
        uiDefButF(block, NUM, B_DIFF,                                                   "Ang:",                 1025, 40, 83,19, &G.scene->toolsettings->skgen_retarget_angle_weight, 0, 10, 1, 0,              "Angle Weight");
        uiDefButF(block, NUM, B_DIFF,                                                   "Len:",                 1108, 40, 83,19, &G.scene->toolsettings->skgen_retarget_length_weight, 0, 10, 1, 0,             "Length Weight");
        uiDefButF(block, NUM, B_DIFF,                                                   "Dist:",                1191, 40, 84,19, &G.scene->toolsettings->skgen_retarget_distance_weight, 0, 10, 1, 0,           "Distance Weight");
-       uiDefButC(block, NUM, B_DIFF,                                                   "Method:",              1025, 20, 125,19, &G.scene->toolsettings->skgen_optimisation_method, 0, 2, 1, 0,"Optimisation Method (0: brute, 1: memoize, 2: annealing max fixed");
 }
 
 static void editing_panel_mesh_skgen(Object *ob, Mesh *me)
index de3e464060d00b8e955d49b1c9aa8a732ba6eede..2d0cf01d4a8fad59edabce16cde7b59cca9ec98f 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"
@@ -2271,6 +2273,107 @@ 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 assign_template_sketch_armature(void *arg1, void *arg2)
+{
+       int index = *(int*)arg1;
+       BIF_setTemplate(index);
+}
+static void view3d_panel_bonesketch_spaces(short cntrl)
+{
+       static int template_index;
+       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_bonesketch_spaces", UI_EMBOSS, UI_HELV, curarea->win);
+               uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE  | cntrl);
+               uiSetPanelHandler(VIEW3D_HANDLER_BONESKETCH);  // for close and esc
+       
+               if(uiNewPanel(curarea, block, "Bone Sketching", "View3d", 10, 230, 250, 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, yco, 180, 20, &G.scene->toolsettings->bone_sketching, 0, 0, 0, 0, "Use sketching to create and edit bones");
+               uiDefButBitC(block, TOG, BONE_SKETCHING_QUICK, B_REDR, "Q", 190, yco, 20, 20, &G.scene->toolsettings->bone_sketching, 0, 0, 0, 0, "Automatically convert and delete on stroke end");
+               yco -= 20;
+               
+               but = uiDefBut(block, BUT, B_REDR, "Convert", 10,yco,100,20, 0, 0, 0, 0, 0, "Convert sketch to armature");
+               uiButSetFunc(but, convert_sketch_armature, NULL, NULL);
+
+               but = uiDefBut(block, BUT, B_REDR, "Delete", 110,yco,100,20, 0, 0, 0, 0, 0, "Delete sketch");
+               uiButSetFunc(but, delete_sketch_armature, NULL, NULL);
+               yco -= 20;
+               
+               uiBlockEndAlign(block);
+
+               uiBlockBeginAlign(block);
+
+               uiDefButC(block, ROW, B_REDR, "Length", 10, yco, 60, 19, &G.scene->toolsettings->bone_sketching_convert, 0, SK_CONVERT_CUT_LENGTH, 0, 0,                                "Subdivide arcs in bones of equal length");
+               uiDefButF(block, NUM, B_REDR,                                   "Lim:",         70, yco, 140, 19, &G.scene->toolsettings->skgen_length_limit,0.1,50.0, 10, 0,           "Maximum length of the subdivided bones");
+               yco -= 20;
+
+               uiDefButC(block, ROW, B_REDR, "Correlation",    10, yco, 60, 19, &G.scene->toolsettings->bone_sketching_convert, 0, SK_CONVERT_CUT_CORRELATION, 0, 0,                                   "Subdivide arcs based on correlation");
+               uiDefButF(block, NUM, B_REDR,                                    "Thres:",                      70, yco, 140, 19, &G.scene->toolsettings->skgen_correlation_limit,0.0, 1.0, 0.01, 0,    "Correlation threshold for subdivision");
+               yco -= 20;
+       
+               uiDefButC(block, ROW, B_REDR, "Fixed",          10, yco, 60, 19, &G.scene->toolsettings->bone_sketching_convert, 0, SK_CONVERT_CUT_FIXED, 0, 0,                                 "Subdivide arcs based on a fixed number of bones");
+               uiDefButC(block, NUM, B_REDR,                                   "Num:",         70, yco, 140, 19, &G.scene->toolsettings->skgen_subdivision_number,1, 100, 1, 5,        "Number of subdivided bones");
+               yco -= 20;
+
+               uiDefButC(block, ROW, B_REDR, "Retarget",       10,  yco,80, 19, &G.scene->toolsettings->bone_sketching_convert, 0, SK_CONVERT_RETARGET, 0, 0,                          "Retarget selected bones to stroke");
+               uiDefButC(block, ROW, B_DIFF, "No",                     90,  yco, 40,19, &G.scene->toolsettings->skgen_retarget_roll, 0, 0, 0, 0,                                                                       "No special roll treatment");
+               uiDefButC(block, ROW, B_DIFF, "View",           130,  yco, 40,19, &G.scene->toolsettings->skgen_retarget_roll, 0, SK_RETARGET_ROLL_VIEW, 0, 0,                          "Roll bones perpendicular to view");
+               uiDefButC(block, ROW, B_DIFF, "Joint",          170, yco, 40,19, &G.scene->toolsettings->skgen_retarget_roll, 0, SK_RETARGET_ROLL_JOINT, 0, 0,                          "Roll bones relative to joint bend");
+               yco -= 20;
+
+               uiBlockEndAlign(block);
+
+               yco -= 10;
+               uiBlockBeginAlign(block);
+               
+               /* button here to select what to do (copy or not), template, ...*/
+
+               BIF_makeListTemplates();
+               template_index = BIF_currentTemplate();
+               
+               but = uiDefButI(block, MENU, B_REDR, BIF_listTemplates(), 10,yco,200,19, &template_index, 0, 0, 0, 0, "Template");
+               uiButSetFunc(but, assign_template_sketch_armature, &template_index, NULL);
+               
+               yco -= 20;
+               
+               uiDefButF(block, NUM, B_DIFF,                                                   "A:",                   10, yco, 66,19, &G.scene->toolsettings->skgen_retarget_angle_weight, 0, 10, 1, 0,               "Angle Weight");
+               uiDefButF(block, NUM, B_DIFF,                                                   "L:",                   76, yco, 67,19, &G.scene->toolsettings->skgen_retarget_length_weight, 0, 10, 1, 0,              "Length Weight");
+               uiDefButF(block, NUM, B_DIFF,                                                   "D:",           143,yco, 67,19, &G.scene->toolsettings->skgen_retarget_distance_weight, 0, 10, 1, 0,            "Distance Weight");
+               yco -= 20;
+               
+               uiDefBut(block, TEX,0,"S:",                                                     10,  yco, 90, 20, G.scene->toolsettings->skgen_side_string, 0.0, 8.0, 0, 0, "Text to replace %S with");
+               uiDefBut(block, TEX,0,"N:",                                                     100, yco, 90, 20, G.scene->toolsettings->skgen_num_string, 0.0, 8.0, 0, 0, "Text to replace %N with");
+               uiDefIconButBitC(block, TOG, SK_RETARGET_AUTONAME, B_DIFF, ICON_AUTO,190,yco,20,20, &G.scene->toolsettings->skgen_retarget_options, 0, 0, 0, 0, "Use Auto Naming");     
+
+               /* auto renaming magic */
+
+               uiBlockEndAlign(block);
+
+               if(yco < 0) uiNewPanelHeight(block, height-yco);
+       }
+}
 
 static void view3d_panel_object(short cntrl)   // VIEW3D_HANDLER_OBJECT
 {
@@ -2662,6 +2765,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;
@@ -3270,6 +3376,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..f681b65925f2aeb9aecde776c82b29841e583b85 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_fullSketchMode())
+       {
+               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 ee5d56eaf43f527284944573823484cd44e5a141..9559059e44cbbf7dd0dee6824a1acbeddb5033d5 100644 (file)
@@ -699,7 +699,7 @@ int join_armature(void)
                                        curbone= editbone_name_exists(&eblist, pchan->name);
                                        
                                        /* Get new name */
-                                       unique_editbone_name(&ebbase, curbone->name);
+                                       unique_editbone_name(&ebbase, curbone->name, NULL);
                                        
                                        /* Transform the bone */
                                        {
@@ -1994,17 +1994,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, NULL);
        
-       BLI_addtail(&G.edbo, bone);
+       BLI_addtail(ebones, bone);
        
        bone->flag |= BONE_TIPSEL;
        bone->weight= 1.0F;
@@ -2021,6 +2018,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];
@@ -2192,13 +2197,12 @@ static EditBone *add_points_bone (float head[], float tail[])
        return ebo;
 }
 
-
-static EditBone *get_named_editbone(char *name)
+static EditBone *get_named_editbone_from_list(char *name, ListBase *editbones)
 {
        EditBone  *eBone;
 
        if (name) {
-               for (eBone=G.edbo.first; eBone; eBone=eBone->next) {
+               for (eBone=editbones->first; eBone; eBone=eBone->next) {
                        if (!strcmp(name, eBone->name))
                                return eBone;
                }
@@ -2207,7 +2211,29 @@ static EditBone *get_named_editbone(char *name)
        return NULL;
 }
 
-static void update_dup_subtarget(EditBone *dupBone)
+static EditBone *get_named_editbone(char *name)
+{
+       return get_named_editbone_from_list(name, &G.edbo);
+}
+
+/* Call this before doing any duplications
+ * */
+void preEditBoneDuplicate(ListBase *editbones)
+{
+       EditBone *eBone;
+       
+       /* clear temp */
+       for (eBone = editbones->first; eBone; eBone = eBone->next)
+       {
+               eBone->temp = NULL;
+       }
+}
+
+/*
+ * Note: When duplicating cross objects, editbones here is the list of bones
+ * from the SOURCE object but ob is the DESTINATION object
+ * */
+void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Object *src_ob, Object *dst_ob)
 {
        /* If an edit bone has been duplicated, lets
         * update it's constraints if the subtarget
@@ -2218,7 +2244,7 @@ static void update_dup_subtarget(EditBone *dupBone)
        bConstraint  *curcon;
        ListBase     *conlist;
        
-       if ( (chan = verify_pose_channel(OBACT->pose, dupBone->name)) ) {
+       if ( (chan = verify_pose_channel(dst_ob->pose, dupBone->name)) ) {
                if ( (conlist = &chan->constraints) ) {
                        for (curcon = conlist->first; curcon; curcon=curcon->next) {
                                /* does this constraint have a subtarget in
@@ -2232,14 +2258,15 @@ static void update_dup_subtarget(EditBone *dupBone)
                                        cti->get_constraint_targets(curcon, &targets);
                                        
                                        for (ct= targets.first; ct; ct= ct->next) {
-                                               if ((ct->tar == G.obedit) && (ct->subtarget[0])) {
-                                                       oldtarget = get_named_editbone(ct->subtarget);
+                                               if ((ct->tar == src_ob) && (ct->subtarget[0])) {
+                                                       ct->tar = dst_ob; /* update target */
+                                                       oldtarget = get_named_editbone_from_list(ct->subtarget, editbones);
                                                        if (oldtarget) {
                                                                /* was the subtarget bone duplicated too? If
                                                                 * so, update the constraint to point at the 
                                                                 * duplicate of the old subtarget.
                                                                 */
-                                                               if (oldtarget->flag & BONE_SELECTED){
+                                                               if (oldtarget->temp){
                                                                        newtarget = (EditBone *) oldtarget->temp;
                                                                        strcpy(ct->subtarget, newtarget->name);
                                                                }
@@ -2255,6 +2282,78 @@ static void update_dup_subtarget(EditBone *dupBone)
        }
 }
 
+void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob)
+{
+       updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
+}
+
+
+EditBone *duplicateEditBoneObjects(EditBone *curBone, char *name, ListBase *editbones, Object *src_ob, Object *dst_ob)
+{
+       EditBone *eBone = MEM_callocN(sizeof(EditBone), "addup_editbone");
+       
+       /*      Copy data from old bone to new bone */
+       memcpy(eBone, curBone, sizeof(EditBone));
+       
+       curBone->temp = eBone;
+       eBone->temp = curBone;
+       
+       if (name != NULL)
+       {
+               BLI_strncpy(eBone->name, name, 32);
+       }
+
+       unique_editbone_name(editbones, eBone->name, NULL);
+       BLI_addtail(editbones, eBone);
+       
+       /* Lets duplicate the list of constraints that the
+        * current bone has.
+        */
+       if (src_ob->pose) {
+               bPoseChannel *chanold, *channew;
+               ListBase     *listold, *listnew;
+               
+               chanold = verify_pose_channel(src_ob->pose, curBone->name);
+               if (chanold) {
+                       listold = &chanold->constraints;
+                       if (listold) {
+                               /* WARNING: this creates a new posechannel, but there will not be an attached bone 
+                                *              yet as the new bones created here are still 'EditBones' not 'Bones'. 
+                                */
+                               channew = 
+                                       verify_pose_channel(dst_ob->pose, eBone->name);
+                               if (channew) {
+                                       /* copy transform locks */
+                                       channew->protectflag = chanold->protectflag;
+                                       
+                                       /* copy bone group */
+                                       channew->agrp_index= chanold->agrp_index;
+                                       
+                                       /* ik (dof) settings */
+                                       channew->ikflag = chanold->ikflag;
+                                       VECCOPY(channew->limitmin, chanold->limitmin);
+                                       VECCOPY(channew->limitmax, chanold->limitmax);
+                                       VECCOPY(channew->stiffness, chanold->stiffness);
+                                       channew->ikstretch= chanold->ikstretch;
+                                       
+                                       /* constraints */
+                                       listnew = &channew->constraints;
+                                       copy_constraints(listnew, listold);
+                                       
+                                       /* custom shape */
+                                       channew->custom= chanold->custom;
+                               }
+                       }
+               }
+       }
+       
+       return eBone;
+}
+
+EditBone *duplicateEditBone(EditBone *curBone, char *name, ListBase *editbones, Object *ob)
+{
+       return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
+}
 
 void adduplicate_armature(void)
 {
@@ -2264,6 +2363,8 @@ void adduplicate_armature(void)
        EditBone        *firstDup=NULL; /*      The beginning of the duplicated bones in the edbo list */
        
        countall(); // flushes selection!
+       
+       preEditBoneDuplicate(&G.edbo);
 
        /* Select mirrored bones */
        if (arm->flag & ARM_MIRROR_EDIT) {
@@ -2277,6 +2378,7 @@ void adduplicate_armature(void)
                        }
                }
        }
+
        
        /*      Find the selected bones and duplicate them as needed */
        for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next) {
@@ -2291,7 +2393,7 @@ void adduplicate_armature(void)
                                curBone->temp = eBone;
                                eBone->temp = curBone;
                                
-                               unique_editbone_name(&G.edbo, eBone->name);
+                               unique_editbone_name(&G.edbo, eBone->name, NULL);
                                BLI_addtail(&G.edbo, eBone);
                                if (!firstDup)
                                        firstDup=eBone;
@@ -2351,12 +2453,12 @@ void adduplicate_armature(void)
                                */
                                if (!curBone->parent)
                                        eBone->parent = NULL;
-                               /*      If this bone has a parent that IS selected,
+                               /*      If this bone has a parent that was duplicated,
                                        Set the duplicate->parent to the curBone->parent->duplicate
                                        */
-                               else if (curBone->parent->flag & BONE_SELECTED)
+                               else if (curBone->parent->temp)
                                        eBone->parent= (EditBone *)curBone->parent->temp;
-                               /*      If this bone has a parent that IS not selected,
+                               /*      If this bone has a parent that was not duplicated,
                                        Set the duplicate->parent to the curBone->parent
                                        */
                                else {
@@ -2366,7 +2468,7 @@ void adduplicate_armature(void)
                                
                                /* Lets try to fix any constraint subtargets that might
                                        have been duplicated */
-                               update_dup_subtarget(eBone);
+                               updateDuplicateSubtarget(eBone, &G.edbo, OBACT);
                        }
                }
        } 
@@ -3055,13 +3157,16 @@ static EditBone *editbone_name_exists (ListBase *ebones, char *name)
 }
 
 /* note: there's a unique_bone_name() too! */
-void unique_editbone_name (ListBase *ebones, char *name)
+void unique_editbone_name (ListBase *ebones, char *name, EditBone *bone)
 {
+       EditBone *dupli;
        char            tempname[64];
        int                     number;
        char            *dot;
        
-       if (editbone_name_exists(ebones, name)) {
+       dupli = editbone_name_exists(ebones, name); 
+       
+       if (dupli && bone != dupli) {
                /*      Strip off the suffix, if it's a number */
                number= strlen(name);
                if (number && isdigit(name[number-1])) {
@@ -3182,7 +3287,7 @@ void extrude_armature(int forked)
                                                        else strcat(newbone->name, "_R");
                                                }
                                        }
-                                       unique_editbone_name(&G.edbo, newbone->name);
+                                       unique_editbone_name(&G.edbo, newbone->name, NULL);
                                        
                                        /* Add the new bone to the list */
                                        BLI_addtail(&G.edbo, newbone);
@@ -3269,7 +3374,7 @@ void subdivide_armature(int numcuts)
                                                        
                                                        newbone->flag |= BONE_CONNECTED;
                                                        
-                                                       unique_editbone_name (&G.edbo, newbone->name);
+                                                       unique_editbone_name (&G.edbo, newbone->name, NULL);
                                                        
                                                        /* correct parent bones */
                                                        for (tbone = G.edbo.first; tbone; tbone=tbone->next) {
@@ -4303,7 +4408,7 @@ void armature_bone_rename(bArmature *arm, char *oldnamep, char *newnamep)
                        
                        eBone= editbone_name_exists(&G.edbo, oldname);
                        if (eBone) {
-                               unique_editbone_name(&G.edbo, newname);
+                               unique_editbone_name(&G.edbo, newname, NULL);
                                BLI_strncpy(eBone->name, newname, MAXBONENAME);
                        }
                        else return;
similarity index 77%
rename from source/blender/src/autoarmature.c
rename to source/blender/src/editarmature_retarget.c
index b0a7a2ab5cc72a7d4ebd56822f5c3af98648d934..c2a64ef017bf06b2af9c53c3fa2995bfb8429798 100644 (file)
@@ -62,7 +62,9 @@
 #include "BKE_armature.h"
 
 #include "BIF_editarmature.h"
+#include "BIF_retarget.h"
 #include "BIF_space.h"
+#include "BIF_toolbox.h"
 
 #include "PIL_time.h"
 
 
 /************ RIG RETARGET DATA STRUCTURES ***************/
 
-struct RigJoint;
-struct RigGraph;
-struct RigNode;
-struct RigArc;
-struct RigEdge;
-
-//#define USE_THREADS
-
-typedef struct RigGraph {
-       ListBase        arcs;
-       ListBase        nodes;
-       
-       float length;
-       
-       FreeArc                 free_arc;
-       FreeNode                free_node;
-       RadialSymmetry  radial_symmetry;
-       AxialSymmetry   axial_symmetry;
-       /*********************************/
-
-       struct RigNode *head;
-       ReebGraph *link_mesh;
-       
-       ListBase editbones;
-       
-       ListBase controls;
-       struct ThreadedWorker *worker;
-       
-       GHash *bones_map;       /* map of editbones by name */
-       GHash *controls_map;    /* map of rigcontrols by bone pointer */
-       
-       Object *ob;
-} RigGraph;
-
-typedef struct RigNode {
-       void *next, *prev;
-       float p[3];
-       int flag;
-
-       int degree;
-       struct BArc **arcs;
-
-       int subgraph_index;
-
-       int symmetry_level;
-       int symmetry_flag;
-       float symmetry_axis[3];
-       /*********************************/
-
-       ReebNode *link_mesh;
-} RigNode;
-
-typedef struct RigArc {
-       void *next, *prev;
-       RigNode *head, *tail;
-       int flag;
-
-       float length;
-
-       int symmetry_level;
-       int symmetry_group;
-       int symmetry_flag;
-       /*********************************/
-       
-       ListBase edges;
-       int count;
-       ReebArc *link_mesh;
-} RigArc;
-
-typedef struct RigEdge {
-       struct RigEdge *next, *prev;
-       float head[3], tail[3];
-       float length;
-       float angle;
-       EditBone *bone;
-       float up_axis[3];
-} RigEdge;
-
-/* Control flags */
-#define RIG_CTRL_DONE                  1
-#define RIG_CTRL_PARENT_DEFORM 2
-#define RIG_CTRL_FIT_ROOT              4
-#define RIG_CTRL_FIT_BONE              8
-
-typedef struct RigControl {
-       struct RigControl *next, *prev;
-       float head[3], tail[3];
-       EditBone *bone;
-       EditBone *link;
-       float   up_axis[3];
-       float   offset[3];
-       int             flag;
-} RigControl;
-
 typedef struct MemoNode {
        float   weight;
        int     next;
@@ -186,8 +94,7 @@ typedef enum
 typedef enum
 {
        METHOD_BRUTE_FORCE = 0,
-       METHOD_MEMOIZE = 1,
-       METHOD_ANNEALING = 2
+       METHOD_MEMOIZE = 1
 } RetargetMethod;
 
 typedef enum
@@ -197,14 +104,14 @@ typedef enum
        ARC_USED = 2
 } ArcUsageFlags;
 
-
 RigGraph *GLOBAL_RIGG = NULL;
 
 /*******************************************************************************************************/
 
 void *exec_retargetArctoArc(void *param);
 
-static void RIG_calculateEdgeAngle(RigEdge *edge_first, RigEdge *edge_second);
+static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second);
+float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]);
 
 /* two levels */
 #define SHAPE_LEVELS (SHAPE_RADIX * SHAPE_RADIX) 
@@ -256,30 +163,105 @@ void getEditBoneRollUpAxis(EditBone *bone, float roll, float up_axis[3])
        VECCOPY(up_axis, mat[2]);
 }
 
-float getNewBoneRoll(EditBone *bone, float old_up_axis[3], float quat[4])
+float rollBoneByQuatAligned(EditBone *bone, float old_up_axis[3], float qrot[4], float qroll[4], float aligned_axis[3])
 {
-       float mat[3][3];
-       float nor[3], up_axis[3], new_up_axis[3], vec[3];
-       float roll;
+       float nor[3], new_up_axis[3], x_axis[3], z_axis[3];
        
        VECCOPY(new_up_axis, old_up_axis);
-       QuatMulVecf(quat, new_up_axis);
-
+       QuatMulVecf(qrot, new_up_axis);
+       
        VecSubf(nor, bone->tail, bone->head);
        
-       vec_roll_to_mat3(nor, 0, mat);
-       VECCOPY(up_axis, mat[2]);
+       Crossf(x_axis, nor, aligned_axis);
+       Crossf(z_axis, x_axis, nor);
        
-       roll = NormalizedVecAngle2(new_up_axis, up_axis);
+       Normalize(new_up_axis);
+       Normalize(x_axis);
+       Normalize(z_axis);
+       
+       if (Inpf(new_up_axis, x_axis) < 0)
+       {
+               VecMulf(x_axis, -1);
+       }
        
-       Crossf(vec, up_axis, new_up_axis);
+       if (Inpf(new_up_axis, z_axis) < 0)
+       {
+               VecMulf(z_axis, -1);
+       }
        
-       if (Inpf(vec, nor) < 0)
+       if (NormalizedVecAngle2(x_axis, new_up_axis) < NormalizedVecAngle2(z_axis, new_up_axis))
+       {
+               RotationBetweenVectorsToQuat(qroll, new_up_axis, x_axis); /* set roll rotation quat */
+               return rollBoneToVector(bone, x_axis);
+       }
+       else
+       {
+               RotationBetweenVectorsToQuat(qroll, new_up_axis, z_axis); /* set roll rotation quat */
+               return rollBoneToVector(bone, z_axis);
+       }
+}
+
+float rollBoneByQuatJoint(RigEdge *edge, RigEdge *previous, float qrot[4], float qroll[4])
+{
+       if (previous == NULL)
+       {
+               QuatOne(qroll);
+               return rollBoneByQuat(edge->bone, edge->up_axis, qrot);
+       }
+       else
        {
-               roll = -roll;
+               float new_up_axis[3];
+               float vec_first[3], vec_second[3], normal[3];
+               
+               if (previous->bone)
+               {
+                       VecSubf(vec_first, previous->bone->tail, previous->bone->head);
+               } 
+               else if (previous->prev->bone)
+               {
+                       VecSubf(vec_first, edge->bone->head, previous->prev->bone->tail);
+               }
+               else
+               {
+                       /* SHOULDN'T BE HERE */
+                       QuatOne(qroll);
+                       return rollBoneByQuat(edge->bone, edge->up_axis, qrot);
+               }
+               
+               VecSubf(vec_second, edge->bone->tail, edge->bone->head);
+       
+               Normalize(vec_first);
+               Normalize(vec_second);
+               
+               Crossf(normal, vec_first, vec_second);
+               Normalize(normal);
+               
+               AxisAngleToQuat(qroll, vec_second, edge->up_angle);
+               
+               QuatMulVecf(qroll, normal);
+                       
+               VECCOPY(new_up_axis, edge->up_axis);
+               QuatMulVecf(qrot, new_up_axis);
+               
+               Normalize(new_up_axis);
+               
+               /* real qroll between normal and up_axis */
+               RotationBetweenVectorsToQuat(qroll, new_up_axis, normal);
+
+               return rollBoneToVector(edge->bone, normal);
        }
+}
+
+float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4])
+{
+       float new_up_axis[3];
+       
+       VECCOPY(new_up_axis, old_up_axis);
+       QuatMulVecf(qrot, new_up_axis);
        
-       return roll;
+       Normalize(new_up_axis);
+       
+       return rollBoneToVector(bone, new_up_axis);
 }
 
 /************************************ DESTRUCTORS ******************************************************/
@@ -291,14 +273,18 @@ void RIG_freeRigArc(BArc *arc)
 
 void RIG_freeRigGraph(BGraph *rg)
 {
+       RigGraph *rigg = (RigGraph*)rg;
        BNode *node;
        BArc *arc;
        
 #ifdef USE_THREADS
-       BLI_destroy_worker(((RigGraph*)rg)->worker);
+       BLI_destroy_worker(rigg->worker);
 #endif
        
-       REEB_freeGraph(((RigGraph*)rg)->link_mesh);
+       if (rigg->link_mesh)
+       {
+               REEB_freeGraph(rigg->link_mesh);
+       }
        
        for (arc = rg->arcs.first; arc; arc = arc->next)
        {
@@ -312,12 +298,16 @@ void RIG_freeRigGraph(BGraph *rg)
        }
        BLI_freelistN(&rg->nodes);
        
-       BLI_freelistN(&((RigGraph*)rg)->controls);
+       BLI_freelistN(&rigg->controls);
 
-       BLI_ghash_free(((RigGraph*)rg)->bones_map, NULL, NULL);
-       BLI_ghash_free(((RigGraph*)rg)->controls_map, NULL, NULL);
+       BLI_ghash_free(rigg->bones_map, NULL, NULL);
+       BLI_ghash_free(rigg->controls_map, NULL, NULL);
        
-       BLI_freelistN(&((RigGraph*)rg)->editbones);
+       if (rigg->editbones != &G.edbo)
+       {
+               BLI_freelistN(rigg->editbones);
+               MEM_freeN(rigg->editbones);
+       }
        
        MEM_freeN(rg);
 }
@@ -434,7 +424,7 @@ static void RIG_appendEdgeToArc(RigArc *arc, RigEdge *edge)
        {
                RigEdge *last_edge = edge->prev;
                VECCOPY(edge->head, last_edge->tail);
-               RIG_calculateEdgeAngle(last_edge, edge);
+               RIG_calculateEdgeAngles(last_edge, edge);
        }
        
        edge->length = VecLenf(edge->head, edge->tail);
@@ -460,10 +450,206 @@ static void RIG_addEdgeToArc(RigArc *arc, float tail[3], EditBone *bone)
        
        RIG_appendEdgeToArc(arc, edge);
 }
+/************************************** CLONING TEMPLATES **********************************************/
+
+static void renameTemplateBone(char *name, char *template_name, ListBase *editbones)
+{
+       char *side_string = G.scene->toolsettings->skgen_side_string;
+       char *num_string = G.scene->toolsettings->skgen_num_string;
+       int i, j;
+       
+       for (i = 0, j = 0; template_name[i] != '\0' && i < 31 && j < 31; i++)
+       {
+               if (template_name[i] == '%')
+               {
+                       if (template_name[i+1] == 'S')
+                       {
+                               j += sprintf(name + j, side_string);
+                               i++;
+                       }
+                       else if (template_name[i+1] == 'N')
+                       {
+                               j += sprintf(name + j, num_string);
+                               i++;
+                       }
+                       else
+                       {
+                               name[j] = template_name[i];
+                               j++;
+                       }
+               }
+               else
+               {
+                       name[j] = template_name[i];
+                       j++;
+               }
+       }
+       
+       name[j] = '\0';
+       
+       unique_editbone_name(editbones, name, NULL);
+}
+
+static RigControl *cloneControl(RigGraph *rg, RigGraph *src_rg, RigControl *src_ctrl, GHash *ptr_hash)
+{
+       RigControl *ctrl;
+       char name[32];
+       
+       ctrl = newRigControl(rg);
+       
+       VECCOPY(ctrl->head, src_ctrl->head);
+       VECCOPY(ctrl->tail, src_ctrl->tail);
+       VECCOPY(ctrl->up_axis, src_ctrl->up_axis);
+       VECCOPY(ctrl->offset, src_ctrl->offset);
+       
+       ctrl->tail_mode = src_ctrl->tail_mode;
+       ctrl->flag = src_ctrl->flag;
+
+       renameTemplateBone(name, src_ctrl->bone->name, rg->editbones);
+       ctrl->bone = duplicateEditBoneObjects(src_ctrl->bone, name, rg->editbones, src_rg->ob, rg->ob);
+       ctrl->bone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL|BONE_ACTIVE);
+       BLI_ghash_insert(ptr_hash, src_ctrl->bone, ctrl->bone);
+       
+       ctrl->link = src_ctrl->link;
+       ctrl->link_tail = src_ctrl->link_tail;
+       
+       return ctrl;
+}
+
+static RigArc *cloneArc(RigGraph *rg, RigGraph *src_rg, RigArc *src_arc, GHash *ptr_hash)
+{
+       RigEdge *src_edge;
+       RigArc  *arc;
+       
+       arc = newRigArc(rg);
+       
+       arc->head = BLI_ghash_lookup(ptr_hash, src_arc->head);
+       arc->tail = BLI_ghash_lookup(ptr_hash, src_arc->tail);
+       
+       arc->head->degree++;
+       arc->tail->degree++;
+       
+       arc->length = src_arc->length;
+
+       arc->count = src_arc->count;
+       
+       for (src_edge = src_arc->edges.first; src_edge; src_edge = src_edge->next)
+       {
+               RigEdge *edge;
+       
+               edge = MEM_callocN(sizeof(RigEdge), "rig edge");
+
+               VECCOPY(edge->head, src_edge->head);
+               VECCOPY(edge->tail, src_edge->tail);
+               VECCOPY(edge->up_axis, src_edge->up_axis);
+               
+               edge->length = src_edge->length;
+               edge->angle = src_edge->angle;
+               edge->up_angle = src_edge->up_angle;
+               
+               if (src_edge->bone != NULL)
+               {
+                       char name[32];
+                       renameTemplateBone(name, src_edge->bone->name, rg->editbones);
+                       edge->bone = duplicateEditBoneObjects(src_edge->bone, name, rg->editbones, src_rg->ob, rg->ob);
+                       edge->bone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL|BONE_ACTIVE);
+                       BLI_ghash_insert(ptr_hash, src_edge->bone, edge->bone);
+               }
+
+               BLI_addtail(&arc->edges, edge);
+       }
+       
+       return arc;
+}
+
+static RigGraph *cloneRigGraph(RigGraph *src, ListBase *editbones, Object *ob)
+{
+       GHash   *ptr_hash;      
+       RigNode *node;
+       RigArc  *arc;
+       RigControl *ctrl;
+       RigGraph *rg;
+       
+       ptr_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+       rg = newRigGraph();
+       
+       rg->ob = ob;
+       rg->editbones = editbones;
+       
+       preEditBoneDuplicate(rg->editbones); /* prime bones for duplication */
+       preEditBoneDuplicate(src->editbones); /* prime bones for duplication */
+       
+       /* Clone nodes */
+       for (node = src->nodes.first; node; node = node->next)
+       {
+               RigNode *cloned_node = newRigNode(rg, node->p);
+               BLI_ghash_insert(ptr_hash, node, cloned_node);
+       }
+       
+       rg->head = BLI_ghash_lookup(ptr_hash, src->head);
+       
+       /* Clone arcs */
+       for (arc = src->arcs.first; arc; arc = arc->next)
+       {
+               cloneArc(rg, src, arc, ptr_hash);
+       }
+       
+       /* Clone controls */
+       for (ctrl = src->controls.first; ctrl; ctrl = ctrl->next)
+       {
+               cloneControl(rg, src, ctrl, ptr_hash);
+       }
+       
+       /* Relink bones properly */
+       for (arc = rg->arcs.first; arc; arc = arc->next)
+       {
+               RigEdge *edge;
+               
+               for (edge = arc->edges.first; edge; edge = edge->next)
+               {
+                       if (edge->bone != NULL)
+                       {
+                               EditBone *bone;
+                               
+                               updateDuplicateSubtargetObjects(edge->bone, src->editbones, src->ob, rg->ob);
+                               
+                               bone = BLI_ghash_lookup(ptr_hash, edge->bone->parent);
+       
+                               if (bone != NULL)
+                               {
+                                       edge->bone->parent = bone;
+                               }
+                       }
+               }
+       }
+       
+       for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next)
+       {
+               EditBone *bone;
+               
+               updateDuplicateSubtargetObjects(ctrl->bone, src->editbones, src->ob, rg->ob);
+
+               bone = BLI_ghash_lookup(ptr_hash, ctrl->bone->parent);
+               
+               if (bone != NULL)
+               {
+                       ctrl->bone->parent = bone;
+               }
+
+               ctrl->link = BLI_ghash_lookup(ptr_hash, ctrl->link);
+               ctrl->link_tail = BLI_ghash_lookup(ptr_hash, ctrl->link_tail);
+       }
+       
+       BLI_ghash_free(ptr_hash, NULL, NULL);
+       
+       return rg;
+}
+
 
 /*******************************************************************************************************/
 
-static void RIG_calculateEdgeAngle(RigEdge *edge_first, RigEdge *edge_second)
+static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second)
 {
        float vec_first[3], vec_second[3];
        
@@ -473,7 +659,17 @@ static void RIG_calculateEdgeAngle(RigEdge *edge_first, RigEdge *edge_second)
        Normalize(vec_first);
        Normalize(vec_second);
        
-       edge_first->angle = saacos(Inpf(vec_first, vec_second));
+       edge_first->angle = NormalizedVecAngle2(vec_first, vec_second);
+       
+       if (edge_second->bone != NULL)
+       {
+               float normal[3];
+
+               Crossf(normal, vec_first, vec_second);
+               Normalize(normal);
+
+               edge_second->up_angle = NormalizedVecAngle2(normal, edge_second->up_axis);
+       }
 }
 
 /************************************ CONTROL BONES ****************************************************/
@@ -485,6 +681,7 @@ static void RIG_addControlBone(RigGraph *rg, EditBone *bone)
        VECCOPY(ctrl->head, bone->head);
        VECCOPY(ctrl->tail, bone->tail);
        getEditBoneRollUpAxis(bone, bone->roll, ctrl->up_axis);
+       ctrl->tail_mode = TL_NONE;
        
        BLI_ghash_insert(rg->controls_map, bone->name, ctrl);
 }
@@ -692,8 +889,6 @@ static void RIG_reconnectControlBones(RigGraph *rg)
        {
                change = 0;
                
-               printf("-------------------------\n");
-               
                for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next)
                {
                        /* if control is not linked yet */
@@ -736,7 +931,6 @@ static void RIG_reconnectControlBones(RigGraph *rg)
                                                                        /* if owner is a control bone, link with it */                                                                  
                                                                        if (link && link->link)
                                                                        {
-                                                                               printf("%s -constraint- %s\n", ctrl->bone->name, link->bone->name);
                                                                                RIG_parentControl(ctrl, link->bone);
                                                                                found = 1;
                                                                                break;
@@ -755,7 +949,6 @@ static void RIG_reconnectControlBones(RigGraph *rg)
                                        /* check if parent is already linked */
                                        if (ctrl_parent && ctrl_parent->link)
                                        {
-                                               printf("%s -parent- %s\n", ctrl->bone->name, ctrl_parent->bone->name);
                                                RIG_parentControl(ctrl, ctrl_parent->bone);
                                                change = 1;
                                        }
@@ -767,7 +960,6 @@ static void RIG_reconnectControlBones(RigGraph *rg)
                                                        /* if a child is linked, link to that one */
                                                        if (ctrl_child->link && ctrl_child->bone->parent == ctrl->bone)
                                                        {
-                                                               printf("%s -child- %s\n", ctrl->bone->name, ctrl_child->bone->name);
                                                                RIG_parentControl(ctrl, ctrl_child->bone);
                                                                change = 1;
                                                                break;
@@ -777,8 +969,54 @@ static void RIG_reconnectControlBones(RigGraph *rg)
                                }
                        }
                }
-               
        }
+       
+       /* third pass, link control tails */
+       for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next)
+       {
+               /* fit bone already means full match, so skip those */
+               if ((ctrl->flag & RIG_CTRL_FIT_BONE) == 0)
+               {
+                       GHashIterator ghi;
+                       
+                       /* look on deform bones first */
+                       BLI_ghashIterator_init(&ghi, rg->bones_map);
+                       
+                       for( ; !BLI_ghashIterator_isDone(&ghi); BLI_ghashIterator_step(&ghi))
+                       {
+                               EditBone *bone = (EditBone*)BLI_ghashIterator_getValue(&ghi);
+                               
+                               /* don't link with parent */
+                               if (bone->parent != ctrl->bone)
+                               {
+                                       if (VecLenf(ctrl->bone->tail, bone->head) < 0.01)
+                                       {
+                                               printf("%s -> %s: TL_HEAD\n", ctrl->bone->name, bone->name);
+                                               ctrl->tail_mode = TL_HEAD;
+                                               ctrl->link_tail = bone;
+                                               break;
+                                       }
+                                       else if (VecLenf(ctrl->bone->tail, bone->tail) < 0.01)
+                                       {
+                                               printf("%s -> %s: TL_TAIL\n", ctrl->bone->name, bone->name);
+                                               ctrl->tail_mode = TL_TAIL;
+                                               ctrl->link_tail = bone;
+                                               break;
+                                       }
+                               }
+                       }
+                       
+                       /* if we haven't found one yet, look in control bones */
+                       if (ctrl->tail_mode == TL_NONE)
+                       {
+                       }
+               }
+               else
+               {
+                       printf("%s FIT\n", ctrl->bone->name);
+               }
+       }
+       
 }
 
 /*******************************************************************************************************/
@@ -1034,7 +1272,7 @@ static void RIG_removeUneededOffsets(RigGraph *rg)
        }
 }
 
-static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node)
+static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node, int selected)
 {
        EditBone *bone, *last_bone = root_bone;
        RigArc *arc = NULL;
@@ -1044,42 +1282,45 @@ static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bo
        {
                int nb_children;
                
-               if ((bone->flag & BONE_NO_DEFORM) == 0)
-               {
-                       BLI_ghash_insert(rg->bones_map, bone->name, bone);
-               
-                       if (arc == NULL)
+               if (selected == 0 || (bone->flag & BONE_SELECTED))
+               { 
+                       if ((bone->flag & BONE_NO_DEFORM) == 0)
                        {
-                               arc = newRigArc(rg);
+                               BLI_ghash_insert(rg->bones_map, bone->name, bone);
+                       
+                               if (arc == NULL)
+                               {
+                                       arc = newRigArc(rg);
+                                       
+                                       if (starting_node == NULL)
+                                       {
+                                               starting_node = newRigNodeHead(rg, arc, root_bone->head);
+                                       }
+                                       else
+                                       {
+                                               addRigNodeHead(rg, arc, starting_node);
+                                       }
+                               }
                                
-                               if (starting_node == NULL)
+                               if (bone->parent && (bone->flag & BONE_CONNECTED) == 0)
                                {
-                                       starting_node = newRigNodeHead(rg, arc, root_bone->head);
+                                       RIG_addEdgeToArc(arc, bone->head, NULL);
                                }
-                               else
+                               
+                               RIG_addEdgeToArc(arc, bone->tail, bone);
+                               
+                               last_bone = bone;
+                               
+                               if (strcmp(bone->name, "head") == 0)
                                {
-                                       addRigNodeHead(rg, arc, starting_node);
+                                       contain_head = 1;
                                }
                        }
-                       
-                       if (bone->parent && (bone->flag & BONE_CONNECTED) == 0)
-                       {
-                               RIG_addEdgeToArc(arc, bone->head, NULL);
-                       }
-                       
-                       RIG_addEdgeToArc(arc, bone->tail, bone);
-                       
-                       last_bone = bone;
-                       
-                       if (strcmp(bone->name, "head") == 0)
+                       else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) /* ignore locked bones */
                        {
-                               contain_head = 1;
+                               RIG_addControlBone(rg, bone);
                        }
                }
-               else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) /* ignore locked bones */
-               {
-                       RIG_addControlBone(rg, bone);
-               }
                
                nb_children = countEditBoneChildren(list, bone);
                if (nb_children > 1)
@@ -1099,7 +1340,7 @@ static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bo
                        for (i = 0; i < nb_children; i++)
                        {
                                root_bone = nextEditBoneChild(list, bone, i);
-                               RIG_arcFromBoneChain(rg, list, root_bone, end_node);
+                               RIG_arcFromBoneChain(rg, list, root_bone, end_node, selected);
                        }
                        
                        /* arc ends here, break */
@@ -1266,21 +1507,30 @@ void RIG_printGraph(RigGraph *rg)
 
 /*******************************************************************************************************/
 
-static RigGraph *armatureToGraph(Object *ob, bArmature *arm)
+RigGraph *armatureToGraph(Object *ob, bArmature *arm)
 {
        EditBone *ebone;
        RigGraph *rg;
        
        rg = newRigGraph();
        
-       make_boneList(&rg->editbones, &arm->bonebase, NULL);
+       if (G.obedit == ob)
+       {
+               rg->editbones = &G.edbo;
+       }
+       else
+       {
+               rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones");
+               make_boneList(rg->editbones, &arm->bonebase, NULL);
+       }
+       
        rg->ob = ob;
 
        /* Do the rotations */
-       for (ebone = rg->editbones.first; ebone; ebone=ebone->next){
+       for (ebone = rg->editbones->first; ebone; ebone=ebone->next){
                if (ebone->parent == NULL)
                {
-                       RIG_arcFromBoneChain(rg, &rg->editbones, ebone, NULL);
+                       RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 0);
                }
        }
        
@@ -1306,25 +1556,73 @@ static RigGraph *armatureToGraph(Object *ob, bArmature *arm)
        return rg;
 }
 
-/************************************ GENERATING *****************************************************/
-
-static EditBone *add_editbonetolist(char *name, ListBase *list)
+RigGraph *armatureSelectedToGraph(Object *ob, bArmature *arm)
 {
-       EditBone *bone= MEM_callocN(sizeof(EditBone), "eBone");
-       
-       BLI_strncpy(bone->name, name, 32);
-       unique_editbone_name(list, bone->name);
-       
-       BLI_addtail(list, bone);
+       EditBone *ebone;
+       RigGraph *rg;
+       
+       rg = newRigGraph();
        
-       bone->flag |= BONE_TIPSEL;
-       bone->weight= 1.0F;
-       bone->dist= 0.25F;
-       bone->xwidth= 0.1;
-       bone->zwidth= 0.1;
-       bone->ease1= 1.0;
-       bone->ease2= 1.0;
-       bone->rad_head= 0.10;
+       if (G.obedit == ob)
+       {
+               rg->editbones = &G.edbo;
+       }
+       else
+       {
+               rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones");
+               make_boneList(rg->editbones, &arm->bonebase, NULL);
+       }
+
+       rg->ob = ob;
+
+       /* Do the rotations */
+       for (ebone = rg->editbones->first; ebone; ebone=ebone->next){
+               if (ebone->parent == NULL)
+               {
+                       RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 1);
+               }
+       }
+       
+       BLI_removeDoubleNodes((BGraph*)rg, 0.001);
+       
+       RIG_removeNormalNodes(rg);
+       
+       RIG_removeUneededOffsets(rg);
+       
+       BLI_buildAdjacencyList((BGraph*)rg);
+       
+       RIG_findHead(rg);
+
+       BLI_markdownSymmetry((BGraph*)rg, (BNode*)rg->head, G.scene->toolsettings->skgen_symmetry_limit);
+       
+       RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */
+       
+       if (BLI_isGraphCyclic((BGraph*)rg))
+       {
+               printf("armature cyclic\n");
+       }
+       
+       return rg;
+}
+/************************************ GENERATING *****************************************************/
+
+static EditBone *add_editbonetolist(char *name, ListBase *list)
+{
+       EditBone *bone= MEM_callocN(sizeof(EditBone), "eBone");
+       
+       BLI_strncpy(bone->name, name, 32);
+       unique_editbone_name(list, bone->name, NULL);
+       
+       BLI_addtail(list, bone);
+       
+       bone->flag |= BONE_TIPSEL;
+       bone->weight= 1.0F;
+       bone->dist= 0.25F;
+       bone->xwidth= 0.1;
+       bone->zwidth= 0.1;
+       bone->ease1= 1.0;
+       bone->ease2= 1.0;
+       bone->rad_head= 0.10;
        bone->rad_tail= 0.05;
        bone->segments= 1;
        bone->layer=  1;//arm->layer;
@@ -1356,7 +1654,7 @@ EditBone * generateBonesForArc(RigGraph *rigg, ReebArc *arc, ReebNode *head, Ree
                int total = 0;
                int boneStart = iter.start;
                
-               parent = add_editbonetolist("Bone", &rigg->editbones);
+               parent = add_editbonetolist("Bone", rigg->editbones);
                parent->flag = BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
                VECCOPY(parent->head, head->p);
                
@@ -1405,7 +1703,7 @@ EditBone * generateBonesForArc(RigGraph *rigg, ReebArc *arc, ReebNode *head, Ree
                        {
                                VECCOPY(parent->tail, btail);
 
-                               child = add_editbonetolist("Bone", &rigg->editbones);
+                               child = add_editbonetolist("Bone", rigg->editbones);
                                VECCOPY(child->head, parent->tail);
                                child->parent = parent;
                                child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
@@ -1481,38 +1779,95 @@ void generateMissingArcs(RigGraph *rigg)
 
 /************************************ RETARGETTING *****************************************************/
 
+static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize);
+
+static void repositionTailControl(RigGraph *rigg, RigControl *ctrl);
+
+static void finalizeControl(RigGraph *rigg, RigControl *ctrl, float resize)
+{
+       if ((ctrl->flag & RIG_CTRL_DONE) == RIG_CTRL_DONE)
+       {
+               RigControl *ctrl_child;
+               
+               /* if there was a tail link: apply link, recalc resize factor and qrot */
+               if (ctrl->tail_mode != TL_NONE)
+               {
+                       float *tail_vec = NULL;
+                       float v1[3], v2[3], qtail[4];
+                       
+                       if (ctrl->tail_mode == TL_TAIL)
+                       {
+                               tail_vec = ctrl->link_tail->tail;
+                       }
+                       else if (ctrl->tail_mode == TL_HEAD)
+                       {
+                               tail_vec = ctrl->link_tail->head;
+                       }
+                       
+                       VecSubf(v1, ctrl->bone->tail, ctrl->bone->head);
+                       VecSubf(v2, tail_vec, ctrl->bone->head);
+                       
+                       VECCOPY(ctrl->bone->tail, tail_vec);
+                       
+                       RotationBetweenVectorsToQuat(qtail, v1, v2);
+                       QuatMul(ctrl->qrot, qtail, ctrl->qrot);
+                       
+                       resize = VecLength(v2) / VecLenf(ctrl->head, ctrl->tail);
+               }
+               
+               ctrl->bone->roll = rollBoneByQuat(ctrl->bone, ctrl->up_axis, ctrl->qrot);
+       
+               /* Cascade to connected control bones */
+               for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next)
+               {
+                       if (ctrl_child->link == ctrl->bone)
+                       {
+                               repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, ctrl->qrot, resize);
+                       }
+                       if (ctrl_child->link_tail == ctrl->bone)
+                       {
+                               repositionTailControl(rigg, ctrl_child);
+                       }
+               }
+       }       
+}
+
+static void repositionTailControl(RigGraph *rigg, RigControl *ctrl)
+{
+       ctrl->flag |= RIG_CTRL_TAIL_DONE;
+
+       finalizeControl(rigg, ctrl, 1); /* resize will be recalculated anyway so we don't need it */
+}
+
 static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize)
 {
-       RigControl *ctrl_child;
        float parent_offset[3], tail_offset[3];
        
-       VecSubf(tail_offset, ctrl->tail, ctrl->head);
-       VecMulf(tail_offset, resize);
-       
        VECCOPY(parent_offset, ctrl->offset);
        VecMulf(parent_offset, resize);
-       
        QuatMulVecf(qrot, parent_offset);
-       QuatMulVecf(qrot, tail_offset);
        
        VecAddf(ctrl->bone->head, head, parent_offset); 
-       VecAddf(ctrl->bone->tail, ctrl->bone->head, tail_offset);
-       ctrl->bone->roll = getNewBoneRoll(ctrl->bone, ctrl->up_axis, qrot);
-       
-       ctrl->flag |= RIG_CTRL_DONE;
 
-       /* Cascade to connected control bones */
-       for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next)
+       ctrl->flag |= RIG_CTRL_HEAD_DONE;
+
+       QUATCOPY(ctrl->qrot, qrot); 
+
+       if (ctrl->tail_mode == TL_NONE)
        {
-               if (ctrl_child->link == ctrl->bone)
-               {
-                       repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, qrot, resize);
-               }
+               VecSubf(tail_offset, ctrl->tail, ctrl->head);
+               VecMulf(tail_offset, resize);
+               QuatMulVecf(qrot, tail_offset);
+
+               VecAddf(ctrl->bone->tail, ctrl->bone->head, tail_offset);
+               
+               ctrl->flag |= RIG_CTRL_TAIL_DONE;
        }
 
+       finalizeControl(rigg, ctrl, resize);
 }
 
-static void repositionBone(RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3])
+static void repositionBone(RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3], float up_axis[3])
 {
        EditBone *bone;
        RigControl *ctrl;
@@ -1532,17 +1887,44 @@ static void repositionBone(RigGraph *rigg, RigEdge *edge, float vec0[3], float v
        
        RotationBetweenVectorsToQuat(qrot, v1, v2);
        
+       VECCOPY(bone->head, vec0);
+       VECCOPY(bone->tail, vec1);
+       
+       if (!VecIsNull(up_axis))
+       {
+               float qroll[4];
+
+               if (G.scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_VIEW)
+               {
+                       bone->roll = rollBoneByQuatAligned(bone, edge->up_axis, qrot, qroll, up_axis);
+               }
+               else if (G.scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_JOINT)
+               {
+                       bone->roll = rollBoneByQuatJoint(edge, edge->next, qrot, qroll);
+               }
+               else
+               {
+                       QuatOne(qroll);
+               }
+               
+               QuatMul(qrot, qroll, qrot);
+       }
+       else
+       {
+               bone->roll = rollBoneByQuat(bone, edge->up_axis, qrot);
+       }
+
        for (ctrl = rigg->controls.first; ctrl; ctrl = ctrl->next)
        {
                if (ctrl->link == bone)
                {
                        repositionControl(rigg, ctrl, vec0, vec1, qrot, resize);
                }
+               if (ctrl->link_tail == bone)
+               {
+                       repositionTailControl(rigg, ctrl);
+               }
        }
-       
-       VECCOPY(bone->head, vec0);
-       VECCOPY(bone->tail, vec1);
-       bone->roll = getNewBoneRoll(bone, edge->up_axis, qrot);
 }
 
 static RetargetMode detectArcRetargetMode(RigArc *arc);
@@ -1603,29 +1985,6 @@ static RetargetMode detectArcRetargetMode(RigArc *iarc)
 }
 
 #ifndef USE_THREADS
-static void printCostCube(float *cost_cube, int nb_joints)
-{
-       int i;
-       
-       for (i = 0; i < nb_joints; i++)
-       {
-               printf("%0.3f ", cost_cube[3 * i]);
-       }
-       printf("\n");
-
-       for (i = 0; i < nb_joints; i++)
-       {
-               printf("%0.3f ", cost_cube[3 * i + 1]);
-       }
-       printf("\n");
-
-       for (i = 0; i < nb_joints; i++)
-       {
-               printf("%0.3f ", cost_cube[3 * i + 2]);
-       }
-       printf("\n");
-}
-
 static void printMovesNeeded(int *positions, int nb_positions)
 {
        int moves = 0;
@@ -1651,7 +2010,7 @@ static void printPositions(int *positions, int nb_positions)
 }
 #endif
 
-#define MAX_COST 100 /* FIX ME */
+#define MAX_COST FLT_MAX /* FIX ME */
 
 static float costDistance(ReebArcIterator *iter, float *vec0, float *vec1, int i0, int i1)
 {
@@ -1772,187 +2131,6 @@ static float calcCostAngleLengthDistance(ReebArcIterator *iter, float **vec_cach
        return new_cost;
 }
 
-static float calcCost(ReebArcIterator *iter, RigEdge *e1, RigEdge *e2, float *vec0, float *vec1, float *vec2, int i0, int i1, int i2)
-{
-       float vec_second[3], vec_first[3];
-       float length1, length2;
-       float new_cost = 0;
-
-       VecSubf(vec_second, vec2, vec1);
-       length2 = Normalize(vec_second);
-
-       VecSubf(vec_first, vec1, vec0); 
-       length1 = Normalize(vec_first);
-
-       /* Angle cost */        
-       new_cost += costAngle(e1->angle, vec_first, vec_second);
-
-       /* Length cost */
-       new_cost += costLength(e1->length, length1);
-       new_cost += costLength(e2->length, length2);
-
-       /* Distance cost */
-       new_cost += costDistance(iter, vec0, vec1, i0, i1);
-       new_cost += costDistance(iter, vec1, vec2, i1, i2);
-
-       return new_cost;
-}
-
-static void calcGradient(RigEdge *e1, RigEdge *e2, ReebArcIterator *iter, int index, int nb_joints, float *cost_cube, int *positions, float **vec_cache)
-{
-       EmbedBucket *bucket = NULL;
-       float *vec0, *vec1, *vec2;
-       float current_cost;
-       int i0, i1, i2;
-       int next_position;
-
-       vec0 = vec_cache[index];
-       vec1 = vec_cache[index + 1];
-       vec2 = vec_cache[index + 2];
-       
-       if (index == 0)
-       {
-               i0 = 0;
-       }
-       else
-       {
-               i0 = positions[index - 1];
-       }
-       
-       i1 = positions[index];
-       
-       if (index +1 == nb_joints)
-       {
-               i2 = iter->length;
-       }
-       else
-       {
-               i2 = positions[index + 1];
-       }
-
-
-       current_cost = calcCost(iter, e1, e2, vec0, vec1, vec2, i0, i1, i2);
-       cost_cube[index * 3 + 1] = current_cost;
-       
-       next_position = positions[index] + 1;
-       
-       if (index + 1 < nb_joints && next_position == positions[index + 1])
-       {
-               cost_cube[index * 3 + 2] = MAX_COST;
-       }
-       else if (next_position > iter->length) /* positions are indexed at 1, so length is last */
-       {
-               cost_cube[index * 3 + 2] = MAX_COST;
-       }
-       else
-       {
-               bucket = peekBucket(iter, next_position);
-               
-               if (bucket == NULL)
-               {
-                       cost_cube[index * 3 + 2] = MAX_COST;
-               }
-               else
-               {
-                       vec1 = bucket->p;
-                       
-                       cost_cube[index * 3 + 2] = calcCost(iter, e1, e2, vec0, vec1, vec2, i0, next_position, i2) - current_cost;
-               }
-       }
-
-       next_position = positions[index] - 1;
-       
-       if (index - 1 > -1 && next_position == positions[index - 1])
-       {
-               cost_cube[index * 3] = MAX_COST;
-       }
-       else if (next_position < 1) /* positions are indexed at 1, so 1 is first */
-       {
-               cost_cube[index * 3] = MAX_COST;
-       }
-       else
-       {
-               bucket = peekBucket(iter, next_position);
-               
-               if (bucket == NULL)
-               {
-                       cost_cube[index * 3] = MAX_COST;
-               }
-               else
-               {
-                       vec1 = bucket->p;
-                       
-                       cost_cube[index * 3] = calcCost(iter, e1, e2, vec0, vec1, vec2, i0, next_position, i2) - current_cost;
-               }
-       }
-}
-
-static float probability(float delta_cost, float temperature)
-{
-       if (delta_cost < 0)
-       {
-               return 1;
-       }
-       else
-       {
-               return (float)exp(delta_cost / temperature);
-       }
-}
-
-static int neighbour(int nb_joints, float *cost_cube, int *moving_joint, int *moving_direction)
-{
-       int total = 0;
-       int chosen = 0;
-       int i;
-       
-       for (i = 0; i < nb_joints; i++)
-       {
-               if (cost_cube[i * 3] < MAX_COST)
-               {
-                       total++;
-               }
-               
-               if (cost_cube[i * 3 + 2] < MAX_COST)
-               {
-                       total++;
-               }
-       }
-       
-       if (total == 0)
-       {
-               return 0;
-       }
-       
-       chosen = (int)(BLI_drand() * total);
-       
-       for (i = 0; i < nb_joints; i++)
-       {
-               if (cost_cube[i * 3] < MAX_COST)
-               {
-                       if (chosen == 0)
-                       {
-                               *moving_joint = i;
-                               *moving_direction = -1;
-                               break;
-                       }
-                       chosen--;
-               }
-               
-               if (cost_cube[i * 3 + 2] < MAX_COST)
-               {
-                       if (chosen == 0)
-                       {
-                               *moving_joint = i;
-                               *moving_direction = 1;
-                               break;
-                       }
-                       chosen--;
-               }
-       }
-       
-       return 1;
-}
-
 static int indexMemoNode(int nb_positions, int previous, int current, int joints_left)
 {
        return joints_left * nb_positions * nb_positions + current * nb_positions + previous;
@@ -2070,13 +2248,10 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
        ReebArc *earc = iarc->link_mesh;
        float min_cost = FLT_MAX;
        float *vec0, *vec1, *vec2;
-       float **vec_cache;
-       float *cost_cache;
        int *best_positions;
-       int *positions;
        int nb_edges = BLI_countlist(&iarc->edges);
        int nb_joints = nb_edges - 1;
-       RetargetMethod method = G.scene->toolsettings->skgen_optimisation_method;
+       RetargetMethod method = METHOD_MEMOIZE;
        int i;
        
        if (nb_joints > earc->bcount)
@@ -2085,10 +2260,7 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
                return;
        }
 
-       positions = MEM_callocN(sizeof(int) * nb_joints, "Aggresive positions");
-       best_positions = MEM_callocN(sizeof(int) * nb_joints, "Best Aggresive positions");
-       cost_cache = MEM_callocN(sizeof(float) * nb_edges, "Cost cache");
-       vec_cache = MEM_callocN(sizeof(float*) * (nb_edges + 1), "Vec cache");
+       best_positions = MEM_callocN(sizeof(int) * nb_joints, "Best positions");
        
        if (testFlipArc(iarc, inode_start))
        {
@@ -2100,23 +2272,18 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
                node_start = earc->head;
                node_end = earc->tail;
        }
-       
-       /* init with first values */
-       for (i = 0; i < nb_joints; i++)
-       {
-               positions[i] = i + 1;
-               //positions[i] = (earc->bcount / nb_edges) * (i + 1);
-       }
-       
-       /* init cost cache */
-       for (i = 0; i < nb_edges; i++)
+
+       /* equal number of joints and potential position, just fill them in */
+       if (nb_joints == earc->bcount)
        {
-               cost_cache[i] = 0;
+               int i;
+               
+               /* init with first values */
+               for (i = 0; i < nb_joints; i++)
+               {
+                       best_positions[i] = i + 1;
+               }
        }
-       
-       vec_cache[0] = node_start->p;
-       vec_cache[nb_edges] = node_end->p;
-
        if (method == METHOD_MEMOIZE)
        {
                int nb_positions = earc->bcount;
@@ -2148,10 +2315,32 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
        /* BRUTE FORCE */
        else if (method == METHOD_BRUTE_FORCE)
        {
+               float **vec_cache;
+               float *cost_cache;
+               int *positions;
                int last_index = 0;
                int first_pass = 1;
                int must_move = nb_joints - 1;
                
+               positions = MEM_callocN(sizeof(int) * nb_joints, "Aggresive positions");
+               cost_cache = MEM_callocN(sizeof(float) * nb_edges, "Cost cache");
+               vec_cache = MEM_callocN(sizeof(float*) * (nb_edges + 1), "Vec cache");
+       
+               /* init with first values */
+               for (i = 0; i < nb_joints; i++)
+               {
+                       positions[i] = i + 1;
+               }
+               
+               /* init cost cache */
+               for (i = 0; i < nb_edges; i++)
+               {
+                       cost_cache[i] = 0;
+               }
+               
+               vec_cache[0] = node_start->p;
+               vec_cache[nb_edges] = node_end->p;              
+               
                while(1)
                {
                        float cost = 0;
@@ -2286,115 +2475,11 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
                                memcpy(best_positions, positions, sizeof(int) * nb_joints);
                        }
                }
-       }
-       /* SIMULATED ANNEALING */
-       else if (method == METHOD_ANNEALING)
-       {
-               RigEdge *previous;
-               float *cost_cube;
-               float cost;
-               int k;
-               int kmax;
-
-               kmax = 100000;
-               
-               BLI_srand(nb_joints);
-               
-               /* [joint: index][position: -1, 0, +1] */
-               cost_cube = MEM_callocN(sizeof(float) * 3 * nb_joints, "Cost Cube");
-               
-               initArcIterator(&iter, earc, node_start);
-
-               /* init vec_cache */
-               for (i = 0; i < nb_joints; i++)
-               {
-                       bucket = peekBucket(&iter, positions[i]);
-                       vec_cache[i + 1] = bucket->p;
-               }
-               
-               cost = 0;
-
-               /* init cost cube */
-               for (previous = iarc->edges.first, edge = previous->next, i = 0;
-                        edge;
-                        previous = edge, edge = edge->next, i += 1)
-               {
-                       calcGradient(previous, edge, &iter, i, nb_joints, cost_cube, positions, vec_cache);
-                       
-                       cost += cost_cube[3 * i + 1];
-               }
-               
-#ifndef USE_THREADS
-               printf("initial cost: %f\n", cost);
-               printf("kmax: %i\n", kmax);
-#endif
-               
-               for (k = 0; k < kmax; k++)
-               {
-                       int status;
-                       int moving_joint = -1;
-                       int move_direction = -1;
-                       float delta_cost;
-                       float temperature;
-                       
-                       status = neighbour(nb_joints, cost_cube, &moving_joint, &move_direction);
-                       
-                       if (status == 0)
-                       {
-                               /* if current state is still a minimum, copy it */
-                               if (cost < min_cost)
-                               {
-                                       min_cost = cost;
-                                       memcpy(best_positions, positions, sizeof(int) * nb_joints);
-                               }
-                               break;
-                       }
-                       
-                       delta_cost = cost_cube[moving_joint * 3 + (1 + move_direction)];
-
-                       temperature = 1 - (float)k / (float)kmax;
-                       if (probability(delta_cost, temperature) > BLI_frand())
-                       {
-                               /* update position */                   
-                               positions[moving_joint] += move_direction;
-                               
-                               /* update vector cache */
-                               bucket = peekBucket(&iter, positions[moving_joint]);
-                               vec_cache[moving_joint + 1] = bucket->p;
-                               
-                               cost += delta_cost;
        
-                               /* cost optimizing */
-                               if (cost < min_cost)
-                               {
-                                       min_cost = cost;
-                                       memcpy(best_positions, positions, sizeof(int) * nb_joints);
-                               }
-
-                               /* update cost cube */                  
-                               for (previous = iarc->edges.first, edge = previous->next, i = 0;
-                                        edge;
-                                        previous = edge, edge = edge->next, i += 1)
-                               {
-                                       if (i == moving_joint - 1 ||
-                                               i == moving_joint ||
-                                               i == moving_joint + 1)
-                                       {
-                                               calcGradient(previous, edge, &iter, i, nb_joints, cost_cube, positions, vec_cache);
-                                       }
-                               }
-                       }
-               }
-
-               //min_cost = cost;
-               //memcpy(best_positions, positions, sizeof(int) * nb_joints);
-               
-//             printf("k = %i\n", k);
-               
-               
-               MEM_freeN(cost_cube);
-       }       
-
+               MEM_freeN(positions);
+               MEM_freeN(cost_cache);
+               MEM_freeN(vec_cache);
+       }
 
        vec0 = node_start->p;
        initArcIterator(&iter, earc, node_start);
@@ -2411,28 +2496,28 @@ static void retargetArctoArcAggresive(RigGraph *rigg, RigArc *iarc, RigNode *ino
                 edge;
                 edge = edge->next, i++)
        {
+               float *no = NULL;
                if (i < nb_joints)
                {
                        bucket = peekBucket(&iter, best_positions[i]);
                        vec1 = bucket->p;
+                       no = bucket->no;
                }
                else
                {
                        vec1 = node_end->p;
+                       no = node_end->no;
                }
                
                if (edge->bone)
                {
-                       repositionBone(rigg, edge, vec0, vec1);
+                       repositionBone(rigg, edge, vec0, vec1, no);
                }
                
                vec0 = vec1;
        }
-       
-       MEM_freeN(positions);
+
        MEM_freeN(best_positions);
-       MEM_freeN(cost_cache);
-       MEM_freeN(vec_cache);
 }
 
 static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_start)
@@ -2489,7 +2574,7 @@ static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_
        for (edge = iarc->edges.first; edge; edge = edge->next)
        {
                float new_bone_length = edge->length / iarc->length * embedding_length;
-
+               float *no = NULL;
                float length = 0;
 
                while (bucket && new_bone_length > length)
@@ -2498,17 +2583,19 @@ static void retargetArctoArcLength(RigGraph *rigg, RigArc *iarc, RigNode *inode_
                        bucket = nextBucket(&iter);
                        previous_vec = vec1;
                        vec1 = bucket->p;
+                       no = bucket->no;
                }
                
                if (bucket == NULL)
                {
                        vec1 = node_end->p;
+                       no = node_end->no;
                }
 
                /* no need to move virtual edges (space between unconnected bones) */           
                if (edge->bone)
                {
-                       repositionBone(rigg, edge, vec0, vec1);
+                       repositionBone(rigg, edge, vec0, vec1, no);
                }
                
                vec0 = vec1;
@@ -2551,11 +2638,11 @@ void *exec_retargetArctoArc(void *param)
 
                if (testFlipArc(iarc, inode_start))
                {
-                       repositionBone(rigg, edge, earc->tail->p, earc->head->p);
+                       repositionBone(rigg, edge, earc->tail->p, earc->head->p, earc->head->no);
                }
                else
                {
-                       repositionBone(rigg, edge, earc->head->p, earc->tail->p);
+                       repositionBone(rigg, edge, earc->head->p, earc->tail->p, earc->tail->no);
                }
        }
        else
@@ -2819,6 +2906,13 @@ static void retargetSubgraph(RigGraph *rigg, RigArc *start_arc, RigNode *start_n
        }
 }
 
+static void finishRetarget(RigGraph *rigg)
+{
+#ifdef USE_THREADS
+       BLI_end_worker(rigg->worker);
+#endif
+}
+
 static void adjustGraphs(RigGraph *rigg)
 {
        RigArc *arc;
@@ -2831,12 +2925,10 @@ static void adjustGraphs(RigGraph *rigg)
                }
        }
 
-#ifdef USE_THREADS
-       BLI_end_worker(rigg->worker);
-#endif
+       finishRetarget(rigg);
 
        /* Turn the list into an armature */
-       editbones_to_armature(&rigg->editbones, rigg->ob);
+       editbones_to_armature(rigg->editbones, rigg->ob);
        
        BIF_undo_push("Retarget Skeleton");
 }
@@ -2860,12 +2952,10 @@ static void retargetGraphs(RigGraph *rigg)
        
        //generateMissingArcs(rigg);
        
-#ifdef USE_THREADS
-       BLI_end_worker(rigg->worker);
-#endif
+       finishRetarget(rigg);
 
        /* Turn the list into an armature */
-       editbones_to_armature(&rigg->editbones, rigg->ob);
+       editbones_to_armature(rigg->editbones, rigg->ob);
 }
 
 
@@ -2950,6 +3040,52 @@ void BIF_retargetArmature()
        allqueue(REDRAWVIEW3D, 0);
 }
 
+void BIF_retargetArc(ReebArc *earc)
+{
+       Object *ob;
+       RigGraph *template_rigg;
+       RigGraph *rigg;
+       RigArc *iarc;
+       bArmature *arm;
+       
+       if (G.scene->toolsettings->skgen_template &&
+               G.scene->toolsettings->skgen_template->type == OB_ARMATURE)
+       {
+               ob = G.scene->toolsettings->skgen_template;     
+               arm = ob->data;
+               template_rigg = armatureToGraph(ob, arm);
+       }
+       else
+       {
+               ob = G.obedit;  
+               arm = ob->data;
+               template_rigg = armatureSelectedToGraph(ob, arm);
+       }
+       
+       if (template_rigg->arcs.first == NULL)
+       {
+               error("No Template and no deforming bones selected");
+               return;
+       }
+       
+       rigg = cloneRigGraph(template_rigg, &G.edbo, G.obedit);
+       
+       iarc = rigg->arcs.first;
+       
+       iarc->link_mesh = earc;
+       iarc->head->link_mesh = earc->head;
+       iarc->tail->link_mesh = earc->tail;
+       
+       retargetArctoArc(rigg, iarc, iarc->head);
+       
+       finishRetarget(rigg);
+       
+       RIG_freeRigGraph((BGraph*)template_rigg);
+       RIG_freeRigGraph((BGraph*)rigg);
+       
+       allqueue(REDRAWVIEW3D, 0);
+}
+
 void BIF_adjustRetarget()
 {
        if (GLOBAL_RIGG)
diff --git a/source/blender/src/editarmature_sketch.c b/source/blender/src/editarmature_sketch.c
new file mode 100644 (file)
index 0000000..c221cb5
--- /dev/null
@@ -0,0 +1,2747 @@
+/**
+ * $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 "DNA_userdef_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_graph.h"
+#include "BLI_ghash.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 "BIF_retarget.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+#include "reeb.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];
+       float no[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                     before;
+       int                     after;
+       int                     gesture_index;
+       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 ******************************/
+
+typedef int(NextSubdivisionFunc)(SK_Stroke*, int, int, float[3], float[3]);
+
+void sk_deleteSelectedStrokes(SK_Sketch *sketch);
+
+void sk_freeStroke(SK_Stroke *stk);
+void sk_freeSketch(SK_Sketch *sketch);
+
+SK_Point *sk_lastStrokePoint(SK_Stroke *stk);
+
+int nextFixedSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3]);
+int nextLengthSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3]);
+int nextCorrelationSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3]);
+
+/******************** TEMPLATES UTILS *************************/
+
+char  *TEMPLATES_MENU = NULL;
+int    TEMPLATES_CURRENT = 0;
+GHash *TEMPLATES_HASH = NULL;
+
+void BIF_makeListTemplates()
+{
+       Base *base;
+       int index = 0;
+
+       if (TEMPLATES_HASH != NULL)
+       {
+               BLI_ghash_free(TEMPLATES_HASH, NULL, NULL);
+       }
+       
+       TEMPLATES_HASH = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp);
+       TEMPLATES_CURRENT = 0;
+
+       for ( base = FIRSTBASE; base; base = base->next )
+       {
+               Object *ob = base->object;
+               
+               if (ob != G.obedit && ob->type == OB_ARMATURE)
+               {
+                       index++;
+                       BLI_ghash_insert(TEMPLATES_HASH, SET_INT_IN_POINTER(index), ob);
+                       
+                       if (ob == G.scene->toolsettings->skgen_template)
+                       {
+                               TEMPLATES_CURRENT = index;
+                       }
+               }
+       }
+}
+
+char *BIF_listTemplates()
+{
+       GHashIterator ghi;
+       char menu_header[] = "Template%t|None%x0|";
+       char *p;
+       
+       if (TEMPLATES_MENU != NULL)
+       {
+               MEM_freeN(TEMPLATES_MENU);
+       }
+       
+       TEMPLATES_MENU = MEM_callocN(sizeof(char) * (BLI_ghash_size(TEMPLATES_HASH) * 32 + 30), "skeleton template menu");
+       
+       p = TEMPLATES_MENU;
+       
+       p += sprintf(TEMPLATES_MENU, "%s", menu_header);
+       
+       BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
+       
+       while (!BLI_ghashIterator_isDone(&ghi))
+       {
+               Object *ob = BLI_ghashIterator_getValue(&ghi);
+               int key = (int)BLI_ghashIterator_getKey(&ghi);
+               
+               p += sprintf(p, "|%s%%x%i", ob->id.name+2, key);
+               
+               BLI_ghashIterator_step(&ghi);
+       }
+       
+       return TEMPLATES_MENU;
+}
+
+int   BIF_currentTemplate()
+{
+       if (TEMPLATES_CURRENT == 0 && G.scene->toolsettings->skgen_template != NULL)
+       {
+               GHashIterator ghi;
+               BLI_ghashIterator_init(&ghi, TEMPLATES_HASH);
+               
+               while (!BLI_ghashIterator_isDone(&ghi))
+               {
+                       Object *ob = BLI_ghashIterator_getValue(&ghi);
+                       int key = (int)BLI_ghashIterator_getKey(&ghi);
+                       
+                       if (ob == G.scene->toolsettings->skgen_template)
+                       {
+                               TEMPLATES_CURRENT = key;
+                               break;
+                       }
+                       
+                       BLI_ghashIterator_step(&ghi);
+               }
+       }
+       
+       return TEMPLATES_CURRENT;
+}
+
+void  BIF_freeTemplates()
+{
+       if (TEMPLATES_MENU != NULL)
+       {
+               MEM_freeN(TEMPLATES_MENU);
+       }
+       
+       if (TEMPLATES_HASH != NULL)
+       {
+               BLI_ghash_free(TEMPLATES_HASH, NULL, NULL);
+       }
+}
+
+void  BIF_setTemplate(int index)
+{
+       if (index > 0)
+       {
+               G.scene->toolsettings->skgen_template = BLI_ghash_lookup(TEMPLATES_HASH, SET_INT_IN_POINTER(index));
+       }
+       else
+       {
+               G.scene->toolsettings->skgen_template = NULL;
+       }
+}      
+
+/******************** 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;
+}
+/*********************** CONVERSION ***************************/
+
+void sk_autoname(ReebArc *arc)
+{
+       if (G.scene->toolsettings->skgen_retarget_options & SK_RETARGET_AUTONAME)
+       {
+               if (arc == NULL)
+               {
+                       char *num = G.scene->toolsettings->skgen_num_string;
+                       int i = atoi(num);
+                       i++;
+                       BLI_snprintf(num, 8, "%i", i);
+               }
+               else
+               {
+                       char *side = G.scene->toolsettings->skgen_side_string;
+                       int valid = 0;
+                       int caps = 0;
+                       
+                       if (BLI_streq(side, ""))
+                       {
+                               valid = 1;
+                       }
+                       else if (BLI_streq(side, "R") || BLI_streq(side, "L"))
+                       {
+                               valid = 1;
+                               caps = 1;
+                       }
+                       else if (BLI_streq(side, "r") || BLI_streq(side, "l"))
+                       {
+                               valid = 1;
+                               caps = 0;
+                       }
+                       
+                       if (valid)
+                       {
+                               if (arc->head->p[0] < 0)
+                               {
+                                       BLI_snprintf(side, 8, caps?"R":"r");
+                               }
+                               else
+                               {
+                                       BLI_snprintf(side, 8, caps?"L":"l");
+                               }
+                       }
+               }
+       }
+}
+
+ReebNode *sk_pointToNode(SK_Point *pt, float imat[][4], float tmat[][3])
+{
+       ReebNode *node;
+       
+       node = MEM_callocN(sizeof(ReebNode), "reeb node");
+       VECCOPY(node->p, pt->p);
+       Mat4MulVecfl(imat, node->p);
+       
+       VECCOPY(node->no, pt->no);
+       Mat3MulVecfl(tmat, node->no);
+       
+       return node;
+}
+
+ReebArc *sk_strokeToArc(SK_Stroke *stk, float imat[][4], float tmat[][3])
+{
+       ReebArc *arc;
+       int i;
+       
+       arc = MEM_callocN(sizeof(ReebArc), "reeb arc");
+       arc->head = sk_pointToNode(stk->points, imat, tmat);
+       arc->tail = sk_pointToNode(sk_lastStrokePoint(stk), imat, tmat);
+       
+       arc->bcount = stk->nb_points - 2; /* first and last are nodes, don't count */
+       arc->buckets = MEM_callocN(sizeof(EmbedBucket) * arc->bcount, "Buckets");
+       
+       for (i = 0; i < arc->bcount; i++)
+       {
+               VECCOPY(arc->buckets[i].p, stk->points[i + 1].p);
+               Mat4MulVecfl(imat, arc->buckets[i].p);
+
+               VECCOPY(arc->buckets[i].no, stk->points[i + 1].no);
+               Mat3MulVecfl(tmat, arc->buckets[i].no);
+       }
+       
+       return arc;
+}
+
+void sk_retargetStroke(SK_Stroke *stk)
+{
+       float imat[4][4];
+       float tmat[3][3];
+       ReebArc *arc;
+       
+       Mat4Invert(imat, G.obedit->obmat);
+       
+       Mat3CpyMat4(tmat, G.obedit->obmat);
+       Mat3Transp(tmat);
+
+       arc = sk_strokeToArc(stk, imat, tmat);
+       
+       sk_autoname(arc);
+
+       BIF_retargetArc(arc);
+       
+       sk_autoname(NULL);
+       
+       MEM_freeN(arc->head);
+       MEM_freeN(arc->tail);
+       REEB_freeArc((BArc*)arc);
+}
+
+/**************************************************************/
+
+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_initPoint(SK_Point *pt)
+{
+       VECCOPY(pt->no, G.vd->viewinv[2]);
+       Normalize(pt->no);
+       /* more init code here */
+}
+
+void sk_copyPoint(SK_Point *dst, SK_Point *src)
+{
+       memcpy(dst, src, sizeof(SK_Point));
+}
+
+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;
+}
+
+void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk)
+{
+       if (sketch->active_stroke == stk)
+       {
+               sketch->active_stroke = NULL;
+       }
+       
+       BLI_remlink(&sketch->strokes, stk);
+       sk_freeStroke(stk);
+}
+
+void sk_reverseStroke(SK_Stroke *stk)
+{
+       SK_Point *old_points = stk->points;
+       int i = 0;
+       
+       sk_allocStrokeBuffer(stk);
+       
+       for (i = 0; i < stk->nb_points; i++)
+       {
+               sk_copyPoint(stk->points + i, old_points + stk->nb_points - 1 - i);
+       }
+       
+       MEM_freeN(old_points);
+}
+
+
+void sk_cancelStroke(SK_Sketch *sketch)
+{
+       if (sketch->active_stroke != NULL)
+       {
+               sk_removeStroke(sketch, sketch->active_stroke);
+       }
+}
+
+/* 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];
+                       
+                       sk_copyPoint(&pt, &old_points[j+1]);
+
+                       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();
+}
+
+void drawSubdividedStrokeBy(SK_Stroke *stk, int start, int end, NextSubdivisionFunc next_subdividion)
+{
+       float head[3], tail[3];
+       int bone_start = start;
+       int index;
+
+       VECCOPY(head, stk->points[start].p);
+       
+       glColor3f(0, 1, 1);
+       glBegin(GL_POINTS);
+       
+       index = next_subdividion(stk, bone_start, end, head, tail);
+       while (index != -1)
+       {
+               glVertex3fv(tail);
+               
+               VECCOPY(head, tail);
+               bone_start = index; // start next bone from current index
+
+               index = next_subdividion(stk, bone_start, end, head, tail);
+       }
+       
+       glEnd();
+}
+
+void sk_drawStrokeSubdivision(SK_Stroke *stk)
+{
+       int head_index = -1;
+       int i;
+       
+       if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET)
+       {
+               return;
+       }
+
+       
+       for (i = 0; i < stk->nb_points; i++)
+       {
+               SK_Point *pt = stk->points + i;
+               
+               if (pt->type == PT_EXACT || i == stk->nb_points - 1) /* stop on exact or on last point */
+               {
+                       if (head_index == -1)
+                       {
+                               head_index = i;
+                       }
+                       else
+                       {
+                               if (i - head_index > 1)
+                               {
+                                       if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_CORRELATION)
+                                       {
+                                               drawSubdividedStrokeBy(stk, head_index, i, nextCorrelationSubdivision);
+                                       }
+                                       else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH)
+                                       {
+                                               drawSubdividedStrokeBy(stk, head_index, i, nextLengthSubdivision);
+                                       }
+                                       else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED)
+                                       {
+                                               drawSubdividedStrokeBy(stk, head_index, i, nextFixedSubdivision);
+                                       }
+                                       
+                               }
+
+                               head_index = i;
+                       }
+               }
+       }       
+}
+
+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(Object *ob, ListBase *ebones, short mval[2], int *dist)
+{
+       SK_Point *pt = NULL;
+       EditBone *bone;
+       
+       for (bone = ebones->first; bone; bone = bone->next)
+       {
+               float vec[3];
+               short pval[2];
+               int pdist;
+               
+               if ((bone->flag & BONE_CONNECTED) == 0)
+               {
+                       VECCOPY(vec, bone->head);
+                       Mat4MulVecfl(ob->obmat, vec);
+                       project_short_noclip(vec, pval);
+                       
+                       pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
+                       
+                       if (pdist < *dist)
+                       {
+                               *dist = pdist;
+                               pt = &boneSnap;
+                               VECCOPY(pt->p, vec);
+                               pt->type = PT_EXACT;
+                       }
+               }
+               
+               
+               VECCOPY(vec, bone->tail);
+               Mat4MulVecfl(ob->obmat, vec);
+               project_short_noclip(vec, pval);
+               
+               pdist = ABS(pval[0] - mval[0]) + ABS(pval[1] - mval[1]);
+               
+               if (pdist < *dist)
+               {
+                       *dist = pdist;
+                       pt = &boneSnap;
+                       VECCOPY(pt->p, vec);
+                       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_initPoint(&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.obedit, &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)
+{
+       int point_added = 0;
+       SK_Point pt;
+       
+       sk_initPoint(&pt);
+       
+       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)
+{
+       int point_added;
+       SK_Point pt;
+       
+       sk_initPoint(&pt);
+
+       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 (ABS(dd->mval[0] - dd->previous_mval[0]) + ABS(dd->mval[1] - dd->previous_mval[1]) > U.gp_manhattendist)
+       {
+               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;
+}
+/********************************************/
+
+/* bone is assumed to be in GLOBAL space */
+void setBoneRollFromPoint(EditBone *bone, SK_Point *pt, float invmat[][4], float tmat[][3])
+{
+       float tangent[3], cotangent[3], normal[3];
+       
+       VecSubf(tangent, bone->tail, bone->head);
+       Crossf(cotangent, tangent, pt->no);
+       Crossf(normal, cotangent, tangent);
+       
+       Mat3MulVecfl(tmat, normal);
+       Normalize(normal);
+       
+       bone->roll = rollBoneToVector(bone, normal);
+
+}
+
+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;
+       }
+}
+
+int nextFixedSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3])
+{
+       static float stroke_length = 0;
+       static float current_length;
+       static char n;
+       float length_threshold;
+       int i;
+       
+       if (stroke_length == 0)
+       {
+               current_length = 0;
+               for (i = start + 1; i <= end; i++)
+               {
+                       stroke_length += VecLenf(stk->points[i].p, stk->points[i - 1].p);
+               }
+               
+               n = 0;
+               current_length = 0;
+       }
+       
+       n++;
+       
+       length_threshold = n * stroke_length / G.scene->toolsettings->skgen_subdivision_number;
+       
+       /* < and not <= because we don't care about end, it is P_EXACT anyway */
+       for (i = start + 1; i < end; i++)
+       {
+               current_length += VecLenf(stk->points[i].p, stk->points[i - 1].p);
+
+               if (current_length >= length_threshold)
+               {
+                       VECCOPY(p, stk->points[i].p);
+                       return i;
+               }
+       }
+       
+       stroke_length = 0;
+       
+       return -1;
+}
+int nextCorrelationSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3])
+{
+       float correlation_threshold = G.scene->toolsettings->skgen_correlation_limit;
+       float n[3];
+       int i;
+       
+       for (i = start + 2; i <= end; i++)
+       {
+               /* Calculate normal */
+               VecSubf(n, stk->points[i].p, head);
+
+               if (calcStrokeCorrelation(stk, start, i, stk->points[start].p, n) < correlation_threshold)
+               {
+                       VECCOPY(p, stk->points[i - 1].p);
+                       return i - 1;
+               }
+       }
+       
+       return -1;
+}
+
+int nextLengthSubdivision(SK_Stroke *stk, int start, int end, float head[3], float p[3])
+{
+       float lengthLimit = G.scene->toolsettings->skgen_length_limit;
+       int same = 1;
+       int i;
+       
+       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, 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, 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(p, dv);
+                                       VecMulf(p, f);
+                                       VecAddf(p, p, vec0);
+                               }
+                               else
+                               {
+                                       VECCOPY(p, vec1);
+                               }
+                       }
+                       else
+                       {
+                               float dv[3];
+                               
+                               VecSubf(dv, vec1, vec0);
+                               Normalize(dv);
+                                
+                               VECCOPY(p, dv);
+                               VecMulf(p, lengthLimit);
+                               VecAddf(p, p, head);
+                       }
+                       
+                       return i - 1; /* restart at lower bound */
+               }
+               else
+               {
+                       i++;
+                       same = 0; // Reset same
+               }
+       }
+       
+       return -1;
+}
+
+EditBone * subdivideStrokeBy(SK_Stroke *stk, int start, int end, float invmat[][4], float tmat[][3], NextSubdivisionFunc next_subdividion)
+{
+       bArmature *arm = G.obedit->data;
+       EditBone *lastBone = NULL;
+       EditBone *child = NULL;
+       EditBone *parent = NULL;
+       int bone_start = start;
+       int index;
+       
+       parent = addEditBone("Bone", &G.edbo, arm);
+       VECCOPY(parent->head, stk->points[start].p);
+       
+       index = next_subdividion(stk, bone_start, end, parent->head, parent->tail);
+       while (index != -1)
+       {
+               setBoneRollFromPoint(parent, &stk->points[index], invmat, tmat);
+
+               child = addEditBone("Bone", &G.edbo, arm);
+               VECCOPY(child->head, parent->tail);
+               child->parent = parent;
+               child->flag |= BONE_CONNECTED;
+               
+               /* going to next bone, fix parent */
+               Mat4MulVecfl(invmat, parent->tail);
+               Mat4MulVecfl(invmat, parent->head);
+
+               parent = child; // new child is next parent
+               bone_start = index; // start next bone from current index
+
+               index = next_subdividion(stk, bone_start, end, parent->head, parent->tail);
+       }
+
+       VECCOPY(parent->tail, stk->points[end].p);
+
+       setBoneRollFromPoint(parent, &stk->points[end], invmat, tmat);
+
+       /* fix last bone */
+       Mat4MulVecfl(invmat, parent->tail);
+       Mat4MulVecfl(invmat, parent->head);
+       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 */
+       float tmat[3][3];
+       int head_index = 0;
+       int i;
+       
+       head = NULL;
+       
+       Mat4Invert(invmat, G.obedit->obmat);
+       
+       Mat3CpyMat4(tmat, G.obedit->obmat);
+       Mat3Transp(tmat);
+       
+       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)
+                               {
+                                       if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_CORRELATION)
+                                       {
+                                               bone = subdivideStrokeBy(stk, head_index, i, invmat, tmat, nextCorrelationSubdivision);
+                                       }
+                                       else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_LENGTH)
+                                       {
+                                               bone = subdivideStrokeBy(stk, head_index, i, invmat, tmat, nextLengthSubdivision);
+                                       }
+                                       else if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_CUT_FIXED)
+                                       {
+                                               bone = subdivideStrokeBy(stk, head_index, i, invmat, tmat, nextFixedSubdivision);
+                                       }
+                               }
+                               
+                               if (bone == NULL)
+                               {
+                                       bone = addEditBone("Bone", &G.edbo, arm);
+                                       
+                                       VECCOPY(bone->head, head->p);
+                                       VECCOPY(bone->tail, pt->p);
+                                       setBoneRollFromPoint(bone, pt, invmat, tmat);
+                                       
+                                       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)
+               {
+                       if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET)
+                       {
+                               sk_retargetStroke(stk);
+                       }
+                       else
+                       {
+                               sk_convertStroke(stk);
+                       }
+                       allqueue(REDRAWBUTSEDIT, 0);
+               }
+       }
+}
+/******************* 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->gesture_index = g_i;
+                               isect->before = s_i;
+                               isect->after = s_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->gesture_index = g_i;
+                                       isect->before = s_i;
+                                       isect->after = 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.99f;
+       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->after);
+       }
+}
+
+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->after].p, isect->stroke->points[isect->before].p);
+               
+               /* same direction, trim end */
+               if (Inpf(stroke_dir, trim_dir) > 0)
+               {
+                       sk_replaceStrokePoint(isect->stroke, &pt, isect->after);
+                       sk_trimStroke(isect->stroke, 0, isect->after);
+               }
+               /* else, trim start */
+               else
+               {
+                       sk_replaceStrokePoint(isect->stroke, &pt, isect->before);
+                       sk_trimStroke(isect->stroke, isect->before, 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;
+                       
+                       sk_removeStroke(sketch, 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->after, isect->next->after);
+                               end_index = MAX2(isect->before, isect->next->before);
+
+                               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 merge strokes that are crossed twice */
+               if (isect->next && isect->next->stroke == isect->stroke)
+               {
+                       int start_index, end_index;
+                       int i;
+                       
+                       start_index = MIN2(isect->after, isect->next->after);
+                       end_index = MAX2(isect->before, isect->next->before);
+
+                       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;
+               }
+       }
+}
+
+int sk_detectReverseGesture(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)
+               {
+                       float start_v[3], end_v[3];
+                       float angle;
+                       
+                       if (isect->gesture_index < isect->next->gesture_index)
+                       {
+                               VecSubf(start_v, isect->p, gesture->points[0].p);
+                               VecSubf(end_v, sk_lastStrokePoint(gesture)->p, isect->next->p);
+                       }
+                       else
+                       {
+                               VecSubf(start_v, isect->next->p, gesture->points[0].p);
+                               VecSubf(end_v, sk_lastStrokePoint(gesture)->p, isect->p);
+                       }
+                       
+                       angle = VecAngle2(start_v, end_v);
+                       
+                       if (angle > 120)
+                       {
+                               return 1;
+                       }
+
+                       /* skip next */                         
+                       isect = isect->next;
+               }
+       }
+               
+       return 0;
+}
+
+void sk_applyReverseGesture(SK_Sketch *sketch, SK_Stroke *gesture, ListBase *list, SK_Stroke *segments)
+{
+       SK_Intersection *isect;
+       
+       for (isect = list->first; isect; isect = isect->next)
+       {
+               /* only reverse strokes that are crossed twice */
+               if (isect->next && isect->next->stroke == isect->stroke)
+               {
+                       sk_reverseStroke(isect->stroke);
+
+                       /* 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_intersections == 2 && sk_detectReverseGesture(sketch, sketch->gesture, &intersections, segments))
+       {
+               sk_applyReverseGesture(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);
+       }
+       else if (nb_segments > 2 && nb_self_intersections == 2)
+       {
+               sk_deleteSelectedStrokes(sketch);
+       }
+       
+       sk_freeStroke(segments);
+       BLI_freelistN(&intersections);
+       BLI_freelistN(&self_intersections);
+}
+
+/********************************************/
+
+void sk_deleteSelectedStrokes(SK_Sketch *sketch)
+{
+       SK_Stroke *stk, *next;
+       
+       for (stk = sketch->strokes.first; stk; stk = next)
+       {
+               next = stk->next;
+               
+               if (stk->selected == 1)
+               {
+                       sk_removeStroke(sketch, 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));
+               
+                       if (stk->selected == 1)
+                       {
+                               sk_drawStrokeSubdivision(stk);
+                       }
+               }
+       
+               /* 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 (G.scene->toolsettings->bone_sketching & BONE_SKETCHING_QUICK)
+                       {
+                               sk_drawStrokeSubdivision(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_Stroke *stk = sketch->active_stroke;
+                       
+                       sk_endStroke(sketch);
+                       
+                       if (G.scene->toolsettings->bone_sketching & BONE_SKETCHING_QUICK)
+                       {
+                               if (G.scene->toolsettings->bone_sketching_convert == SK_CONVERT_RETARGET)
+                               {
+                                       sk_retargetStroke(stk);
+                               }
+                               else
+                               {
+                                       sk_convertStroke(stk);
+                               }
+                               BIF_undo_push("Convert Sketch");
+                               sk_removeStroke(sketch, stk);
+                               allqueue(REDRAWBUTSEDIT, 0);
+                       }
+                       
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+               /* no gestures in quick mode */
+               else if (G.scene->toolsettings->bone_sketching & BONE_SKETCHING_QUICK)
+               {
+                       retval = 0; /* return zero for default click behavior */
+               }
+               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_cancelStrokeSketch()
+{
+       if (BIF_validSketchMode())
+       {
+               if (GLOBAL_sketch != NULL)
+               {
+                       sk_cancelStroke(GLOBAL_sketch);
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+       }
+}
+
+void BIF_deleteSketch()
+{
+       if (BIF_validSketchMode())
+       {
+               if (GLOBAL_sketch != NULL)
+               {
+                       sk_deleteSelectedStrokes(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;
+       }
+}
+
+int BIF_fullSketchMode()
+{
+       if (G.obedit && 
+               G.obedit->type == OB_ARMATURE && 
+               G.scene->toolsettings->bone_sketching & BONE_SKETCHING && 
+               (G.scene->toolsettings->bone_sketching & BONE_SKETCHING_QUICK) == 0)
+       {
+               return 1;
+       }
+       else
+       {
+               return 0;
+       }
+}
index fd8bd7dc014ac7c9bf7cd181e6f3c7fea1916e3f..f4cfc0c0dd6b1acbeb5f6f1f5d3d470337d11930 100644 (file)
@@ -939,7 +939,7 @@ static void gp_stroke_to_bonechain (bGPDlayer *gpl, bGPDstroke *gps, bArmature *
                /* add new bone - note: sync with editarmature.c::add_editbone() */
                {
                        BLI_strncpy(ebo->name, "Stroke", 32);
-                       unique_editbone_name(bones, ebo->name);
+                       unique_editbone_name(bones, ebo->name, NULL);
                        
                        BLI_addtail(bones, ebo);
                        
index e2caf97df051342d8224b01d6a7e38a08a8c7dad..b51c3e620e5315223c78446473c2f25f7862144c 100644 (file)
@@ -3978,6 +3978,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);
@@ -4055,6 +4058,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 b6221c2f84b5926138c62db0b51b681836bb3fb7..ede33374ac8908c1ccc0c76afd22ee62ef3bf593 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 */
 
@@ -1259,11 +1261,13 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                        return; /* return if event was processed (swallowed) by handler(s) */
                        }
 #endif
+                       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 */
@@ -1306,6 +1310,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                        }
                                }
                        }
+                       
+                       BDR_queueDrawSketch();
 
                        /* Handle retopo painting */
                        if(retopo_mesh_paint_check()) {
@@ -1908,7 +1914,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 (BIF_fullSketchMode())
+                                                       {
+                                                               BIF_selectAllSketch(1);
+                                                       }
+                                                       else
+                                                       {
+                                                               deselectall_armature(1, 1);     /* 1 == toggle */
+                                                       }
+                                               }
                                        }
                                        else if (ob && (ob->flag & OB_POSEMODE)){
                                                deselectall_posearmature(ob, 1, 1);
@@ -1976,6 +1991,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_fullSketchMode())
+                                       {
+                                               BIF_convertSketch();
+                                       }
                                        else
                                                convertmenu();  /* editobject.c */
                                }
@@ -2497,8 +2516,11 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                        
                                        else if(G.qual==LR_ALTKEY && G.obedit->type==OB_ARMATURE)
                                                clear_bone_parent();
-                                       else if((G.qual==0) && (G.obedit->type==OB_ARMATURE)) 
-                                               armature_select_hierarchy(BONE_SELECT_PARENT, 1); // 1 = add to selection
+                                       else if((G.qual==0) && (G.obedit->type==OB_ARMATURE))
+                                       { 
+                                               toggle_blockhandler(curarea, VIEW3D_HANDLER_BONESKETCH, UI_PNL_TO_MOUSE);
+                                               allqueue(REDRAWVIEW3D, 0);
+                                       }
                                        else if((G.qual==(LR_CTRLKEY|LR_ALTKEY)) && (G.obedit->type==OB_ARMATURE))
                                                separate_armature();
                                        else if((G.qual==0) && G.obedit->type==OB_MESH)
@@ -2783,7 +2805,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:
@@ -2945,7 +2967,11 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                break;
 
                        case ESCKEY:
-                               if(G.qual==0) {
+                               if (G.qual == 0 && BIF_validSketchMode())
+                               {
+                                       BIF_cancelStrokeSketch();
+                               }
+                               else if(G.qual==0) {
                                        if (G.vd->flag & V3D_DISPIMAGE) {
                                                G.vd->flag &= ~V3D_DISPIMAGE;
                                                doredraw= 1;
index 16c26336b895427237eb5438d731005ffcf490e4..7ebdc3a11cda6676eb9ebd00df599002e425d7fa 100644 (file)
@@ -1103,6 +1103,7 @@ void exit_usiblender(void)
        
        BIF_GlobalReebFree();
        BIF_freeRetarget();
+       BIF_freeTemplates();
        
        tf= G.ttfdata.first;
        while(tf)
index 258e4fd99e08cadf84a339d0ae513d90ed4e64d2..0908a75c6a3dc4c12c80d24f9d5888fa916529e7 100644 (file)
@@ -75,6 +75,7 @@
 #include "BIF_space.h"
 #include "BIF_screen.h"
 #include "BIF_toolbox.h"
+#include "BIF_sketch.h"
 
 #include "BSE_view.h"
 #include "BSE_edit.h"          /* For countall */
@@ -83,6 +84,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"
@@ -1879,7 +1881,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 (BIF_fullSketchMode())
+               {
+                       BDR_drawSketchNames();
+               }
+               else
+               {
+                       draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
+               }
        }
        else {
                Base *base;