Added method to remove vertices from basic meshes by remapping the v/e/l/p custom...
[blender.git] / source / blender / editors / sculpt_paint / sculpt.c
index 29ee294258abe1aea5d3cd557f9978b45ec1e636..8f2d0242ea0112bafa524d7b9ff148d892ec01dc 100644 (file)
 #include "BLI_alloca.h"
 #include "BLI_array.h"
 
+#define SIL_STROKE_STORE_CHUNK 512
+/* Store bias is used to bias a close estimate since resizing is more expensive than bigger array on first allocate*/
+#define STORE_ESTIMATE_BIAS 0.1f
+/* Fillet Blur determines the fuzziness wether a vert is intersecting or not.
+ * Important for example if two shapes with the same thickness intersect. */
+#define SIL_FILLET_BLUR_MAX 0.3f
+#define SIL_FILLET_BLUR_MIN 0.001f
+
 #define DEBUG_DRAW
 #ifdef DEBUG_DRAW
-// static void bl_debug_draw(void);
+/* static void bl_debug_draw(void);*/
 /* add these locally when using these functions for testing */
 extern void bl_debug_draw_quad_clear(void);
 extern void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3]);
 extern void bl_debug_draw_edge_add(const float v0[3], const float v1[3]);
 extern void bl_debug_color_set(const unsigned int col);
 
+static void bl_debug_draw_medge_add(Mesh *me, int e){
+       bl_debug_draw_edge_add(me->mvert[me->medge[e].v1].co, me->mvert[me->medge[e].v2].co);
+}
+
 static void bl_debug_draw_point(const float pos[3],const float thickness)
 {
        float h = thickness*0.5;
@@ -138,6 +150,117 @@ static void bl_debug_draw_point(const float pos[3],const float thickness)
 }
 #endif
 
+typedef struct {
+       float bmin[3], bmax[3];
+} BB;
+
+/*     init data:
+ *     Silhouette Data */
+typedef struct SilhouetteStroke {
+       float *points;
+       float *points_v2;
+       int totvert;
+       int max_verts;
+       BB bb;
+} SilhouetteStroke;
+
+#ifdef DEBUG_DRAW
+void bl_debug_draw_BB_add(BB *bb,const unsigned int col){
+       float v1[3],v2[3],v3[3],v4[3];
+       float xd[3], yd[3], zd[3];
+
+       bl_debug_color_set(col);
+
+       xd[0] = bb->bmax[0]-bb->bmin[0];
+       xd[1] = 0.0f;
+       xd[2] = 0.0f;
+
+       yd[0] = 0.0f;
+       yd[1] = bb->bmax[1]-bb->bmin[1];
+       yd[2] = 0.0f;
+
+       zd[0] = 0.0f;
+       zd[1] = 0.0f;
+       zd[2] = bb->bmax[2]-bb->bmin[2];
+
+       copy_v3_v3(v1,bb->bmin);
+       copy_v3_v3(v2,bb->bmin);
+       add_v3_v3(v2,xd);
+       add_v3_v3v3(v3,v1,yd);
+       add_v3_v3v3(v4,v2,yd);
+
+       bl_debug_draw_edge_add(v1,v2);
+       bl_debug_draw_edge_add(v1,v3);
+       bl_debug_draw_edge_add(v2,v4);
+
+       copy_v3_v3(v1,v3);
+       copy_v3_v3(v2,v4);
+       add_v3_v3v3(v3,v1,zd);
+       add_v3_v3v3(v4,v2,zd);
+
+       bl_debug_draw_edge_add(v1,v2);
+       bl_debug_draw_edge_add(v1,v3);
+       bl_debug_draw_edge_add(v2,v4);
+
+       copy_v3_v3(v1,v3);
+       copy_v3_v3(v2,v4);
+       sub_v3_v3v3(v3,v1,yd);
+       sub_v3_v3v3(v4,v2,yd);
+
+       bl_debug_draw_edge_add(v1,v2);
+       bl_debug_draw_edge_add(v1,v3);
+       bl_debug_draw_edge_add(v2,v4);
+
+       copy_v3_v3(v1,v3);
+       copy_v3_v3(v2,v4);
+       sub_v3_v3v3(v3,v1,zd);
+       sub_v3_v3v3(v4,v2,zd);
+
+       bl_debug_draw_edge_add(v1,v2);
+       bl_debug_draw_edge_add(v1,v3);
+       bl_debug_draw_edge_add(v2,v4);
+       
+}
+#endif
+
+
+typedef enum {
+       SIL_INIT = 0,
+       SIL_DRAWING = 1,
+       SIL_OP = 2
+} SilhouetteState;
+
+typedef struct SilhouetteData {
+       ARegion *ar;            /* region that Silhouette started drawn in */
+       void *draw_handle;      /* for drawing preview loop */
+       ViewContext vc;
+       SilhouetteStroke *current_stroke;
+       Object *ob;
+       BMEditMesh *em;                 /*Triangulated stroke for spine generation*/
+       Scene *scene;
+
+       float add_col[3];               /* preview color */
+       float last_mouse_pos[2];
+
+       SilhouetteState state;  /* Operator state */
+
+       float depth;                                    /* Depth or thickness of the generated shape */
+       float smoothness;                               /* Smoothness of the generated shape */
+       int resolution;                                 /* Subdivision of the shape*/
+       float anchor[3];                                /* Origin point of the reference plane */
+       float z_vec[3];                                 /* Orientation of the reference plane */
+       MeshElemMap *emap;                              /* Original Mesh vert -> edges map */
+       GHash *i_edges;                                 /* Edges crossing the both shapes. (only orig mesh)*/
+       int *fillet_ring_orig;                  /* ring_edges to connect to in the orig mesh */
+       int *fillet_ring_orig_start;    /* start positions to each individual ring */
+       int *fillet_ring_new;                   /* ring_edges to connect to in the new mesh */
+       int *fillet_ring_new_start;             /* start positions to each individual ring */
+       int num_rings, fillet_ring_tot;
+       int *inter_edges;                               /* edges crossing the two shapes */
+       int num_inter_edges;                    /* number of edges crossing */
+       BB *fillet_ring_bbs;                            /* every ring gets a Bounding box to check intersection with branches */
+} SilhouetteData;
+
 /** \name Tool Capabilities
  *
  * Avoid duplicate checks, internal logic only,
@@ -544,6 +667,9 @@ typedef struct SculptThreadedTaskData {
        float strength;
        bool smooth_mask;
        bool has_bm_orco;
+       SilhouetteData *sil;
+       int *v_to_rm; /* Shared array handle access with mutex! */
+       int num_v_to_rm;
 
        SculptProjectVector *spvc;
        float *offset;
@@ -4745,8 +4871,11 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
                                     const float mouse[2])
 {
        /* Don't start the stroke until mouse goes over the mesh.
-        * note: mouse will only be null when re-executing the saved stroke. */
-       if (!mouse || over_mesh(C, op, mouse[0], mouse[1])) {
+        * note: mouse will only be null when re-executing the saved stroke.
+        * We have exception for 'exec' strokes since they may not set 'mouse', only 'location', see: T52195. */
+       if (((op->flag & OP_IS_INVOKE) == 0) ||
+           (mouse == NULL) || over_mesh(C, op, mouse[0], mouse[1]))
+       {
                Object *ob = CTX_data_active_object(C);
                SculptSession *ss = ob->sculpt;
                Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -5020,39 +5149,36 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
 
 /****************** Topology tools Silhouette ******************/
 
-/*     init data:
- *     Silhouette Data */
-typedef struct SilhouetteStroke {
-       float *points;
-       int totvert;
-       int max_verts;
-}SilhouetteStroke;
+/* Axis-aligned bounding box (Same as in pbvh_intern.h)*/
 
-typedef enum {
-       SIL_INIT = 0,
-       SIL_DRAWING = 1,
-       SIL_OP = 2
-} SilhouetteState;
+/* TODO: import BB functions */
+/* Expand the bounding box to include a new coordinate */
+static void BB_expand(BB *bb, const float co[3])
+{
+       for (int i = 0; i < 3; ++i) {
+               bb->bmin[i] = min_ff(bb->bmin[i], co[i]);
+               bb->bmax[i] = max_ff(bb->bmax[i], co[i]);
+       }
+}
 
-typedef struct SilhouetteData {
-       ARegion *ar;            /* region that Silhouette started drawn in */
-       void *draw_handle;      /* for drawing preview loop */
-       ViewContext vc;
-       SilhouetteStroke *current_stroke;
-       Object *ob;
-       BMEditMesh *em;                 /*Triangulated stroke for spine generation*/
-       Scene *scene;
+static void BB_reset(BB *bb)
+{
+       bb->bmin[0] = bb->bmin[1] = bb->bmin[2] = FLT_MAX;
+       bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX;
+}
 
-       float add_col[3];               /* preview color */
-       float last_mouse_pos[2];
+static bool bb_intersect(BB *bb1, BB *bb2) {
+       int i;
 
-       SilhouetteState state;  /* Operator state */
+       /* min is inclusive max is exclusive? BB*/
+       for (i = 0; i < 3; ++i) {
+               if(bb1->bmin[i] >= bb2->bmax[i] || bb1->bmax[i] < bb2->bmin[i]){
+                       return false;
+               }
+       }
 
-       float depth;                    /* Depth or thickness of the generated shape */
-       float smoothness;               /* Smoothness of the generated shape */
-       float anchor[3];                /* Origin point of the reference plane */
-       float z_vec[3];                 /* Orientation of the reference plane */
-} SilhouetteData;
+       return true;
+}
 
 static void silhouette_stroke_free(SilhouetteStroke *stroke)
 {
@@ -5064,23 +5190,28 @@ static void silhouette_stroke_free(SilhouetteStroke *stroke)
        }
 }
 
-static SilhouetteStroke *silhouette_stroke_new(int max_verts)
+static SilhouetteStroke *silhouette_stroke_new()
 {
        SilhouetteStroke *stroke = MEM_callocN(sizeof(SilhouetteStroke), "SilhouetteStroke");
-       stroke->points = 0;
-       stroke->points = MEM_callocN(sizeof(float) * 3 * max_verts,"SilhouetteStrokePoints");/* TODO: Dynamic length */
+       stroke->points = MEM_callocN(sizeof(float) * 3 * SIL_STROKE_STORE_CHUNK,"SilhouetteStrokePoints");
+       stroke->points_v2 = MEM_callocN(sizeof(float) * 2 * SIL_STROKE_STORE_CHUNK,"SilhouetteStrokePoints");
        stroke->totvert = 0;
-       stroke->max_verts = max_verts;
+       stroke->max_verts = SIL_STROKE_STORE_CHUNK;
+       BB_reset(&stroke->bb);
        return stroke;
 }
 
-static SilhouetteData *silhouette_data_new(bContext *C, wmOperator *op, bool rna_full)
+static SilhouetteData *silhouette_data_new(bContext *C)
 {
        SilhouetteData *sil = MEM_callocN(sizeof(SilhouetteData), "SilhouetteData");
        Object *obedit = CTX_data_edit_object(C);
        Scene *scene = CTX_data_scene(C);
+       Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+       View3D *v3d = CTX_wm_view3d(C);
+       const float *fp = ED_view3d_cursor3d_get(scene, v3d);
+
        sil->ar = CTX_wm_region(C);
-       sil->current_stroke = silhouette_stroke_new(1024);
+       sil->current_stroke = silhouette_stroke_new();
        view3d_set_viewcontext(C, &sil->vc);
 
        sil->add_col[0] = 1.00; /* add mode color is light red */
@@ -5088,14 +5219,19 @@ static SilhouetteData *silhouette_data_new(bContext *C, wmOperator *op, bool rna
        sil->add_col[2] = 0.39;
 
        /*Load RNA Data if present */
-       sil->smoothness = RNA_float_get(op->ptr, "smoothness");
-       sil->depth = RNA_float_get(op->ptr, "depth");
-       if (rna_full) {
-               RNA_float_get_array(op->ptr, "z_vec", sil->z_vec);
-               RNA_float_get_array(op->ptr, "anchor", sil->anchor);
-               RNA_float_get_array(op->ptr, "points", sil->current_stroke->points);
-               sil->current_stroke->totvert = RNA_int_get(op->ptr, "totvert");
-       }
+       sil->smoothness = sd->silhouette_smoothness / 100.0f;
+       sil->depth = sd->silhouette_depth;
+       sil->resolution = sd->silhouette_resolution;
+
+       copy_v3_v3(sil->anchor, fp);
+
+       /* Intersection variables */
+       sil->fillet_ring_orig = NULL;
+       sil->fillet_ring_orig_start = NULL;
+       sil->fillet_ring_new = NULL;
+       sil->fillet_ring_new_start = NULL;
+       sil->inter_edges = NULL;
+       sil->fillet_ring_bbs = NULL;
 
        sil->scene = scene;
        sil->ob = obedit;
@@ -5109,6 +5245,25 @@ static void silhouette_data_free(struct wmOperator *op)
        data = op->customdata;
        if (data) {
                silhouette_stroke_free(data->current_stroke);
+
+               if (data->inter_edges) {
+                       MEM_freeN(data->inter_edges);
+               }
+               if (data->fillet_ring_orig) {
+                       MEM_freeN(data->fillet_ring_orig);
+               }
+               if (data->fillet_ring_orig_start) {
+                       MEM_freeN(data->fillet_ring_orig_start);
+               }
+               if (data->fillet_ring_new) {
+                       MEM_freeN(data->fillet_ring_new);
+               }
+               if (data->fillet_ring_new_start) {
+                       MEM_freeN(data->fillet_ring_new_start);
+               }
+               if (data->fillet_ring_bbs) {
+                       MEM_freeN(data->fillet_ring_bbs);
+               }
                MEM_SAFE_FREE(data);
        }
 }
@@ -5119,46 +5274,55 @@ static void silhoute_stroke_point_to_3d(SilhouetteData *sil, int point, float r_
        /*ED_view3d_win_to_3d(sil->vc.v3d, sil->ar, sil->anchor, &sil->current_stroke->points[point], r_v);*/
 }
 
+#if 0
 /* TODO: Add dynamic memory allocation */
 static void silhouette_stroke_add_3Dpoint(SilhouetteStroke *stroke, float point[3])
 {
-       if (stroke->totvert < stroke->max_verts) {
-               copy_v3_v3(&stroke->points[stroke->totvert * 3], point);
-               stroke->totvert ++;
-       } else {
-               printf("Stroke reached maximum vert count.\n");
+       if (stroke->totvert >= stroke->max_verts) {
+               stroke->max_verts += SIL_STROKE_STORE_CHUNK;
+               stroke->points = MEM_reallocN(stroke->points, sizeof(float) * 3 * stroke->max_verts);
+               stroke->points_v2 = MEM_reallocN(stroke->points_v2, sizeof(float) * 2 * stroke->max_verts);
        }
+
+       copy_v3_v3(&stroke->points[stroke->totvert * 3], point);
+       stroke->totvert ++;
 }
+#endif
 
 static void silhouette_stroke_add_point(SilhouetteData *sil, SilhouetteStroke *stroke, float point[2])
 {
-       if (stroke->totvert < stroke->max_verts) {
-               ED_view3d_win_to_3d(sil->vc.v3d, sil->ar, sil->anchor, point, &sil->current_stroke->points[stroke->totvert * 3]);
-               stroke->totvert ++;
-       } else {
-               printf("Stroke reached maximum vert count.\n");
+       if (stroke->totvert >= stroke->max_verts) {
+               stroke->max_verts += SIL_STROKE_STORE_CHUNK;
+               stroke->points = MEM_reallocN(stroke->points, sizeof(float) * 3 * stroke->max_verts);
+               stroke->points_v2 = MEM_reallocN(stroke->points_v2, sizeof(float) * 2 * stroke->max_verts);
        }
+
+       copy_v2_v2(&stroke->points_v2[stroke->totvert * 2], point);
+       ED_view3d_win_to_3d(sil->vc.v3d, sil->ar, sil->anchor, point, &sil->current_stroke->points[stroke->totvert * 3]);
+       BB_expand(&stroke->bb, &sil->current_stroke->points[stroke->totvert * 3]);
+       stroke->totvert ++;
 }
 
 /* Set reference plane, 3D plane which is drawn on in 2D */
-static void silhouette_set_ref_plane(const bContext *C, SilhouetteData *sil)
+static void silhouette_set_ref_plane(SilhouetteData *sil)
 {
-       Scene *scene = CTX_data_scene(C);
-       View3D *v3d = CTX_wm_view3d(C);
-       const float *fp = ED_view3d_cursor3d_get(scene, v3d);
-
-       ED_view3d_global_to_vector(sil->ar->regiondata, (float[3]){0.0f,0.0f,0.0f}, sil->z_vec);
-       copy_v3_v3(sil->anchor, fp);
+       /*Get the view vector. Same as ED_view3d_global_to_vector from the center of screen or orthographic*/
+       negate_v3_v3(sil->z_vec, sil->vc.rv3d->viewinv[2]);
+       normalize_v3(sil->z_vec);
+       /*ED_view3d_global_to_vector(sil->ar->regiondata, sil->anchor, sil->z_vec);*/
 }
 
-static void sculpt_silhouette_stroke_update(bContext *C, float mouse[2], SilhouetteData *sil)
+static void sculpt_silhouette_stroke_update(float mouse[2], SilhouetteData *sil)
 {
-       silhouette_set_ref_plane( C, sil);
+       float anchor[3];
+       silhouette_set_ref_plane(sil);
        SilhouetteStroke *stroke = sil->current_stroke;
 
        sil->last_mouse_pos[0] = mouse[0];
        sil->last_mouse_pos[1] = mouse[1];
        silhouette_stroke_add_point(sil, stroke, sil->last_mouse_pos);
+       interp_v3_v3v3(anchor, sil->anchor, &stroke->points[stroke->totvert * 3 - 3], 1 / stroke->totvert);
+       copy_v3_v3(sil->anchor, anchor);
        ED_region_tag_redraw(sil->ar);
        copy_v2_v2(sil->last_mouse_pos,mouse);
 }
@@ -5189,6 +5353,9 @@ typedef struct SpineBranch{
        int *terminal_points;   /* Description of the connected branches. Per fork 2 ints (point,branch_idx) */
        BranchState flag;
        int *e_start_arr;               /* Edges on the ends are stored (used primarly for bridging) */
+       int fs_bs_offset;               /* Frontside edge offset to backside*/
+       int *e_flip_side_ends;  /* Front and backside connecting edges of each part*/
+       bool intersecting;
 }SpineBranch;
 
 /* Main Tree Container */
@@ -5197,6 +5364,31 @@ typedef struct Spine{
        SpineBranch **branches; /* All branches. Can contain Null pointers if branches got removed*/
 }Spine;
 
+typedef struct {
+       SculptSession *ss;
+       BB *bb_target;
+       bool original;
+} SculptSearchBBData;
+
+/* Search nodes to integrate another BB into (used for silhouette)*/
+static bool sculpt_search_BB_cb(PBVHNode *node, void *data_v)
+{
+       SculptSearchBBData *data = data_v;
+       BB *bb_target = data->bb_target;
+       float bb_min[3], bb_max[3];
+       int i;
+
+       BKE_pbvh_node_get_BB(node, bb_min, bb_max);
+
+       /* min is inclusive max is exclusive? BB*/
+       for (i = 0; i < 3; ++i) {
+               if(bb_target->bmin[i] >= bb_max[i] || bb_target->bmax[i] < bb_min[i]){
+                       return false;
+               }
+       }
+       return true;
+}
+
 static int get_adjacent_faces(BMFace *f, BMFace **ad_f, BMFace *last_f)
 {
        int ad_faces = 0;
@@ -5289,6 +5481,7 @@ static void free_spine_branch(SpineBranch *branch)
        }
        if (branch->flag & BRANCH_EDGE_GEN) {
                MEM_freeN(branch->e_start_arr);
+               MEM_freeN(branch->e_flip_side_ends);
        }
        MEM_freeN(branch);
 }
@@ -5340,7 +5533,7 @@ static SpineBranch *new_spine_branch(int idx, int max_alloc, int hull_max)
        /*TODO: way to big, maybe shrink if done creating or dynamic arrays?*/
        branch->points = MEM_callocN(sizeof(float) * 3 * max_alloc, __func__);
        branch->hull_points = MEM_callocN(sizeof(int) * hull_max * 2 * 3, "Spine Hull");
-       branch->terminal_points = MEM_callocN(sizeof(int) * hull_max * 2, "Spine terminal");
+       branch->terminal_points = MEM_callocN(sizeof(int) * 3 * 2, "Spine terminal");
 
        branch->idx = idx;
        return branch;
@@ -5370,7 +5563,7 @@ static SpineBranch *spine_branchoff(Spine *spine, SpineBranch *current_branch, i
        SpineBranch *new_branch = new_spine_branch(spine->totbranches, max_alloc, hull_max);
        spine->branches[spine->totbranches] = new_branch;
 
-       current_branch->terminal_points[current_branch->totforks * 2    ] = current_branch->totpoints;
+       current_branch->terminal_points[current_branch->totforks * 2    ] = current_branch->totpoints - 1;
        current_branch->terminal_points[current_branch->totforks * 2 + 1] = spine->totbranches;
 
        copy_v3_v3(&new_branch->points[0], &current_branch->points[current_branch->totpoints * 3 - 3]);
@@ -5542,32 +5735,36 @@ static Spine *silhouette_generate_spine(SilhouetteData *sil, SilhouetteStroke *s
  * Interpolate between the three points resulting in a vertex line between a and c.
  * Smoothness regulates the cutoff to start a circular interpolation
  */
-static void calc_vert_quarter(Mesh *me, float a[3], float b[3], float c[3], int v_steps, int w_h_steps, float smoothness, bool flip){
+static void calc_vert_quarter(Mesh *me, float a[3], float b[3], float c[3], int v_steps, int w_h_steps, float smoothness, bool flip, bool flip_side){
        int v_start = me->totvert;
-       int v_pos = flip ? v_start + v_steps + w_h_steps - 1 : v_start;
+       int v_pos = flip ? v_start + v_steps + w_h_steps - 1 - (flip_side ? 1 : 0): v_start;
        float inv_smooth = 1.0f - smoothness;
        float v1[3], v2[3], v3[3], v4[3], v5[3], up[3], side[3], d[3];
        float f_sin, f_cos;
-       int s_steps_w = inv_smooth * (w_h_steps + 1);
-       int s_steps_v = inv_smooth * v_steps;
+       int s_steps_w = inv_smooth * w_h_steps;
+       int s_steps_v = fmax(1, inv_smooth * v_steps);
        int s_steps_c = v_steps - s_steps_v + w_h_steps - s_steps_w;
 
-       ED_mesh_vertices_add(me, NULL, v_steps + w_h_steps);
+       ED_mesh_vertices_add(me, NULL, v_steps + w_h_steps - (flip_side ? 1 : 0));
 
        sub_v3_v3v3(up, c, b);
        add_v3_v3v3(d, a, up);
        mul_v3_fl(up, 1.0f / (float)v_steps);
        sub_v3_v3v3(side, a, b);
-       mul_v3_fl(side, 1.0f / (float)(w_h_steps + 1));
+       if (w_h_steps > 0) {
+               mul_v3_fl(side, 1.0f / (float)(w_h_steps));
+       }
        mul_v3_v3fl(v2, side, s_steps_w);
        add_v3_v3(v2, c);
 
        copy_v3_v3(v1, a);
        for (int v = 0; v < s_steps_v; v++) {
-               copy_v3_v3(me->mvert[v_pos].co, v1);
-               me->mvert[v_pos].flag = 0;
-               me->mvert[v_pos].bweight = 0;
-               v_pos += flip ? - 1 : 1;
+               if (!flip_side || v > 0) {
+                       copy_v3_v3(me->mvert[v_pos].co, v1);
+                       me->mvert[v_pos].flag = 0;
+                       me->mvert[v_pos].bweight = 0;
+                       v_pos += flip ? - 1 : 1;
+               }
                if (v < s_steps_v - 1) {
                        add_v3_v3(v1, up);
                }
@@ -5603,15 +5800,15 @@ static void calc_vert_quarter(Mesh *me, float a[3], float b[3], float c[3], int
 }
 
 /* W_steps needs to be uneven! */
-static void calc_vert_half(Mesh *me, float left[3], float right[3], float center[3], float upper_center[3], int v_steps, int w_steps, float smoothness)
+static void calc_vert_half(Mesh *me, float left[3], float right[3], float center[3], float upper_center[3], int v_steps, int w_steps, float smoothness, bool flip_side)
 {
        int half_w = w_steps / 2;
-       calc_vert_quarter(me, left, center, upper_center, v_steps, half_w, smoothness, false);
+       calc_vert_quarter(me, left, center, upper_center, v_steps, half_w, smoothness, false, flip_side);
        ED_mesh_vertices_add(me, NULL, 1);
        copy_v3_v3(me->mvert[me->totvert - 1].co, upper_center);
        me->mvert[me->totvert - 1].flag = 0;
        me->mvert[me->totvert - 1].bweight = 0;
-       calc_vert_quarter(me, right, center, upper_center, v_steps, half_w, smoothness, true);
+       calc_vert_quarter(me, right, center, upper_center, v_steps, half_w, smoothness, true, flip_side);
 }
 
 /* Create standardised Mesh. Simple UxV rectangular grid. (Edges, Loops, Polys):*/
@@ -5716,8 +5913,13 @@ static void bridge_loops(Mesh *me, int e_start_a, int e_start_b, int totvert, bo
                me->medge[e_start + i].flag = 0;
 
                if (i < totvert - 1) {
-                       me->medge[e_start + i].v1 = me->medge[e_start_a + i * a_stride].v1;
-                       me->medge[e_start + i].v2 = me->medge[e_start_b + (flip ? -i : i) * b_stride].v1;
+                       if (flip) {
+                               me->medge[e_start + i].v1 = me->medge[e_start_a + i * a_stride].v1;
+                               me->medge[e_start + i].v2 = me->medge[e_start_b - i * b_stride].v2;
+                       } else {
+                               me->medge[e_start + i].v1 = me->medge[e_start_a + i * a_stride].v1;
+                               me->medge[e_start + i].v2 = me->medge[e_start_b + i * b_stride].v1;
+                       }
 
                        me->mloop[l_start + i * 4 + 0].v = me->medge[e_start_a + i * a_stride].v1;
                        me->mloop[l_start + i * 4 + 0].e = e_start_a + i * a_stride;
@@ -5725,10 +5927,16 @@ static void bridge_loops(Mesh *me, int e_start_a, int e_start_b, int totvert, bo
                        me->mloop[l_start + i * 4 + (n_flip? 3 : 1)].v = me->medge[e_start_a + i * a_stride].v2;
                        me->mloop[l_start + i * 4 + (n_flip? 3 : 1)].e = e_start + i + 1;
 
-                       me->mloop[l_start + i * 4 + 2].v = me->medge[e_start_b + (flip ? -i : i) * b_stride].v2;
-                       me->mloop[l_start + i * 4 + 2].e = e_start_b + (flip ? -i : i) * b_stride;
+                       if (flip) {
+                               me->mloop[l_start + i * 4 + 2].v = me->medge[e_start_b - i * b_stride].v1;
+                               me->mloop[l_start + i * 4 + 2].e = e_start_b - i * b_stride;
+                               me->mloop[l_start + i * 4 + (n_flip? 1 : 3)].v = me->medge[e_start_b - i * b_stride].v2;
+                       } else {
+                               me->mloop[l_start + i * 4 + 2].v = me->medge[e_start_b + i * b_stride].v2;
+                               me->mloop[l_start + i * 4 + 2].e = e_start_b + i * b_stride;
+                               me->mloop[l_start + i * 4 + (n_flip? 1 : 3)].v = me->medge[e_start_b + i * b_stride].v1;
+                       }
 
-                       me->mloop[l_start + i * 4 + (n_flip? 1 : 3)].v = me->medge[e_start_b + (flip ? -i : i) * b_stride].v1;
                        me->mloop[l_start + i * 4 + (n_flip? 1 : 3)].e = e_start + i;
 
                        me->mpoly[p_start + i].loopstart = l_start + i * 4;
@@ -5737,12 +5945,128 @@ static void bridge_loops(Mesh *me, int e_start_a, int e_start_b, int totvert, bo
                        me->mpoly[p_start + i].flag = 0;
                        me->mpoly[p_start + i].pad = 0;
                } else {
-                       me->medge[e_start + i].v1 = me->medge[e_start_a + (i - 1) * a_stride].v2;
-                       me->medge[e_start + i].v2 = me->medge[e_start_b + (flip ? -(i - 1) : (i - 1)) * b_stride].v2;
+                       if (flip) {
+                               me->medge[e_start + i].v1 = me->medge[e_start_a + (i - 1) * a_stride].v2;
+                               me->medge[e_start + i].v2 = me->medge[e_start_b - (i - 1) * b_stride].v1;
+                       } else {
+                               me->medge[e_start + i].v1 = me->medge[e_start_a + (i - 1) * a_stride].v2;
+                               me->medge[e_start + i].v2 = me->medge[e_start_b + (i - 1) * b_stride].v2;
+                       }
                }
        }
 }
 
+/*
+ * Generate a quad from three edges. Returning the newly created edge.
+ *  ___a___
+ *  |      |
+ *  b     new
+ *  |      |
+ *  ___c___
+ */
+static int add_quad(Mesh *me, int edge_b, int edge_a, int edge_c, bool flip)
+{
+       int v_a, v_c;
+       MEdge e_a, e_b, e_c;
+       int e_start = me->totedge;
+       int l_start = me->totloop;
+       int p_start = me->totpoly;
+       bool b_flip = false;
+
+       e_a = me->medge[edge_a];
+       e_b = me->medge[edge_b];
+       e_c = me->medge[edge_c];
+
+       if (e_a.v1 == e_b.v1 || e_a.v1 == e_b.v2){
+               b_flip = (e_a.v1 == e_b.v1);
+               v_a = e_a.v2;
+       } else {
+               b_flip = (e_a.v2 == e_b.v1);
+               v_a = e_a.v1;
+       }
+       if (e_c.v1 == e_b.v1 || e_c.v1 == e_b.v2){
+               v_c = e_c.v2;
+       } else {
+               v_c = e_c.v1;
+       }
+
+       ED_mesh_edges_add(me, NULL, 1);
+
+       me->medge[e_start].v2 = v_a;
+       me->medge[e_start].v1 = v_c;
+       me->medge[e_start].crease = 0;
+       me->medge[e_start].bweight = 0;
+       me->medge[e_start].flag = 0;
+
+       ED_mesh_loops_add(me, NULL, 4);
+       me->mloop[l_start].v = b_flip ? e_b.v1 : e_b.v2;
+       me->mloop[l_start].e = edge_a;
+
+       me->mloop[l_start + (flip ? 1 : 3)].v = v_a;
+       me->mloop[l_start + (flip ? 1 : 3)].e = e_start;
+
+       me->mloop[l_start + 2].v = v_c;
+       me->mloop[l_start + 2].e = edge_c;
+
+       me->mloop[l_start + (flip ? 3 : 1)].v = b_flip ? e_b.v2 : e_b.v1;
+       me->mloop[l_start + (flip ? 3 : 1)].e = edge_b;
+
+       ED_mesh_polys_add(me, NULL, 1);
+       me->mpoly[p_start].loopstart = l_start;
+       me->mpoly[p_start].totloop = 4;
+       me->mpoly[p_start].mat_nr = 0;
+       me->mpoly[p_start].flag = 0;
+       me->mpoly[p_start].pad = 0;
+
+       return e_start;
+}
+
+static void add_face(Mesh *me, int e1, int e2, int e3, int e4, int l_start, int p_start, bool flip){
+       int comp_v1;
+
+       if (me->medge[e1].v1 == me->medge[e2].v1 || me->medge[e1].v1 == me->medge[e2].v2) {
+               comp_v1 = me->medge[e1].v1;
+               me->mloop[l_start].v = me->medge[e1].v2;
+               me->mloop[l_start].e = e1;
+       } else {
+               comp_v1 = me->medge[e1].v2;
+               me->mloop[l_start].v = me->medge[e1].v1;
+               me->mloop[l_start].e = e1;
+       }
+       if (me->medge[e2].v1 == comp_v1) {
+               me->mloop[l_start + (flip ? 3 : 1)].v = me->medge[e2].v1;
+               comp_v1 = me->medge[e2].v2;
+       } else {
+               me->mloop[l_start + (flip ? 3 : 1)].v = me->medge[e2].v2;
+               comp_v1 = me->medge[e2].v1;
+       }
+       me->mloop[l_start + (flip ? 3 : 1)].e = e2;
+
+       if (me->medge[e3].v1 == comp_v1) {
+               me->mloop[l_start + 2].v = me->medge[e3].v1;
+               comp_v1 = me->medge[e3].v2;
+       } else {
+               me->mloop[l_start + 2].v = me->medge[e3].v2;
+               comp_v1 = me->medge[e3].v1;
+       }
+       me->mloop[l_start + 2].e = e3;
+
+       if (me->medge[e4].v1 == comp_v1) {
+               me->mloop[l_start + (flip ? 1 : 3)].v = me->medge[e4].v1;
+               comp_v1 = me->medge[e4].v2;
+       } else {
+               me->mloop[l_start + (flip ? 1 : 3)].v = me->medge[e4].v2;
+               comp_v1 = me->medge[e4].v1;
+       }
+       me->mloop[l_start + (flip ? 1 : 3)].e = e4;
+
+       me->mpoly[p_start].totloop = 4;
+       me->mpoly[p_start].loopstart = l_start;
+       me->mpoly[p_start].mat_nr = 0;
+       me->mpoly[p_start].flag = 0;
+       me->mpoly[p_start].pad = 0;
+}
+
 /* TODO: is there a sort function already?*/
 static int cmpfunc (const void * a, const void * b)
 {
@@ -5750,7 +6074,7 @@ static int cmpfunc (const void * a, const void * b)
 }
 
 /* Generate the Tube shape for branches with two ends. */
-static void fill_tube(Mesh *me, float *left, float *right, int totl, int totr, int u_steps, float z_vec[3], int v_steps, int w_steps, float smoothness, int *UNUSED(r_edge_loop_ends))
+static void fill_tube(Mesh *me, float *left, float *right, int totl, int totr, int u_steps, float z_vec[3], int v_steps, int w_steps, float smoothness, int *r_edge_loop_ends, bool n_g_flip, bool flip_side)
 {
        float step_l = left[totl * 4 - 1] / (float)u_steps;
        float step_r = right[totr * 4 - 1] / (float)u_steps;
@@ -5759,7 +6083,7 @@ static void fill_tube(Mesh *me, float *left, float *right, int totl, int totr, i
        int l_u_pos_i = 1, r_u_pos_i = totr - 2;
 
        const int v_start = me->totvert;
-       //const int e_start = me->totedge;
+       const int e_start = me->totedge;
 
        for (int u = 0; u < u_steps; u++) {
                while (l_u_pos_i < totl - 1 && left[l_u_pos_i * 4 + 3] <= step_l * (float)u) {
@@ -5774,7 +6098,11 @@ static void fill_tube(Mesh *me, float *left, float *right, int totl, int totr, i
                if (totl > 1) {
                        a = left[l_u_pos_i * 4 - 1];
                        b = left[l_u_pos_i * 4 + 3];
-                       f = (step_l * (float)u - a) / (b - a);
+                       if (a != b) {
+                               f = (step_l * (float)u - a) / (b - a);
+                       } else {
+                               f = 0.0f;
+                       }
                        interp_v3_v3v3(v1, &left[l_u_pos_i * 4 - 4], &left[l_u_pos_i * 4], f);
                } else {
                        copy_v3_v3(v1, &left[0]);
@@ -5783,7 +6111,11 @@ static void fill_tube(Mesh *me, float *left, float *right, int totl, int totr, i
                if (totr > 1) {
                        a = right[r_u_pos_i * 4 + 7];
                        b = right[r_u_pos_i * 4 + 3];
-                       f = (step_r * (float)(u_steps - u - 1) - a) / (b - a);
+                       if (a != b) {
+                               f = (step_r * (float)(u_steps - u - 1) - a) / (b - a);
+                       } else {
+                               f = 0.0f;
+                       }
                        interp_v3_v3v3(v2, &right[r_u_pos_i * 4 + 4], &right[r_u_pos_i * 4], f);
                } else {
                        copy_v3_v3(v2, &right[0]);
@@ -5794,14 +6126,20 @@ static void fill_tube(Mesh *me, float *left, float *right, int totl, int totr, i
                add_v3_v3v3(v4, v3, z_vec);
 
                /* v1 left, v2 right, v3 center bottom, v4 center top */
-               calc_vert_half(me, v1, v2, v3, v4, v_steps, w_steps, smoothness);
+               calc_vert_half(me, v1, v2, v3, v4, v_steps, w_steps, smoothness, flip_side);
+       }
+       generate_mesh_grid_f_e(me, u_steps, v_steps * 2 + w_steps - (flip_side ? 2 : 0), v_start, n_g_flip);
+       if (!flip_side) {
+               r_edge_loop_ends[0] = e_start;
+               r_edge_loop_ends[1] = 2;
+               r_edge_loop_ends[2] = me->totedge - v_steps * 2 - w_steps + 1;
+               r_edge_loop_ends[3] = 1;
+       } else {
+               r_edge_loop_ends[4] = e_start;
+               r_edge_loop_ends[5] = 2;
+               r_edge_loop_ends[6] = me->totedge - v_steps * 2 - w_steps + 3;
+               r_edge_loop_ends[7] = 1;
        }
-       generate_mesh_grid_f_e(me, u_steps, v_steps * 2 + w_steps, v_start, false);
-       /*r_edge_loop_ends[0] = e_start;
-       r_edge_loop_ends[1] = 2;
-
-       r_edge_loop_ends[2] = me->totedge - v_steps + w_steps;
-       r_edge_loop_ends[3] = 1;*/
 }
 
 static int get_cyclic_offset(SpineBranch *branch)
@@ -5825,15 +6163,24 @@ static int get_cyclic_offset(SpineBranch *branch)
 }
 
 /* Generate the Cap for branches with one ends. */
-static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float z_vec[3], float depth, int v_steps, int w_steps, float smoothness)
+static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float z_vec[3], float depth, int v_steps, int w_steps, float smoothness, bool n_g_flip, bool flip_side)
 {
        float *cap_p = NULL;
-       float v1[3], m_center[3], m_center_up[3];
+       float v1[3], m_center[3], m_center_up[3], left_ref[3], right_ref[3];
        float totlength = 0.0f;
        float step_size = depth / (float)w_steps;
        int cyclic_offset = 0, n_i = 0;
+       int e_cap_start_a, e_cap_start_b, e_cap_start_c;
+       int e_corner_a, e_corner_b;
+       int cap_end_flip_e_start, cap_end_flip_start_a_l, cap_end_flip_start_b_l;
+       int cap_end_flip_start_a_r, cap_end_flip_start_b_r, e_cap_tube_start, e_cap_tube_end;
+       int e_flip_tube_end[2];
        BLI_array_declare(cap_p);
 
+       if (!flip_side) {
+               branch->fs_bs_offset = me->totedge;
+       }
+
        /* calc and sort hullpoints for the three sides */
        qsort (branch->hull_points, branch->tot_hull_points, sizeof(int), cmpfunc);
 
@@ -5851,6 +6198,12 @@ static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float
                copy_v3_v3(v1, &cap_p[i * 4]);
        }
 
+       if (!(branch->flag & BRANCH_EDGE_GEN)) {
+               branch->e_start_arr = MEM_callocN(sizeof(int) * 4, "edge startposition array");
+               branch->e_flip_side_ends = MEM_callocN(sizeof(int) * 2, "fs bs edges");
+               branch->flag |= BRANCH_EDGE_GEN;
+       }
+
        totlength = cap_p[branch->tot_hull_points * 4 - 1];
 
        float cap_length = fmin(totlength, (w_steps * step_size));
@@ -5860,12 +6213,14 @@ static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float
        int u_pos_i = 0;
        int v_start = me->totvert;
        int u_steps;
-       int e_start_tube[4];
+       int e_start_tube[8];
+       int totl = 0, totr = 0;
+       int e_flip_start;
+       int e_flip_offset = 0;  /* carry edgecount difference in both sides to refrence opposing edges by subtracting totedge - flip offset. Only valid if flip_side = true*/
 
        /* If the cap is big enough a tube is added between the cap and the last branch. */
        if (totlength > step_size * w_steps) {
                int side_l = cap_pos;
-               int totl = 0, totr = 0;
                float *left = NULL, *right = NULL;
                float n_off_right;
                BLI_array_declare(left);
@@ -5898,42 +6253,98 @@ static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float
 
                if (totl >= 1 && totr >= 1) {
                        u_steps = fmax(2.0f, fmax(left[totl * 4 - 1], right[totr * 4 - 1]) / (float)(2 * depth / v_steps));
-                       fill_tube(me, left, right, totl, totr, u_steps, z_vec, v_steps, w_steps, smoothness, e_start_tube);
+                       e_flip_start = me->totedge;
+                       fill_tube(me, left, right, totl, totr, u_steps, z_vec, v_steps, w_steps, smoothness, e_start_tube, n_g_flip, flip_side);
+                       copy_v3_v3(left_ref, &left[totl * 4 - 4]);
+                       copy_v3_v3(right_ref, &right[0]);
+                       cap_length = totlength - left[totl * 4 - 1] - right[totr * 4 - 1];
+
+                       if (flip_side) {
+                               branch->e_flip_side_ends[0] = me->totedge;
+                               bridge_loops(me,
+                                                        e_flip_start + 1,
+                                                        e_flip_start - branch->fs_bs_offset + 1,
+                                                        u_steps,
+                                                        false,
+                                                        ((v_steps - 1) * 2 + w_steps) * 2 - 1,
+                                                        (v_steps * 2 + w_steps) * 2 - 1,
+                                                        !n_g_flip);
+                               branch->e_flip_side_ends[1] = me->totedge;
+                               e_flip_tube_end[0] = me->totedge - 1;
+                               bridge_loops(me,
+                                                        e_flip_start + ((v_steps - 1) * 2 + w_steps) * 2 - 2,
+                                                        e_flip_start - branch->fs_bs_offset + (v_steps * 2 + w_steps) * 2 - 2,
+                                                        u_steps,
+                                                        false,
+                                                        ((v_steps - 1) * 2 + w_steps) * 2 - 1,
+                                                        (v_steps * 2 + w_steps) * 2 - 1,
+                                                        n_g_flip);
+                               e_flip_tube_end[1] = me->totedge - 1;
+                               e_flip_offset += u_steps * 2 - 2;
+                       }
                }
-
-               copy_v3_v3(m_center, &left[totl * 4 - 4]);
-               add_v3_v3(m_center, &right[0]);
-               mul_v3_fl(m_center, 0.5f);
                BLI_array_free(left);
                BLI_array_free(right);
-       } else {
-               copy_v3_v3(m_center, &cap_p[0]);
-               add_v3_v3(m_center, &cap_p[branch->tot_hull_points * 4 - 4]);
-               mul_v3_fl(m_center, 0.5f);
+       }
+
+       if (totlength <= step_size * w_steps || totl == 0 || totr == 0) {
+               copy_v3_v3(left_ref, &cap_p[0]);
+               copy_v3_v3(right_ref, &cap_p[branch->tot_hull_points * 4 - 4]);
        }
 
        cap_pos = (totlength - cap_length) / 2.0f;
-       u_pos_i = 1;
-       v_start = me->totvert;
+       step_size = cap_length / (w_steps + 2);
 
+       interp_v3_v3v3(m_center, left_ref, right_ref, 0.5f);
        add_v3_v3v3(m_center_up, m_center, z_vec);
 
-       /*TODO: Corners need two additional loops*/
+       /* Add connecting edge */
+       v_start = me->totvert;
+       e_cap_start_a = me->totedge;
+       calc_vert_half(me,
+                                  left_ref,
+                                  right_ref,
+                                  m_center,
+                                  m_center_up,
+                                  v_steps,
+                                  w_steps,
+                                  smoothness,
+                                  flip_side);
+
+       /*TODO connect to flipside */
+       ED_mesh_edges_add(me, NULL, v_steps * 2 + w_steps - 1 - (flip_side ? 2 : 0));
+       for(int v = 0; v < v_steps * 2 + w_steps - 1 - (flip_side ? 2 : 0); v++){
+               me->medge[e_cap_start_a + v].v1 = v_start + v;
+               me->medge[e_cap_start_a + v].v2 = v_start + v + 1;
+               me->medge[e_cap_start_a + v].crease = 0;
+               me->medge[e_cap_start_a + v].bweight = 0;
+               me->medge[e_cap_start_a + v].flag = 0;
+       }
+
+       e_flip_offset += 2;
+
+       cap_pos += step_size;
+
+       u_pos_i = 1;
+       v_start = me->totvert;
+
        for (int u = 0; u < w_steps; u++) {
                while (u_pos_i < branch->tot_hull_points && cap_p[u_pos_i * 4 + 3] <= cap_pos) {
                        u_pos_i ++;
                }
 
+               interp_v3_v3v3(m_center, left_ref, right_ref, smoothness * 0.5f + (1.0f - smoothness) * ((float)u / w_steps));
+               add_v3_v3v3(m_center_up, m_center, z_vec);
+
                a = cap_p[u_pos_i * 4 - 1];
                b = cap_p[u_pos_i * 4 + 3];
-               f = (cap_pos - a) / (b - a);
+               if (a != b) {
+                       f = (cap_pos - a) / (b - a);
+               } else {
+                       f = 0.0f;
+               }
                interp_v3_v3v3(v1, &cap_p[u_pos_i * 4 - 4], &cap_p[u_pos_i * 4], f);
 
-               /* TODO: Better c ref point*/
-               bl_debug_color_set(0xff0000);
-               bl_debug_draw_point(v1, 0.2f);
-               bl_debug_color_set(0x000000);
-
                calc_vert_quarter(me,
                                                  v1,
                                                  m_center,
@@ -5941,16 +6352,172 @@ static void add_ss_cap(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float
                                                  v_steps,
                                                  0,
                                                  smoothness,
-                                                 false);
+                                                 false,
+                                                 flip_side);
 
                cap_pos += step_size;
        }
-       generate_mesh_grid_f_e(me, w_steps, v_steps, v_start, false);
+       e_cap_start_b = me->totedge;
+       generate_mesh_grid_f_e(me, w_steps, v_steps - (flip_side ? 1 : 0), v_start, n_g_flip);
+       e_cap_start_c = me->totedge;
+
+       if (flip_side) {
+               cap_end_flip_e_start = me->totedge;
+               bridge_loops(me,
+                                        e_cap_start_b + 1,
+                                        e_cap_start_b - branch->fs_bs_offset + e_flip_offset + 1,
+                                        w_steps,
+                                        false,
+                                        v_steps * 2 - 3,
+                                        v_steps * 2 - 1,
+                                        !n_g_flip);
+               e_flip_offset += w_steps - 1;
+       }
+
+       bridge_loops(me,
+                                e_cap_start_a,
+                                e_cap_start_b,
+                                v_steps - (flip_side ? 1 : 0),
+                                false,
+                                1,
+                                2,
+                                !n_g_flip);
+
+       e_corner_a = me->totedge - 1;
+       cap_end_flip_start_a_l = me->totedge - v_steps + 1;
+       cap_end_flip_start_b_l = me->totedge - v_steps + 1 - branch->fs_bs_offset + e_flip_offset;
+
+       bridge_loops(me,
+                                e_cap_start_a + v_steps - (flip_side ? 1 : 0),
+                                e_cap_start_b + 2 * v_steps - 2 - (flip_side ? 2 : 0),
+                                w_steps,
+                                false,
+                                1,
+                                2 * v_steps - 1 - (flip_side ? 2 : 0),
+                                !n_g_flip);
+
+       e_corner_b = me->totedge - 1;
+
+       bridge_loops(me,
+                                e_cap_start_a + v_steps - (flip_side ? 1 : 0) + w_steps,
+                                e_cap_start_c - 1,
+                                v_steps - (flip_side ? 1 : 0),
+                                true,
+                                1,
+                                1,
+                                !n_g_flip);
+       cap_end_flip_start_a_r = me->totedge - 1;
+       cap_end_flip_start_b_r = me->totedge - branch->fs_bs_offset + e_flip_offset + 1;
+
+       ED_mesh_loops_add(me, NULL, 6);
+       ED_mesh_polys_add(me, NULL, 2);
+       /* corner a */
+       me->mloop[me->totloop - 6].v = me->medge[e_cap_start_a + v_steps -(flip_side ? 1 : 0) - 1].v1;
+       me->mloop[me->totloop - 6].e = e_cap_start_a + v_steps -(flip_side ? 1 : 0) - 1;
+
+       me->mloop[me->totloop - (n_g_flip ? 5 : 4)].v = me->medge[e_corner_a + 1].v1;
+       me->mloop[me->totloop - (n_g_flip ? 5 : 4)].e = e_corner_a + 1;
+
+       me->mloop[me->totloop - (n_g_flip ? 4 : 5)].v = me->medge[e_corner_a].v2;
+       me->mloop[me->totloop - (n_g_flip ? 4 : 5)].e = e_corner_a;
+
+       me->mpoly[me->totpoly - 2].loopstart = me->totloop - 6;
+       me->mpoly[me->totpoly - 2].totloop = 3;
+       me->mpoly[me->totpoly - 2].mat_nr = 0;
+       me->mpoly[me->totpoly - 2].flag = 0;
+       me->mpoly[me->totpoly - 2].pad = 0;
+
+       /* corner b*/
+       me->mloop[me->totloop - 3].v = me->medge[e_cap_start_a + v_steps -(flip_side ? 1 : 0) + w_steps - 1].v1;
+       me->mloop[me->totloop - 3].e = e_cap_start_a + v_steps -(flip_side ? 1 : 0) + w_steps - 1;
+
+       me->mloop[me->totloop - (n_g_flip ? 2 : 1)].v = me->medge[e_corner_b + 1].v1;
+       me->mloop[me->totloop - (n_g_flip ? 2 : 1)].e = e_corner_b + 1;
+
+       me->mloop[me->totloop - (n_g_flip ? 1 : 2)].v = me->medge[e_corner_b].v2;
+       me->mloop[me->totloop - (n_g_flip ? 1 : 2)].e = e_corner_b;
+
+       me->mpoly[me->totpoly - 1].loopstart = me->totloop - 3;
+       me->mpoly[me->totpoly - 1].totloop = 3;
+       me->mpoly[me->totpoly - 1].mat_nr = 0;
+       me->mpoly[me->totpoly - 1].flag = 0;
+       me->mpoly[me->totpoly - 1].pad = 0;
+
+       if (totlength <= step_size * w_steps || totl == 0 || totr == 0) {
+               branch->e_start_arr[flip_side ? 2 : 0] = e_cap_start_a;
+               branch->e_start_arr[flip_side ? 3 : 1] = 1;
+       } else {
+               e_cap_tube_start = me->totedge;
+               bridge_loops(me,
+                                        e_cap_start_a,
+                                        e_start_tube[flip_side ? 6 : 2],
+                                        v_steps * 2 + w_steps - (flip_side ? 2 : 0),
+                                        false,
+                                        1,
+                                        1,
+                                        n_g_flip);
+               e_cap_tube_end = me->totedge - 1;
+               e_flip_offset += 2;
+               branch->e_start_arr[flip_side ? 2 : 0] = e_start_tube[flip_side ? 4 : 0];
+               branch->e_start_arr[flip_side ? 3 : 1] = e_start_tube[flip_side ? 5 : 1];
+       }
+
+       if (!flip_side) {
+               branch->fs_bs_offset = me->totedge - branch->fs_bs_offset;
+       } else {
+               add_quad(me, cap_end_flip_e_start, cap_end_flip_start_a_l, cap_end_flip_start_b_l, !n_g_flip);
+               add_quad(me, cap_end_flip_e_start + w_steps - 1, cap_end_flip_start_a_r, cap_end_flip_start_b_r, n_g_flip);
+               if (totlength <= step_size * w_steps || totl == 0 || totr == 0) {
+                       branch->e_flip_side_ends[0] = me->totedge - 2;
+                       branch->e_flip_side_ends[1] = me->totedge - 1;
+               } else {
+                       ED_mesh_loops_add(me, NULL, 8);
+                       ED_mesh_polys_add(me, NULL, 2);
+                       add_face(me,
+                                        e_flip_tube_end[0],
+                                        e_cap_tube_start - branch->fs_bs_offset + e_flip_offset,
+                                        me->totedge - 2,
+                                        e_cap_tube_start,
+                                        me->totloop - 8,
+                                        me->totpoly - 2,
+                                        n_g_flip);
+
+                       add_face(me,
+                                        e_flip_tube_end[1],
+                                        e_cap_tube_end - branch->fs_bs_offset + e_flip_offset + 2,
+                                        me->totedge - 1,
+                                        e_cap_tube_end,
+                                        me->totloop - 4,
+                                        me->totpoly - 1,
+                                        !n_g_flip);
+               }
+       }
+
        BLI_array_free(cap_p);
 }
 
+static int calc_branch_orientation(Spine *spine, SpineBranch *branch, float point[3], int f_s)
+{
+       int s = 0;
+       float last_dist = len_v3v3(&spine->branches[branch->terminal_points[1]]->points[spine->branches[branch->terminal_points[1]]->totpoints * 3 - 3], point);
+       if (spine->branches[branch->terminal_points[3]]->totpoints < 2 || spine->branches[branch->terminal_points[5]]->totpoints < 2) {
+               return f_s;
+       }
+       float curr_dist = len_v3v3(&spine->branches[branch->terminal_points[3]]->points[3], point);
+       if(last_dist > curr_dist){
+               last_dist = curr_dist;
+               s = 1;
+       }
+       curr_dist = len_v3v3(&spine->branches[branch->terminal_points[5]]->points[3], point);
+       if(last_dist > curr_dist){
+               last_dist = curr_dist;
+               s = 2;
+       }
+       return s;
+}
+
 /* Generate a T-Intersection for branches with three ends. */
-static void add_ss_tinter(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float z_vec[3], float depth, int v_steps, int w_steps, float smoothness)
+static void add_ss_tinter(SilhouetteData *sil, Spine *spine, SpineBranch *branch, Mesh *me, float z_vec[3], float depth, int v_steps, int w_steps, float smoothness, bool n_g_flip, bool flip_side)
 {
        float *sa = NULL;
        int b_start[3] = {0,0,0}, b_tot[3] = {0,0,0};
@@ -5961,9 +6528,19 @@ static void add_ss_tinter(SilhouetteData *sil, SpineBranch *branch, Mesh *me, fl
        float v1[3], v2[3], v3[3], v4[3], center[3], center_up[3];
        float center_s[3 * 3];
        int w_h_steps = w_steps / 2;
-       int v_start;
+       int v_start, v_start_center;
+       int e_start[3], e_start_center, e_start_inner[3], e_t_sign[6];
+       int stride_le;
+       int ori[3];
+       int e_flip_offset = 0;  /* carry edgecount difference in both sides to refrence opposing edges by subtracting totedge - flip offset. Only valid if flip_side = true*/
+       int e_flip_start[3];
+       int e_flip_q_l[3], e_flip_q_r[3];
        BLI_array_declare(sa);
 
+       if (!flip_side) {
+               branch->fs_bs_offset = me->totedge;
+       }
+
        /* calc and sort hullpoints for the three sides */
        qsort (branch->hull_points, branch->tot_hull_points, sizeof(int), cmpfunc);
 
@@ -6005,7 +6582,7 @@ static void add_ss_tinter(SilhouetteData *sil, SpineBranch *branch, Mesh *me, fl
                }
        }
 
-       u_steps = 3;
+       u_steps = 5;
        zero_v3(center);
        for (int s = 0; s < 3; s++) {
                copy_v3_v3(&center_s[s * 3], &sa[b_start[s]]);
@@ -6024,11 +6601,28 @@ static void add_ss_tinter(SilhouetteData *sil, SpineBranch *branch, Mesh *me, fl
        /*needs to be uneven*/
        u_steps |= 1;
 
+       if (!(branch->flag & BRANCH_EDGE_GEN)) {
+               branch->e_start_arr = MEM_callocN(sizeof(int) * 12,"edge startposition array");
+               branch->e_flip_side_ends = MEM_callocN(sizeof(int) * 6, "fs bs edges");
+               branch->flag |= BRANCH_EDGE_GEN;
+       }
+
+       v_start_center = me->totvert;
+       ED_mesh_vertices_add(me, NULL, u_steps + u_steps / 2);
+       e_start_center = me->totedge;
+       ED_mesh_edges_add(me, NULL, (u_steps / 2) * 3);
+
        for (int s = 0; s < 3; s++) {
                step_length = sa[b_start[s] + b_tot[s] * 4 - 1] / (float)u_steps;
 
                add_v3_v3v3(v3, &center_s[s * 3], z_vec);
 
+               v_start = me->totvert;
+
+               ori[s] = calc_branch_orientation(spine, branch, &center_s[s * 3], s);
+               branch->e_start_arr[(flip_side ? 6 : 0) + ori[s] * 2] = me->totedge;
+               branch->e_start_arr[(flip_side ? 6 : 0) + ori[s] * 2 + 1] = 1;
+
                calc_vert_half(me,
                                           &sa[b_start[s]],
                                           &sa[b_start[(s + 2) % 3] + b_tot[(s + 2) % 3] * 4 - 4],
@@ -6036,7 +6630,21 @@ static void add_ss_tinter(SilhouetteData *sil, SpineBranch *branch, Mesh *me, fl
                                           v3,
                                           v_steps,
                                           w_steps,
-                                          smoothness);
+                                          smoothness,
+                                          flip_side);
+
+               e_start[s] = me->totedge;
+
+               ED_mesh_edges_add(me, NULL, v_steps * 2 + w_steps - 1 - (flip_side ? 2 : 0));
+               for(int v = 0; v < v_steps * 2 + w_steps - 1 - (flip_side ? 2 : 0); v++){
+                       me->medge[e_start[s] + v].v1 = v_start + v;
+                       me->medge[e_start[s] + v].v2 = v_start + v + 1;
+                       me->medge[e_start[s] + v].crease = 0;
+                       me->medge[e_start[s] + v].bweight = 0;
+                       me->medge[e_start[s] + v].flag = 0;
+               }
+
+               e_flip_offset += 2;
 
                v_start = me->totvert;
 
@@ -6052,42 +6660,201 @@ static void add_ss_tinter(SilhouetteData *sil, SpineBranch *branch, Mesh *me, fl
                        } else {
                                a = sa[b_start[s] + pos_i_sa * 4 - 1];
                                b = sa[b_start[s] + pos_i_sa * 4 + 3];
-                               f = (step_length * (float)u - a) / (b - a);
+                               if (a != b) {
+                                       f = (step_length * (float)u - a) / (b - a);
+                               } else {
+                                       f = 0.0f;
+                               }
                                interp_v3_v3v3(v1, &sa[b_start[s] + pos_i_sa * 4 - 4], &sa[b_start[s] + pos_i_sa * 4], f);
                        }
 
                        f = fabs((float)(u_steps / 2 - u) / ((float)u_steps / 2.0f));
                        if (u < u_steps / 2){
                                interp_v3_v3v3(v4, center, &center_s[s * 3], f);
+                               add_v3_v3v3(v2, v4, z_vec);
+
+                               copy_v3_v3(me->mvert[v_start_center + s * (u_steps / 2) + u].co, v2);
+                               me->mvert[v_start_center + s * (u_steps / 2) + u].flag = 0;
+                               me->mvert[v_start_center + s * (u_steps / 2) + u].bweight = 0;
                        } else if (u == u_steps / 2) {
                                copy_v3_v3(v4, center);
+                               add_v3_v3v3(v2, v4, z_vec);
+                               if (s == 0) {
+                                       /* Add center at v2 */
+                                       copy_v3_v3(me->mvert[v_start_center].co, v2);
+                                       me->mvert[v_start_center].flag = 0;
+                                       me->mvert[v_start_center].bweight = 0;
+                               }
                        } else {
                                interp_v3_v3v3(v4, center, &center_s[(s + 1) % 3 * 3], f);
+                               add_v3_v3v3(v2, v4, z_vec);
                        }
-                       add_v3_v3v3(v2, v4, z_vec);
 
-                       calc_vert_quarter(me, v1, v4, v2, v_steps, w_h_steps, smoothness, false);
-               }
+                       calc_vert_quarter(me, v1, v4, v2, v_steps, w_h_steps, smoothness, false, flip_side);
+               }
+
+               me->medge[e_start_center + s * (u_steps / 2)].v1 = me->medge[e_start[s] + v_steps - (flip_side ? 1 : 0) + w_steps / 2].v1;
+               me->medge[e_start_center + s * (u_steps / 2)].v2 = v_start_center + s * (u_steps / 2) + 1;
+               me->medge[e_start_center + s * (u_steps / 2)].crease = 0;
+               me->medge[e_start_center + s * (u_steps / 2)].bweight = 0;
+               me->medge[e_start_center + s * (u_steps / 2)].flag = 0;
+
+               for (int u = 1; u < u_steps / 2 - 1; u++) {
+                       me->medge[e_start_center + s * (u_steps / 2) + u].v1 = v_start_center + s * (u_steps / 2) + u;
+                       me->medge[e_start_center + s * (u_steps / 2) + u].v2 = v_start_center + s * (u_steps / 2) + 1 + u;
+                       me->medge[e_start_center + s * (u_steps / 2) + u].crease = 0;
+                       me->medge[e_start_center + s * (u_steps / 2) + u].bweight = 0;
+                       me->medge[e_start_center + s * (u_steps / 2) + u].flag = 0;
+               }
+
+               me->medge[e_start_center + (s + 1) * (u_steps / 2) - 1].v1 = v_start_center + s * (u_steps / 2) + 1 + (u_steps / 2 - 2);
+               me->medge[e_start_center + (s + 1) * (u_steps / 2) - 1].v2 = v_start_center;
+               me->medge[e_start_center + (s + 1) * (u_steps / 2) - 1].crease = 0;
+               me->medge[e_start_center + (s + 1) * (u_steps / 2) - 1].bweight = 0;
+               me->medge[e_start_center + (s + 1) * (u_steps / 2) - 1].flag = 0;
+
+               e_start_inner[s] = me->totedge;
+               generate_mesh_grid_f_e(me, u_steps - 2, v_steps - (flip_side ? 1 : 0) + w_steps / 2, v_start, n_g_flip);
+
+               if (flip_side) {
+                       e_flip_start[s] = me->totedge;
+                       bridge_loops(me,
+                                                e_start_inner[s] + 1,
+                                                e_start_inner[s] - branch->fs_bs_offset + e_flip_offset + 1,
+                                                u_steps - 2,
+                                                false,
+                                                (v_steps - 1 + w_steps / 2) * 2 - 1,
+                                                (v_steps + w_steps / 2) * 2 - 1,
+                                                !n_g_flip);
+
+                       e_flip_offset += u_steps - 3;
+               }
+       }
+
+       for(int s = 0; s < 3; s++){
+               int e_end_a, e_end_b;
+               bridge_loops(me,
+                                        e_start_inner[s],
+                                        e_start[s],
+                                        v_steps -(flip_side ? 1 : 0) + w_steps / 2,
+                                        false,
+                                        2,
+                                        1,
+                                        n_g_flip);
+               e_flip_offset += 1;
+
+               if (flip_side) {
+                       e_flip_q_l[0] = e_flip_start[s];
+                       e_flip_q_l[1] = me->totedge - (v_steps + w_steps / 2) + 1;
+                       e_flip_q_l[2] = me->totedge - (v_steps + w_steps / 2) - branch->fs_bs_offset + e_flip_offset;
+               }
+
+               e_end_a = me->totedge;
+               bridge_loops(me,
+                                        e_start_inner[(s + 2) % 3] + (u_steps - 3) * (2 * (v_steps -(flip_side ? 1 : 0) + w_steps / 2) - 1),
+                                        e_start[s] + v_steps * 2 -(flip_side ? 2 : 0) + w_steps - 2,
+                                        v_steps -(flip_side ? 1 : 0) + w_steps / 2,
+                                        true,
+                                        1,
+                                        1,
+                                        !n_g_flip);
+
+               if (flip_side) {
+                       e_flip_q_r[0] = e_flip_start[(s + 2) % 3] + u_steps - 3;
+                       e_flip_q_r[1] = me->totedge - (v_steps + w_steps / 2) + 1;
+                       e_flip_q_r[2] = me->totedge - (v_steps + w_steps / 2) + 1 - branch->fs_bs_offset + e_flip_offset;
+               }
+
+               e_end_b = me->totedge;
+
+               int e_side_a, e_side_b;
+               e_side_a = add_quad(me, e_start[s] + v_steps -(flip_side ? 1 : 0) + w_steps / 2, e_start_center + s * (u_steps / 2), e_end_b - 1, !n_g_flip);
+               e_side_b = add_quad(me, e_start[s] + v_steps -(flip_side ? 1 : 0) + w_steps / 2 - 1, e_end_a - 1, e_start_center + s * (u_steps / 2), !n_g_flip);
+               stride_le = (2 * (v_steps -(flip_side ? 1 : 0) + w_steps / 2) - 1);
+
+               for (int u = 1; u < u_steps / 2 - 1; u++) {
+                       e_side_b = add_quad(me,
+                                                               e_side_b,
+                                                               e_start_inner[s] - 1 + stride_le * u,
+                                                               e_start_center + s * (u_steps / 2) + u,
+                                                               !n_g_flip);
+                       e_side_a = add_quad(me,
+                                                               e_side_a,
+                                                               e_start_inner[(s + 2) % 3] - 1 + stride_le * (u_steps - 2 - u),
+                                                               e_start_center + s * (u_steps / 2) + u,
+                                                               n_g_flip);
+               }
+
+               e_t_sign[s * 2] = add_quad(me,
+                                e_side_b,
+                                e_start_inner[s] - 1 + stride_le * ((u_steps / 2) - 1),
+                                e_start_center + s * (u_steps / 2) + u_steps / 2 - 1,
+                                !n_g_flip);
+
+               e_t_sign[s * 2 + 1] = e_side_a;
+
+               if (flip_side) {
+                       branch->e_flip_side_ends[ori[s] * 2] = me->totedge;
+                       add_quad(me,
+                                        e_flip_q_l[0],
+                                        e_flip_q_l[1],
+                                        e_flip_q_l[2],
+                                        !n_g_flip);
+                       branch->e_flip_side_ends[ori[s] * 2 + 1] = me->totedge;
+                       add_quad(me,
+                                        e_flip_q_r[0],
+                                        e_flip_q_r[1],
+                                        e_flip_q_r[2],
+                                        n_g_flip);
+                       e_flip_offset -= 1;
+               }
+       }
+
+       for(int s = 0; s < 3; s++){
+               ED_mesh_loops_add(me, NULL, 4);
+               me->mloop[me->totloop - 4].v = me->medge[e_t_sign[(s + 2) % 3 * 2]].v1;
+               me->mloop[me->totloop - 4].e = e_t_sign[(s + 2) % 3 * 2];
+
+               me->mloop[me->totloop - (n_g_flip ? 3 : 1)].v = me->medge[e_start_center + s * (u_steps / 2) + u_steps / 2 - 1].v1;
+               me->mloop[me->totloop - (n_g_flip ? 3 : 1)].e = e_start_center + s * (u_steps / 2) + u_steps / 2 - 1;
+
+               me->mloop[me->totloop - 2].v = me->medge[e_start_inner[(s + 2) % 3] - 1 + stride_le * ((u_steps / 2))].v2;
+               me->mloop[me->totloop - 2].e = e_t_sign[s * 2 + 1];
+
+               me->mloop[me->totloop - (n_g_flip ? 1 : 3)].v = me->medge[e_start_inner[(s + 2) % 3] - 1 + stride_le * ((u_steps / 2))].v1;
+               me->mloop[me->totloop - (n_g_flip ? 1 : 3)].e = e_start_inner[(s + 2) % 3] - 1 + stride_le * ((u_steps / 2));
 
-               generate_mesh_grid_f_e(me, u_steps - 2, v_steps + w_steps / 2, v_start, false);
+               ED_mesh_polys_add(me, NULL, 1);
+               me->mpoly[me->totpoly - 1].loopstart = me->totloop - 4;
+               me->mpoly[me->totpoly - 1].totloop = 4;
+               me->mpoly[me->totpoly - 1].mat_nr = 0;
+               me->mpoly[me->totpoly - 1].flag = 0;
+               me->mpoly[me->totpoly - 1].pad = 0;
+
+       }
+
+       if (!flip_side) {
+               branch->fs_bs_offset = me->totedge - branch->fs_bs_offset;
        }
 
-       /* TODO: faces */
        BLI_array_free(sa);
 }
 
-static void add_ss_tube(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float z_vec[3], float depth, int v_steps, int w_steps, float w_fact)
+static void add_ss_tube(SilhouetteData *sil, SpineBranch *branch, Mesh *me, float z_vec[3], float depth, int v_steps, int w_steps, float w_fact, bool n_g_flip, bool flip_side)
 {
        /* x y z l (accumulative length)*/
        float *left = NULL, *right = NULL;
        int totl = 0, totr = 0;
        int u_steps = 0;
-       //int square_uv_steps;
        bool f_swap = false;
        int cyclic_offset = 0, n_i = 0;
+       int e_start = 0;
        BLI_array_declare(left);
        BLI_array_declare(right);
 
+       if (!flip_side) {
+               branch->fs_bs_offset = me->totedge;
+       }
        /* Calc and sort Hullpoints to left and right side */
        qsort (branch->hull_points, branch->tot_hull_points, sizeof(int), cmpfunc);
 
@@ -6141,12 +6908,41 @@ static void add_ss_tube(SilhouetteData *sil, SpineBranch *branch, Mesh *me, floa
        }
 
        u_steps = fmax(2.0f, fmax(left[totl * 4 - 1], right[totr * 4 - 1]) / (float)(2 * depth / v_steps));
-       //square_uv_steps = u_steps * v_steps;
-       /*if (!(branch->flag & BRANCH_EDGE_GEN)) {
-               branch->e_start_arr = MEM_callocN(sizeof(int) * 18,"edge startposition array");
+
+       if (!(branch->flag & BRANCH_EDGE_GEN)) {
+               branch->e_start_arr = MEM_callocN(sizeof(int) * 8, "edge startposition array");
+               branch->e_flip_side_ends = MEM_callocN(sizeof(int) * 4, "fs bs edges");
                branch->flag |= BRANCH_EDGE_GEN;
-       }*/
-       fill_tube(me, left, right, totl, totr, u_steps, z_vec, v_steps, w_steps, w_fact, branch->e_start_arr);
+       }
+
+       e_start = me->totedge;
+
+       fill_tube(me, left, right, totl, totr, u_steps, z_vec, v_steps, w_steps, w_fact, branch->e_start_arr, n_g_flip, flip_side);
+
+       if (flip_side) {
+               branch->e_flip_side_ends[0] = me->totedge;
+               bridge_loops(me,
+                                        e_start + 1,
+                                        e_start - branch->fs_bs_offset + 1,
+                                        u_steps,
+                                        false,
+                                        ((v_steps - 1) * 2 + w_steps) * 2 - 1,
+                                        (v_steps * 2 + w_steps) * 2 - 1,
+                                        !n_g_flip);
+               branch->e_flip_side_ends[1] = me->totedge;
+               branch->e_flip_side_ends[2] = me->totedge - 1;
+               bridge_loops(me,
+                                        e_start + ((v_steps - 1) * 2 + w_steps) * 2 - 2,
+                                        e_start - branch->fs_bs_offset + (v_steps * 2 + w_steps) * 2 - 2,
+                                        u_steps,
+                                        false,
+                                        ((v_steps - 1) * 2 + w_steps) * 2 - 1,
+                                        (v_steps * 2 + w_steps) * 2 - 1,
+                                        n_g_flip);
+               branch->e_flip_side_ends[3] = me->totedge - 1;
+       } else {
+               branch->fs_bs_offset = me->totedge - branch->fs_bs_offset;
+       }
 
        BLI_array_free(left);
        BLI_array_free(right);
@@ -6164,10 +6960,12 @@ static int r_branch_count(Spine *spine, SpineBranch *b)
        return r_forks;
 }
 
-/* Connects the different Branches if they have the BRANCH_EDGE_GEN flag set. */
-static void bridge_all_parts_rec(Mesh *me, Spine *spine, SpineBranch *active_branch, SpineBranch *prev_branch)
+/* TODO: T-Intersections are sometimes misordered! Connects the different Branches if they have the BRANCH_EDGE_GEN flag set. */
+static void bridge_all_parts_rec(Mesh *me, Spine *spine, SpineBranch *active_branch, SpineBranch *prev_branch, int verts_per_loop, bool n_g_flip)
 {
-       int b_fork_off, a_fork_off = 0;
+       int b_fork_off, a_fork_off, a_fork_off_inv, b_fork_off_inv, comp_e_start, comp_e_start_flip;
+       float dist_a, dist_b;
+       a_fork_off = 0;
        for (int i = 0; i < active_branch->totforks; i++) {
                SpineBranch *comp = spine->branches[active_branch->terminal_points[i * 2 + 1]];
                if (comp && comp != prev_branch) {
@@ -6181,22 +6979,65 @@ static void bridge_all_parts_rec(Mesh *me, Spine *spine, SpineBranch *active_bra
                                                b_fork_off ++;
                                        }
                                }
-                               for (int s = 0; s < 3; s++) {
-                                       if (s == 1 && (comp->totforks == 3 || active_branch->totforks == 3)) {
-                                               /* TODO: connect center */
-                                       } else {
-                                               bridge_loops(me,
-                                                                        active_branch->e_start_arr[a_fork_off * 9 + s * 3],
-                                                                        comp->e_start_arr[b_fork_off * 9 + s * 3],
-                                                                        active_branch->e_start_arr[a_fork_off * 9 + s * 3 + 1],
-                                                                        false,
-                                                                        active_branch->e_start_arr[a_fork_off * 9 + s * 3 + 2],
-                                                                        comp->e_start_arr[b_fork_off * 9 + s * 3 + 2],
-                                                                        !(s & 2));
-                                       }
+
+                               /* TODO: Might fail with thin geometry */
+                               dist_a = len_v3v3(me->mvert[me->medge[active_branch->e_start_arr[a_fork_off * 2]].v1].co, me->mvert[me->medge[comp->e_start_arr[b_fork_off * 2]].v1].co);
+                               dist_b = len_v3v3(me->mvert[me->medge[active_branch->e_start_arr[a_fork_off * 2]].v1].co, me->mvert[me->medge[comp->e_start_arr[b_fork_off * 2] + (verts_per_loop - 2 - 0) * comp->e_start_arr[b_fork_off * 2 + 1]].v2].co);
+
+                               /* TODO: Tube bug inverse?
+                               if (comp->hull_points[0] == 0) {
+                                       bl_debug_color_set(0x0000ff);
+                                       bl_debug_draw_medge_add(me, comp->e_start_arr[b_fork_off * 2] + comp->e_start_arr[b_fork_off * 2 + 1] * (verts_per_loop - 2));
+                                       bl_debug_color_set(0x000000);
+                               }*/
+                               a_fork_off_inv = a_fork_off * 2 + active_branch->totforks * 2;
+                               b_fork_off_inv = b_fork_off * 2 + comp->totforks * 2;
+                               if (dist_a > dist_b) {
+                                       comp_e_start = comp->e_start_arr[b_fork_off * 2] + comp->e_start_arr[b_fork_off * 2 + 1] * (verts_per_loop - 2);
+                                       comp_e_start_flip = comp->e_start_arr[b_fork_off_inv] + comp->e_start_arr[b_fork_off_inv + 1] * (verts_per_loop - 4);
+                               } else {
+                                       comp_e_start = comp->e_start_arr[b_fork_off * 2];
+                                       comp_e_start_flip = comp->e_start_arr[b_fork_off_inv];
                                }
+                               bridge_loops(me,
+                                                        active_branch->e_start_arr[a_fork_off * 2],
+                                                        comp_e_start,
+                                                        verts_per_loop,
+                                                        (dist_a > dist_b),
+                                                        active_branch->e_start_arr[a_fork_off * 2 + 1],
+                                                        comp->e_start_arr[b_fork_off * 2 + 1],
+                                                        !n_g_flip ^ (dist_a > dist_b));
+
+                               bridge_loops(me,
+                                                        active_branch->e_start_arr[a_fork_off_inv],
+                                                        comp_e_start_flip,
+                                                        verts_per_loop - 2,
+                                                        (dist_a > dist_b),
+                                                        active_branch->e_start_arr[a_fork_off_inv + 1],
+                                                        comp->e_start_arr[b_fork_off_inv + 1],
+                                                        n_g_flip ^ (dist_a > dist_b));
+
+                               ED_mesh_loops_add(me, NULL, 8);
+                               ED_mesh_polys_add(me, NULL, 2);
+                               add_face(me,
+                                                me->totedge - 1,
+                                                active_branch->e_flip_side_ends[a_fork_off * 2 + 1],
+                                                me->totedge - verts_per_loop + 1,
+                                                comp->e_flip_side_ends[b_fork_off * 2 + ((dist_a > dist_b) ? 0 : 1)],
+                                                me->totloop - 8,
+                                                me->totpoly - 2,
+                                                n_g_flip ^ (dist_a > dist_b));
+
+                               add_face(me,
+                                                me->totedge - verts_per_loop + 2,
+                                                active_branch->e_flip_side_ends[a_fork_off * 2],
+                                                me->totedge - verts_per_loop * 2 + 2,
+                                                comp->e_flip_side_ends[b_fork_off * 2 + ((dist_a > dist_b) ? 1 : 0)],
+                                                me->totloop - 4,
+                                                me->totpoly - 1,
+                                                !n_g_flip ^ (dist_a > dist_b));
                        }
-                       bridge_all_parts_rec(me, spine, comp, active_branch);
+                       bridge_all_parts_rec(me, spine, comp, active_branch, verts_per_loop, n_g_flip);
                }
                if (comp) {
                        a_fork_off ++;
@@ -6204,7 +7045,7 @@ static void bridge_all_parts_rec(Mesh *me, Spine *spine, SpineBranch *active_bra
        }
 }
 
-static void bridge_all_parts(Mesh *me, Spine *spine)
+static void bridge_all_parts(Mesh *me, Spine *spine, int verts_per_loop, bool n_g_flip)
 {
        SpineBranch *active_branch = NULL;
        for (int i = 0; i < spine->totbranches; i++) {
@@ -6218,29 +7059,41 @@ static void bridge_all_parts(Mesh *me, Spine *spine)
                /* No Branches in the spine. Should not happen. */
                return;
        }
-       bridge_all_parts_rec(me, spine, active_branch, NULL);
+       bridge_all_parts_rec(me, spine, active_branch, NULL, verts_per_loop, n_g_flip);
+}
+
+static bool calc_stroke_normal_ori(SilhouetteStroke *stroke, float z_vec[3]) {
+       float n[3];
+       /*TODO: stroke points to multidimensional array*/
+       cross_poly_v3(n, (float (*)[3])stroke->points, stroke->totvert);
+       return dot_v3v3(n, z_vec) <= 0;
 }
 
 /* Generates a 3D shape from a stroke. */
 static void silhouette_create_shape_mesh(bContext *C, Mesh *me, SilhouetteData *sil, SilhouetteStroke *stroke)
 {
        float z_vec[3] = {0.0f,0.0f,1.0f};
+       float inv_z_vec[3];
        float depth = sil->depth;
-       int ss_level = 3;
+       int ss_level = sil->resolution;
        int v_steps = (1 << ss_level) + 2;
+       bool n_ori = false;
        /* TODO: RNA Init*/
 
        copy_v3_v3(z_vec, sil->z_vec);
        normalize_v3(z_vec);
 
-       //Generate spine
+       n_ori = calc_stroke_normal_ori(stroke, z_vec);
+
+       /* Generate spine */
        Spine *spine = silhouette_generate_spine(sil, stroke);
        SpineBranch *a_branch;
 
        mul_v3_fl(z_vec, depth);
+       mul_v3_v3fl(inv_z_vec, z_vec, -1.0f);
 
        int w_steps = v_steps / 2 + 2;
-       float smoothness = 0.5f;//sil->smoothness;
+       float smoothness = sil->smoothness;
 
        for (int i = 0; i < spine->totbranches; i++) {
                a_branch = spine->branches[i];
@@ -6248,19 +7101,31 @@ static void silhouette_create_shape_mesh(bContext *C, Mesh *me, SilhouetteData *
                        int r_forks = r_branch_count(spine, a_branch);
                        switch (r_forks) {
                                case 1:
-                                       add_ss_cap(sil, a_branch, me, z_vec, depth, v_steps, w_steps, smoothness);
+                                       add_ss_cap(sil, a_branch, me, z_vec, depth, v_steps, w_steps, smoothness, n_ori, false);
+                                       add_ss_cap(sil, a_branch, me, inv_z_vec, depth, v_steps, w_steps, smoothness, !n_ori, true);
+#ifdef DEBUG_DRAW
+                                       /*debug_branch(a_branch, 0x00ff00);*/
+#endif
                                        break;
                                case 2:
-                                       add_ss_tube(sil, a_branch, me, z_vec, depth, v_steps, w_steps, smoothness);
+                                       add_ss_tube(sil, a_branch, me, z_vec, depth, v_steps, w_steps, smoothness, n_ori, false);
+                                       add_ss_tube(sil, a_branch, me, inv_z_vec, depth, v_steps, w_steps, smoothness, !n_ori, true);
+#ifdef DEBUG_DRAW
+                                       /*debug_branch(a_branch, 0xff0000);*/
+#endif
                                        break;
                                case 3:
-                                       add_ss_tinter(sil, a_branch, me, z_vec, depth, v_steps, w_steps, smoothness);
+                                       add_ss_tinter(sil, spine, a_branch, me, z_vec, depth, v_steps, w_steps, smoothness, n_ori, false);
+                                       add_ss_tinter(sil, spine, a_branch, me, inv_z_vec, depth, v_steps, w_steps, smoothness, !n_ori, true);
+#ifdef DEBUG_DRAW
+                                       /*debug_branch(a_branch, 0x0000ff);*/
+#endif
                                        break;
                        }
                }
        }
 
-       bridge_all_parts(me, spine);
+       bridge_all_parts(me, spine, v_steps * 2 + w_steps, n_ori);
 
        free_spine(spine);
 
@@ -6268,25 +7133,718 @@ static void silhouette_create_shape_mesh(bContext *C, Mesh *me, SilhouetteData *
 }
 
 /* Adds additional points to the stroke if start and end are far apart. */
-static void stroke_smooth_cap(SilhouetteStroke *stroke, float max_dist)
+static void stroke_smooth_cap(SilhouetteData *sil, SilhouetteStroke *stroke, float max_dist)
 {
-       float v1[3], v2[3], dv[3];
+       float v1[2], v2[2], dv[2];
        float length = 0;
-       copy_v3_v3(v1, &stroke->points[0]);
-       copy_v3_v3(v2, &stroke->points[stroke->totvert * 3 - 3]);
+       copy_v2_v2(v1, &stroke->points_v2[0]);
+       copy_v2_v2(v2, &stroke->points_v2[stroke->totvert * 2 - 2]);
 
-       sub_v3_v3v3(dv,v1,v2);
-       length = len_v3(dv);
+       sub_v2_v2v2(dv,v1,v2);
+       length = len_v2(dv);
 
        if (length > max_dist) {
                int steps = floorf(length / (float)max_dist);
-               mul_v3_fl(dv, 1.0f / (float)steps);
+               mul_v2_fl(dv, 1.0f / (float)steps);
                for (int i = 1; i < steps; i++) {
-                       mul_v3_v3fl(v1, dv, i);
-                       add_v3_v3(v1, v2);
-                       silhouette_stroke_add_3Dpoint(stroke, v1);
+                       mul_v2_v2fl(v1, dv, i);
+                       add_v2_v2(v1, v2);
+                       silhouette_stroke_add_point(sil, stroke, v1);
+               }
+       }
+}
+
+static void remove_connected_from_edgehash(MeshElemMap *emap, GHash *edge_hash, int v) {
+       for (int e = 0; e < emap[v].count; e++) {
+               BLI_ghash_remove(edge_hash, emap[v].indices[e], NULL, NULL);
+       }
+}
+
+static bool has_cross_border_neighbour(Mesh *me, GHash *vert_hash, GHash *edge_hash, MeshElemMap *emap, int edge, int l_v_edge, int depth) {
+       int v_edge;
+
+       v_edge = me->medge[edge].v1 == l_v_edge ? me->medge[edge].v2 : me->medge[edge].v1;
+
+       if (depth == 0) {
+               return BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(v_edge));
+       } else {
+               if(!BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(v_edge))){
+                       for (int e = 0; e < emap[v_edge].count; e++) {
+                               if(emap[v_edge].indices[e] != edge) {
+                                       if(has_cross_border_neighbour(me, vert_hash, edge_hash, emap, emap[v_edge].indices[e], v_edge, depth - 1)){
+                                               return true;
+                                       }
+                               }
+                       }
+               } else {
+                       BLI_ghash_remove(edge_hash, edge, NULL, NULL);
+               }
+       }
+       return false;
+}
+
+/* Get the adjacent edge which connects the edges within the edge_hash. Used to create multiple ordered loops
+ * v_edge is the endpoint off curr_edge from which to branch off
+ * TODO: One wide strips might get cutoff */
+static int get_adjacent_edge(Mesh *me, MeshElemMap *emap, int curr_edge, int v_edge, GHash *edge_hash, GHash *vert_hash)
+{
+       for (int e = 0; e < emap[v_edge].count; e++) {
+               if(emap[v_edge].indices[e] != curr_edge && has_cross_border_neighbour(me, vert_hash, edge_hash, emap, emap[v_edge].indices[e], v_edge, 1)) {
+                       return emap[v_edge].indices[e];
+               }
+       }
+       for (int e = 0; e < emap[v_edge].count; e++) {
+               if(emap[v_edge].indices[e] != curr_edge && has_cross_border_neighbour(me, vert_hash, edge_hash, emap, emap[v_edge].indices[e], v_edge, 2)) {
+                       return emap[v_edge].indices[e];
+               }
+       }
+       /*End Of Loop. Shouldn't happen with two manifold meshes*/
+       return -1;
+}
+
+/*TODO:Remove Temp debug function*/
+static char *cd_type_name(int t)
+{
+       char *name = "";
+       switch(t) {
+               case -1 : name = "CD_AUTO_FROM_NAME      ";break;
+               case  0 : name = "CD_MVERT               ";break;
+               case  1 : name = "CD_MSTICKY             ";break;  /* DEPRECATED */
+               case  2 : name = "CD_MDEFORMVERT         ";break;
+               case  3 : name = "CD_MEDGE               ";break;
+               case  4 : name = "CD_MFACE               ";break;
+               case  5 : name = "CD_MTFACE              ";break;
+               case  6 : name = "CD_MCOL                ";break;
+               case  7 : name = "CD_ORIGINDEX           ";break;
+               case  8 : name = "CD_NORMAL          ";break;
+                       /*      CD_POLYINDEX        = 9, */
+               case 10 : name = "CD_PROP_FLT        ";break;
+               case 11 : name = "CD_PROP_INT        ";break;
+               case 12 : name = "CD_PROP_STR        ";break;
+               case 13 : name = "CD_ORIGSPACE       ";break;  /* for modifier stack face location mapping */
+               case 14 : name = "CD_ORCO            ";break;
+               case 15 : name = "CD_MTEXPOLY        ";break;
+               case 16 : name = "CD_MLOOPUV         ";break;
+               case 17 : name = "CD_MLOOPCOL        ";break;
+               case 18 : name = "CD_TANGENT         ";break;
+               case 19 : name = "CD_MDISPS          ";break;
+               case 20 : name = "CD_PREVIEW_MCOL    ";break;  /* for displaying weightpaint colors */
+                       /*      CD_ID_MCOL          = 21, */
+               case 22 : name = "CD_TEXTURE_MLOOPCOL";break;
+               case 23 : name = "CD_CLOTH_ORCO      ";break;
+               case 24 : name = "CD_RECAST          ";break;
+
+                       /* BMESH ONLY START */
+               case 25 : name = "CD_MPOLY           ";break;
+               case 26 : name = "CD_MLOOP           ";break;
+               case 27 : name = "CD_SHAPE_KEYINDEX  ";break;
+               case 28 : name = "CD_SHAPEKEY        ";break;
+               case 29 : name = "CD_BWEIGHT         ";break;
+               case 30 : name = "CD_CREASE          ";break;
+               case 31 : name = "CD_ORIGSPACE_MLOOP ";break;
+               case 32 : name = "CD_PREVIEW_MLOOPCOL";break;
+               case 33 : name = "CD_BM_ELEM_PYPTR   ";break;
+                       /* BMESH ONLY END */
+               case 34 : name = "CD_PAINT_MASK      ";break;
+               case 35 : name = "CD_GRID_PAINT_MASK ";break;
+               case 36 : name = "CD_MVERT_SKIN      ";break;
+               case 37 : name = "CD_FREESTYLE_EDGE  ";break;
+               case 38 : name = "CD_FREESTYLE_FACE  ";break;
+               case 39 : name = "CD_MLOOPTANGENT    ";break;
+               case 40 : name = "CD_TESSLOOPNORMAL  ";break;
+               case 41 : name = "CD_CUSTOMLOOPNORMAL";break;
+
+               case 42 : name = "CD_NUMTYPES        ";break;
+               default: name = "No Name";
+       }
+       return name;
+}
+
+#if 0
+static void debug_cd(Mesh *me)
+{
+       char *name = "";
+       printf("Debugging Custom Data:\n\n");
+       printf("%i Customdata Layers in vdata\n", CustomData_number_of_layers_typemask(&me->vdata, CD_MASK_EVERYTHING));
+       printf("%i Customdata Layers in edata\n", CustomData_number_of_layers_typemask(&me->edata, CD_MASK_EVERYTHING));
+       printf("%i Customdata Layers in ldata\n", CustomData_number_of_layers_typemask(&me->ldata, CD_MASK_EVERYTHING));
+       printf("%i Customdata Layers in pdata\n", CustomData_number_of_layers_typemask(&me->pdata, CD_MASK_EVERYTHING));
+       for (int i = 0; i < CustomData_number_of_layers_typemask(&me->vdata, CD_MASK_EVERYTHING); i++) {
+               name = cd_type_name(me->vdata.layers[i].type);
+               printf("Layer found with name %s\n", name);
+       }
+       for (int i = 0; i < CustomData_number_of_layers_typemask(&me->edata, CD_MASK_EVERYTHING); i++) {
+               name = cd_type_name(me->edata.layers[i].type);
+               printf("Layer found with name %s\n", name);
+       }
+       for (int i = 0; i < CustomData_number_of_layers_typemask(&me->ldata, CD_MASK_EVERYTHING); i++) {
+               name = cd_type_name(me->ldata.layers[i].type);
+               printf("Layer found with name %s\n", name);
+       }
+       for (int i = 0; i < CustomData_number_of_layers_typemask(&me->pdata, CD_MASK_EVERYTHING); i++) {
+               name = cd_type_name(me->pdata.layers[i].type);
+               printf("Layer found with name %s\n", name);
+       }
+}
+#endif
+
+/* Copy customdata from source to destination. Layers need to be matching!
+ * redirect_map needs to be the new positions ofelements in the dest array. -1 marks elements which do not get copied over. */
+static void CustomData_copy_partial(const struct CustomData *source, struct CustomData *dest, CustomDataMask mask, int *redirect_map, int tot_elem)
+{
+       int num_layers_to_copy;
+       int d_size;
+       CustomDataLayer *curr_l, *dest_l;
+       char *name;
+
+       num_layers_to_copy = CustomData_number_of_layers_typemask(source, mask);
+
+       for (int l = 0; l < num_layers_to_copy; l++) {
+               curr_l = &source->layers[l];
+               dest_l = &dest->layers[l];
+               if (CD_TYPE_AS_MASK(curr_l->type) & mask) {
+                       for (int i = 0; i < tot_elem; i++) {
+                               if(redirect_map[i] != -1) {
+                                       d_size = CustomData_sizeof(curr_l->type);
+                                       memcpy(dest_l->data + redirect_map[i] * d_size, curr_l->data + i * d_size, d_size);
+                               }
+                       }
+                       name = cd_type_name(curr_l->type);
+                       printf("Layer %s copied %i values of size %i.\n", name, tot_elem, CustomData_sizeof(curr_l->type));
+               }
+       }
+}
+
+/* Function used to remove vertices from a basic mesh
+ * Can be optimised easily be introucing multithreading
+ * Parts and ideas how multithreading can be introduced are marked with "MT:"
+ * TODO: Add Multithreading */
+static void remove_verts_from_mesh(Mesh *me, int *v_to_rm, int num_v_to_rm){
+       int *v_rd_table, *e_rd_table, *l_rd_table, *p_rd_table;
+       int next_del = 0, next_del_pos = 0;
+       MEdge e;
+       MLoop l;
+       MPoly p;
+
+       int n_totvert, n_totedge, n_totloop, n_totpoly;
+
+       CustomData vdata, edata, ldata, pdata;
+
+       /* MT: Prefix Sum / Scan to calculate new positions for vertices.
+        * Calculating the new positions with the vertices removed
+        */
+       v_rd_table = MEM_callocN(sizeof(int) * me->totvert, "Vertex redirect table");
+
+       qsort(v_to_rm, num_v_to_rm, sizeof(int), cmpfunc);
+
+       n_totvert = 0;
+       next_del = v_to_rm[0];
+       for (int i = 0; i < me->totvert; i++) {
+               if (i == next_del) {
+                       if (next_del_pos + 1 < num_v_to_rm) {
+                               next_del_pos ++;
+                               next_del = v_to_rm[next_del_pos];
+                       }
+                       v_rd_table[i] = -1;
+               } else {
+                       v_rd_table[i] = n_totvert;
+                       n_totvert ++;
+               }
+       }
+
+       /* MT: parallelize loop, !shared access to sum value
+        * Calculate new edge positions + remap vertice pointer
+        */
+       e_rd_table = MEM_callocN(sizeof(int) * me->totedge, "Edge redirect table");
+       n_totedge = 0;
+       for (int i = 0; i < me->totedge; i++) {
+               e = me->medge[i];
+               if(v_rd_table[e.v1] == -1 || v_rd_table[e.v2] == -1) {
+                       e_rd_table[i] = -1;
+               } else {
+                       e.v1 = v_rd_table[e.v1];
+                       e.v2 = v_rd_table[e.v2];
+                       me->medge[i] = e;
+                       e_rd_table[i] = n_totedge;
+                       n_totedge ++;
+               }
+       }
+
+       /* MT: same as above
+        * Calculate new loop positions + remap edge pointers */
+       l_rd_table = MEM_callocN(sizeof(int) * me->totloop, "Loop redirect table");
+       n_totloop = 0;
+       for (int i = 0; i < me->totloop; i++) {
+               l = me->mloop[i];
+               if(v_rd_table[l.v] == -1 || e_rd_table[l.e] == -1) {
+                       l_rd_table[i] = -1;
+               } else {
+                       l.v = v_rd_table[l.v];
+                       l.e = e_rd_table[l.e];
+                       me->mloop[i] = l;
+                       l_rd_table[i] = n_totloop;
+                       n_totloop ++;
+               }
+       }
+
+       /* MT: same as above
+        * Calculate new poly positions + remap pointers */
+       p_rd_table = MEM_callocN(sizeof(int) * me->totpoly, "Poly redirect table");
+       n_totpoly = 0;
+       for (int i = 0; i < me->totpoly; i++) {
+               p = me->mpoly[i];
+               for(int l = p.loopstart; l < p.loopstart + p.totloop; l++){
+                       if(l_rd_table[l] == -1) {
+                               p_rd_table[i] = -1;
+                               /* TODO: Bad practise? easily solved other way*/
+                               goto skip_poly;
+                       }
+               }
+               me->mpoly[i].loopstart = l_rd_table[me->mpoly[i].loopstart];
+               p_rd_table[i] = n_totpoly;
+               n_totpoly ++;
+               skip_poly:;
+       }
+
+       /*Redirection tables are done. Continue to copy and allocate new Customdata blocks*/
+       CustomData_copy(&me->vdata, &vdata, CD_MASK_EVERYTHING, CD_CALLOC, n_totvert);
+       CustomData_copy(&me->edata, &edata, CD_MASK_EVERYTHING, CD_CALLOC, n_totedge);
+       CustomData_copy(&me->ldata, &ldata, CD_MASK_EVERYTHING, CD_CALLOC, n_totloop);
+       CustomData_copy(&me->pdata, &pdata, CD_MASK_EVERYTHING, CD_CALLOC, n_totpoly);
+
+       CustomData_copy_partial(&me->vdata, &vdata, CD_MASK_EVERYTHING, v_rd_table, me->totvert);
+       CustomData_copy_partial(&me->edata, &edata, CD_MASK_EVERYTHING, e_rd_table, me->totedge);
+       CustomData_copy_partial(&me->ldata, &ldata, CD_MASK_EVERYTHING, l_rd_table, me->totloop);
+       CustomData_copy_partial(&me->pdata, &pdata, CD_MASK_EVERYTHING, p_rd_table, me->totpoly);
+
+       CustomData_free(&me->vdata, me->totvert);
+       CustomData_free(&me->edata, me->totedge);
+       CustomData_free(&me->ldata, me->totloop);
+       CustomData_free(&me->pdata, me->totpoly);
+
+       me->vdata = vdata;
+       me->edata = edata;
+       me->ldata = ldata;
+       me->pdata = pdata;
+
+       me->totvert = n_totvert;
+       me->totedge = n_totedge;
+       me->totloop = n_totloop;
+       me->totpoly = n_totpoly;
+
+
+       BKE_mesh_update_customdata_pointers(me, true);
+}
+
+static void calc_ring_bbs(SilhouetteData *sil, Mesh *me)
+{
+       int len, edge;
+       BB *curr;
+       sil->fillet_ring_bbs = MEM_callocN(sizeof(BB) * sil->num_rings, "ring bb mem");
+
+       for (int r = 0; r < sil->num_rings; r++) {
+               len = r + 1 < sil->num_rings ? sil->fillet_ring_new_start[r + 1] - sil->fillet_ring_new_start[r] : sil->fillet_ring_tot - sil->fillet_ring_new_start[r];
+               curr = &sil->fillet_ring_bbs[r];
+               BB_reset(curr);
+               for (int e = 0; e < len; e++) {
+                       edge = sil->fillet_ring_new[sil->fillet_ring_new_start[r] + e];
+                       BB_expand(curr, me->mvert[me->medge[edge].v1].co);
+                       BB_expand(curr, me->mvert[me->medge[edge].v2].co);
+               }
+       }
+}
+
+/* We calculate a start and an endpoint of the two node ends intersecting. Now we need to determine the right side on which the intersection happens 
+ * Returning the points in correct order (positive looping results in inner side);
+ */
+static void order_positive_is_inside(Mesh *me, SilhouetteData *sil, MeshElemMap *emap, int *r11, int *r12, int r1_start, int r1_tot, int r2_start, int r2_tot)
+{
+       int dist_1;
+       int center;
+       int comp_v1, comp_v2;
+       int comp_e;
+       int tmp_swap;
+       if (*r11 > *r12) {
+               dist_1 = r1_tot - *r11 + *r12;
+       } else {
+               dist_1 = *r12 - *r11;
+       }
+
+       center = r1_start + (*r11 + (dist_1 / 2)) % r1_tot;
+       comp_v1 = me->medge[sil->fillet_ring_new[center]].v2;
+
+       for (int e = 0; e < emap[comp_v1].count; e++) {
+               comp_e = emap[comp_v1].indices[e];
+               if (comp_e != sil->fillet_ring_new[center] && comp_e != sil->fillet_ring_new[center + 1] && comp_e != sil->fillet_ring_new[center - 1]) {
+                       comp_v2 = me->medge[comp_e].v1 == comp_v1 ? me->medge[comp_e].v2 : me->medge[comp_e].v1;
+                       for (int e_l = 0; e_l < r2_tot; e_l ++) {
+                               if (me->medge[sil->fillet_ring_new[r2_start + e_l]].v2 == comp_v2) {
+                                       return;
+                               }
+                       }
+               }
+       }
+       tmp_swap = *r11;
+       *r11 = *r12;
+       *r12 = tmp_swap;
+       return;
+}
+
+typedef enum MergeRingFlag {
+       ADDED_TO_MERGE = 1,
+} MergeRingFlag;
+
+
+typedef struct MergeRingInfo {
+       int r1;
+       int r2;
+       int r1_start;
+       int r2_start;
+       int r1_tot;
+       int r2_tot;
+       int r1_e_a;
+       int r1_e_b;
+       int r2_e_a;
+       int r2_e_b;
+       int flag;
+} MergeRingInfo;
+
+static void join_node_separated_rings(SilhouetteData *sil, Mesh *me, MeshElemMap *emap)
+{
+       MergeRingInfo *merge_info = NULL;
+       int *merged_to_one = NULL;
+       MEdge e1_c, e2_c;
+       MergeRingInfo t_m_info;
+
+       BLI_array_declare(merge_info);
+
+       printf("Joining rings. In total %i rings to check.\n", sil->num_rings);
+       for (int r1 = 0; r1 < sil->num_rings - 1; r1++) {
+               for (int r2 = r1 + 1; r2 < sil->num_rings; r2++) {
+                       if (bb_intersect(&sil->fillet_ring_bbs[r1], &sil->fillet_ring_bbs[r2])) {
+                               t_m_info.r1_start = sil->fillet_ring_new_start[r1];
+                               t_m_info.r2_start = sil->fillet_ring_new_start[r2];
+                               t_m_info.r1_tot = sil->fillet_ring_new_start[r1 + 1] - t_m_info.r1_start;
+                               t_m_info.r2_tot = r2 + 1 < sil->num_rings ? sil->fillet_ring_new_start[r2 + 1] - t_m_info.r2_start : sil->fillet_ring_tot - t_m_info.r2_start;
+                               t_m_info.r1_e_a = -1, t_m_info.r1_e_b = -1, t_m_info.r2_e_a = -1, t_m_info.r2_e_b = -1;
+                               for (int e1 = 0; e1 < t_m_info.r1_tot; e1++) {
+                                       e1_c = me->medge[sil->fillet_ring_new[t_m_info.r1_start + e1]];
+                                       for (int e2 = 0; e2 < t_m_info.r2_tot; e2++) {
+                                               e2_c = me->medge[sil->fillet_ring_new[t_m_info.r2_start + e2]];
+                                               if (e1_c.v1 == e2_c.v1 || e1_c.v1 == e2_c.v2 || e1_c.v2 == e2_c.v1 || e1_c.v2 == e2_c.v2) {
+                                                       if (t_m_info.r1_e_a == -1) {
+                                                               t_m_info.r1_e_a = e1;
+                                                               t_m_info.r2_e_a = e2;
+                                                       } else {
+                                                               if (abs(t_m_info.r1_e_a - e1) > 3) {
+                                                                       t_m_info.r1_e_b = e1;
+                                                                       t_m_info.r2_e_b = e2;
+                                                                       /* Found start and endpoint of the two ring intersections */
+                                                                       order_positive_is_inside(me, sil, emap, &t_m_info.r1_e_a, &t_m_info.r1_e_b, t_m_info.r1_start, t_m_info.r1_tot, t_m_info.r2_start, t_m_info.r2_tot);
+                                                                       order_positive_is_inside(me, sil, emap, &t_m_info.r2_e_a, &t_m_info.r2_e_b, t_m_info.r2_start, t_m_info.r2_tot, t_m_info.r1_start, t_m_info.r1_tot);
+
+                                                                       BLI_array_append(merge_info, t_m_info);
+#ifdef DEBUG_DRAW
+                                                                       bl_debug_color_set(0xffffff);
+                                                                       bl_debug_draw_point(me->mvert[me->medge[sil->fillet_ring_new[t_m_info.r1_start + t_m_info.r1_e_a]].v1].co, 0.2f);
+                                                                       bl_debug_color_set(0x000000);
+                                                                       bl_debug_draw_point(me->mvert[me->medge[sil->fillet_ring_new[t_m_info.r1_start + t_m_info.r1_e_b]].v1].co, 0.3f);
+                                                                       bl_debug_color_set(0x000000);
+
+                                                                       bl_debug_color_set(0x00ff00);
+                                                                       for (int e_ins = 0; e_ins < t_m_info.r1_tot; e_ins ++) {
+                                                                               if((t_m_info.r1_e_a + e_ins) % t_m_info.r1_tot == t_m_info.r1_e_b) {
+                                                                                       bl_debug_color_set(0x000000);
+                                                                                       break;
+                                                                               }
+                                                                               bl_debug_draw_medge_add(me, sil->fillet_ring_new[t_m_info.r1_start + (t_m_info.r1_e_a + e_ins) % t_m_info.r1_tot]);
+                                                                       }
+                                                                       bl_debug_color_set(0x000000);
+#endif 
+                                                                       /* TODO: Is this a bad coding practise?
+                                                                        * Maybe:
+                                                                        * e1 = r1_tot;
+                                                                        * e2 = r2_tot;
+                                                                        * r2++;
+                                                                        */
+                                                                       goto next_ring;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       /* Continue with the next ring */
+                       next_ring:;
+               }
+       }
+
+       BLI_array_declare(merged_to_one);
+       for (int i = 0; i < BLI_array_count(merge_info); i++) {
+               if (!merge_info[i].flag & ADDED_TO_MERGE) {
+                       BLI_array_append(merged_to_one, merge_info[0].r1);
+                       merge_info[0].flag |= ADDED_TO_MERGE;
+                       for (int j = i; j < BLI_array_count(merge_info); j++) {
+                               for (int k = 0; k < BLI_array_count(merged_to_one); k++) {
+
+                               }
+                       }
                }
        }
+       BLI_array_free(merged_to_one);
+       BLI_array_free(merge_info);
+}
+
+static void prep_int_shared_mem(int **mem, int *r_num, int *r_start, int len, const char *str)
+{
+       if (!mem) {
+               *r_start = 0;
+               *mem = MEM_callocN(sizeof(int) * len, str);
+               *r_num = len;
+       } else {
+               *r_start = *r_num;
+               *r_num = *r_num + len;
+               *mem = MEM_reallocN(*mem, sizeof(int) * (*r_num));
+       }
+}
+
+/* Calculate the intersections with existing geometry. Used to connect the new Silhouette to the old mesh
+ * Fillets are the smooth transition from one part to another.
+ */
+static void do_calc_fillet_line_task_cb_ex(void *userdata, void *UNUSED(userdata_chunk), const int n, const int UNUSED(thread_id))
+{
+       SculptThreadedTaskData *data = userdata;
+       SculptSession *ss = data->ob->sculpt;
+       SilhouetteData *sil = data->sil;
+       Mesh *me = data->ob->data;
+       PBVHNode *curr_node = data->nodes[n];
+
+       PBVHVertexIter vd;
+       float point[2];
+       float sil_plane[4];
+       float fuzz;
+       MEdge e_comp;
+       int v_i, vd_i;
+       GHash *vert_hash = BLI_ghash_int_new("vertices within intersection");
+       GHash *edge_hash = BLI_ghash_int_new("edges on the intersection");
+       int *edge_ring_fillet = NULL;
+       int *ring_start = NULL;
+       int v_rm_start_in_shared_arr = 0, int_e_start_in_shared_arr = 0, fillet_edge_ring_start_shared_arr = 0, fillet_ring_start_start_shared_arr = 0;
+       int r_size;
+       BLI_array_declare(edge_ring_fillet);
+       BLI_array_declare(ring_start);
+       int comp_v, idx;
+
+       /*GHashIterState state;*/
+       GHashIterator gh_iter;
+       int curr_edge = -1, last_edge = -1, start_edge = -1, tmp_curr_edge = -1;
+
+       plane_from_point_normal_v3(sil_plane, sil->anchor, sil->z_vec);
+
+       /* TODO: Is this a unique vert iteration? If not edges might be added twice by different threads */
+       BKE_pbvh_vertex_iter_begin(ss->pbvh, curr_node, vd, PBVH_ITER_UNIQUE)
+       {
+               /* get the interior vertices of the 2d drawn silhouette and all relevant vertices 
+                * Ignores smoothness, assuming the smoothness blures the fillets anyways it should be ok. */
+               fuzz = SIL_FILLET_BLUR_MIN + sil->smoothness * 0.01f * SIL_FILLET_BLUR_MAX;
+               if (dist_squared_to_plane_v3(vd.co, sil_plane) <= sil->depth + fuzz) {
+                       if (!BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(vd.vert_indices[vd.i]))) {
+                               ED_view3d_project_float_v2_m4(sil->ar, vd.co, point, data->mat);
+                               if (isect_point_poly_v2(point, (float(*)[2])sil->current_stroke->points_v2, sil->current_stroke->totvert, false)){
+                                       if (!BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(vd.vert_indices[vd.i]))) {
+                                               BLI_ghash_insert(vert_hash, SET_INT_IN_POINTER(vd.vert_indices[vd.i]), SET_INT_IN_POINTER(vd.vert_indices[vd.i]));
+                                               vd_i = vd.vert_indices[vd.i];
+                                               for (int e = 0; e < sil->emap[vd_i].count; e++){
+                                                       e_comp = me->medge[sil->emap[vd_i].indices[e]];
+                                                       v_i = e_comp.v1 == vd_i ? e_comp.v2 : e_comp.v1;
+                                                       if (!BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(v_i)))
+                                                       {
+                                                               ED_view3d_project_float_v2_m4(sil->ar, me->mvert[v_i].co, point, data->mat);
+                                                               if (!isect_point_poly_v2(point, (float(*)[2])sil->current_stroke->points_v2, sil->current_stroke->totvert, false) || dist_squared_to_plane_v3(me->mvert[v_i].co, sil_plane) > sil->depth + fuzz) {
+                                                                       BLI_ghash_insert(edge_hash, SET_INT_IN_POINTER(sil->emap[vd_i].indices[e]), SET_INT_IN_POINTER(sil->emap[vd_i].indices[e]));
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       BKE_pbvh_vertex_iter_end;
+
+       /* Finished writing all vertices which are within the intersection and need to be removed.
+        * write them to the shared array. Lock the mutex to avoid collisions */
+       BLI_mutex_lock(&data->mutex);
+       prep_int_shared_mem(&data->v_to_rm, &data->num_v_to_rm, &v_rm_start_in_shared_arr, BLI_ghash_size(vert_hash), "verts to remove");
+       prep_int_shared_mem(&sil->inter_edges, &sil->num_inter_edges, &int_e_start_in_shared_arr, BLI_ghash_size(edge_hash), "edges on transition");
+
+       /* Copy vertice data over.*/
+       GHASH_ITER_INDEX (gh_iter, vert_hash, idx) {
+               data->v_to_rm[v_rm_start_in_shared_arr + idx] = BLI_ghashIterator_getKey(&gh_iter);
+       }
+
+       /* Copy edge data over. */
+       GHASH_ITER_INDEX (gh_iter, edge_hash, idx) {
+               sil->inter_edges[int_e_start_in_shared_arr + idx] = BLI_ghashIterator_getKey(&gh_iter);
+       }
+       BLI_mutex_unlock(&data->mutex);
+
+       /* TODO: Workaround, do a BLI_ghash_pop style while loop
+        * TODO: A adjacency search might fail if there is not a single path to be searched, shouldn't be a problem on first thought though.
+        * Breaker is a anti crash method in case the algorithm gets caught in an endless loop. Shouldn't happen!*/
+       int breaker;
+       int debug_test_v;
+       do {
+               breaker = me->totedge;
+               BLI_ghashIterator_init(&gh_iter, edge_hash);
+               if(!BLI_ghashIterator_done(&gh_iter)){
+                       start_edge = BLI_ghashIterator_getValue(&gh_iter);
+                       BLI_ghash_remove(edge_hash, start_edge, NULL, NULL);
+                       comp_v = BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(me->medge[start_edge].v1)) ? me->medge[start_edge].v2 : me->medge[start_edge].v1;
+                       debug_test_v = comp_v;
+                       BLI_assert(!BLI_ghash_haskey(vert_hash, SET_INT_IN_POINTER(comp_v)));
+                       start_edge = get_adjacent_edge(me, sil->emap, start_edge, comp_v, edge_hash, vert_hash);
+                       if(start_edge >= 0) {
+                               BLI_array_append(ring_start, BLI_array_count(edge_ring_fillet));
+                               curr_edge = start_edge;
+                               last_edge = -1;
+
+                               while(!(curr_edge == start_edge && last_edge != -1) && curr_edge != -1 && breaker > 0) {
+                                       BLI_array_append(edge_ring_fillet, curr_edge);
+                                       if(last_edge == -1) {
+                                               comp_v = me->medge[start_edge].v1;
+                                       } else {
+                                               if (me->medge[curr_edge].v1 == me->medge[last_edge].v1 || me->medge[curr_edge].v1 == me->medge[last_edge].v2) {
+                                                       comp_v = me->medge[curr_edge].v2;
+                                               } else {
+                                                       comp_v = me->medge[curr_edge].v1;
+                                               }
+                                       }
+                                       remove_connected_from_edgehash(sil->emap, edge_hash, comp_v);
+                                       tmp_curr_edge = get_adjacent_edge(me, sil->emap, curr_edge, comp_v, edge_hash, vert_hash);
+                                       last_edge = curr_edge;
+                                       curr_edge = tmp_curr_edge;
+                                       breaker --;
+                               }
+                               printf("Found a cut loop!\n");
+                               BLI_assert(breaker > 0);
+                               /* TODO: Bug shouldn't reach but does on some occasion.*/
+                               if (breaker == 0) {
+                                       BLI_array_empty(edge_ring_fillet);
+#ifdef DEBUG_DRAW
+
+                                       bl_debug_color_set(0x00ff00);
+                                       bl_debug_draw_point(me->mvert[debug_test_v].co, 0.2f);
+                                       bl_debug_draw_medge_add(me, start_edge);
+                                       bl_debug_color_set(0x000000);
+#endif
+                               }
+                       }
+               }
+       } while (!BLI_ghashIterator_done(&gh_iter));
+
+       /* Prep ring memory*/
+       BLI_mutex_lock(&data->mutex);
+       prep_int_shared_mem(&sil->fillet_ring_new, &sil->fillet_ring_tot, &fillet_edge_ring_start_shared_arr, BLI_array_count(edge_ring_fillet), "edges on transition");
+       prep_int_shared_mem(&sil->fillet_ring_new_start, &sil->num_rings, &fillet_ring_start_start_shared_arr, BLI_array_count(ring_start), "start of individual rings");
+
+       /* Copy ring memory */
+       for (int i = 0; i < BLI_array_count(edge_ring_fillet); i++) {
+               sil->fillet_ring_new[fillet_edge_ring_start_shared_arr + i] = edge_ring_fillet[i];
+       }
+       /* Offset start pointers to account chunks beforehand */
+       for (int i = 0; i < BLI_array_count(ring_start); i++) {
+               sil->fillet_ring_new_start[fillet_ring_start_start_shared_arr + i] = ring_start[i] + fillet_edge_ring_start_shared_arr;
+       }
+       BLI_mutex_unlock(&data->mutex);
+
+       /*TODO: merge rings from multiple threads / nodes*/
+#ifdef DEBUG_DRAW
+       for(int r = 0; r < BLI_array_count(ring_start); r++) {
+               r_size = r < BLI_array_count(ring_start) - 1 ? ring_start[r + 1] - ring_start[r] : BLI_array_count(edge_ring_fillet) - ring_start[r];
+               for(int i = 0; i < r_size; i++) {
+                       if(i == 0){
+                               bl_debug_color_set(0x00ffff);
+                       } else {
+                               bl_debug_color_set(0xff00ff);
+                       }
+                       bl_debug_draw_medge_add(me, edge_ring_fillet[ring_start[r] + i]);
+                       bl_debug_color_set(0x000000);
+               }
+       }
+#endif
+       BLI_array_free(ring_start);
+       BLI_array_free(edge_ring_fillet);
+       BLI_ghash_free(vert_hash, NULL, NULL);
+       BLI_ghash_free(edge_hash, NULL, NULL);
+}
+
+static void do_calc_fillet_line(Object *ob, SilhouetteData *silhouette, PBVHNode **nodes, int totnode)
+{
+       Mesh *me = ob->data;
+       float projmat[4][4];
+       MeshElemMap *emap;
+       int *emap_mem;
+       int *v_remove = NULL;
+       RegionView3D *rv3d;
+       View3D *v3d;
+       /*rctf viewplane;
+       float clipend;
+       float clipnear;*/
+
+       rv3d = silhouette->ar->regiondata;
+       v3d = silhouette->vc.v3d;
+
+       BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->medge, me->totvert, me->totedge);
+       silhouette->emap = emap;
+       /* calc the projection matrix used to convert 3d vertice in 2d space */
+       mul_m4_m4m4(projmat, (float (*)[4])rv3d->persmat, ob->obmat);
+       /* TODO: Orthographic projection:
+       ED_view3d_ob_project_mat_get(silhouette->ar->regiondata, ob, projmat);
+
+       float vmat[4][4], winmat[4][4];;
+
+
+       mul_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, ob->obmat);
+       mul_m4_m4m4(projmat, (float (*)[4])rv3d->persmat, ob->obmat);
+
+       ED_view3d_viewplane_get(v3d, rv3d, silhouette->ar->winx, silhouette->ar->winy, &viewplane, &clipnear, &clipend, NULL);
+       orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
+
+       mul_m4_m4m4(vmat, (float (*)[4])rv3d->viewmat, ob->obmat);
+       mul_m4_m4m4(projmat, winmat, vmat);*/
+
+       /* threaded loop over nodes */
+       SculptThreadedTaskData data = {
+               .ob = ob, .nodes = nodes,
+               .sil = silhouette, .mat = projmat, .v_to_rm = v_remove
+       };
+
+       BLI_task_parallel_range_ex(
+                                                          0, totnode, &data, NULL, 0, do_calc_fillet_line_task_cb_ex,
+                                                          (totnode > SCULPT_THREADED_LIMIT), false);
+
+       v_remove = data.v_to_rm;
+
+       calc_ring_bbs(silhouette, me);
+
+#ifdef DEBUG_DRAW
+       for (int r = 0; r < silhouette->num_rings; r ++) {
+               bl_debug_draw_BB_add(&silhouette->fillet_ring_bbs[r], 0x0000ff);
+       }
+#endif
+
+       /*TODO: Join multiple parts together when totnode > 1.*/
+       join_node_separated_rings(silhouette, me, emap);
+
+       if (v_remove) {
+               printf("Removing vertices/edges/loops/polys from mesh.\n");
+               remove_verts_from_mesh(me, v_remove, data.num_v_to_rm);
+               MEM_freeN(v_remove);
+       }
+
+       MEM_freeN(emap);
+       MEM_freeN(emap_mem);
 }
 
 static void sculpt_silhouette_calc_mesh(bContext *C, wmOperator *op)
@@ -6295,27 +7853,52 @@ static void sculpt_silhouette_calc_mesh(bContext *C, wmOperator *op)
        Object *ob = CTX_data_active_object(C);
        SilhouetteData *sil = op->customdata;
        Mesh *me = ob->data;
+       /*Sculpt *sd = CTX_data_tool_settings(C)->sculpt;*/
+       SculptSession *ss = ob->sculpt;
+       SculptSearchBBData data;
+       PBVHNode **nodes = NULL;
 
        SilhouetteStroke *stroke = sil->current_stroke;
-       stroke_smooth_cap(stroke, 0.3f);
+
+       stroke_smooth_cap(sil, stroke, 10.0f);
+
+       int totnode;
+
+       data.ss = ss;
+       data.bb_target = &stroke->bb;
+       /* get the pbvh nodes intersecting the silhouette BB */
+       BKE_pbvh_search_gather(ss->pbvh, sculpt_search_BB_cb, &data, &nodes, &totnode);
+
+       /* Only act if some verts are inside the silhouette drawn */
+       if (totnode) {
+               printf("Connect to geometry\n");
+               do_calc_fillet_line(ob, sil, nodes, totnode);
+       }
 
        silhouette_create_shape_mesh(C, me, sil, stroke);
 
-       /* Rebuild mesh caches 
+       /* Rebuild mesh caches
         * TODO: Proper PBVH etc. */
+
+       BKE_mesh_calc_edges(me, false, true);
+       BKE_mesh_tessface_clear(me);
+       BKE_mesh_calc_normals(me);
+       DAG_id_tag_update(&me->id, 0);
+       WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+
        BKE_object_free_derived_caches(ob);
 }
 
 static void sculpt_silhouette_stroke_done(bContext *UNUSED(C), wmOperator *op)
 {
+#ifdef DEBUG_DRAW
        SilhouetteData *sil = op->customdata;
 
-#ifdef DEBUG_DRAW
        for (int i = 1; i < sil->current_stroke->totvert; i ++) {
                float v1[3], v2[3];
                copy_v3_v3(v1, &sil->current_stroke->points[i * 3 - 3]);
                copy_v3_v3(v2, &sil->current_stroke->points[i * 3]);
-               bl_debug_draw_edge_add(v1,v2);
+               /*bl_debug_draw_edge_add(v1,v2);*/
        }
 #endif
        
@@ -6335,13 +7918,30 @@ static void sculpt_silhouette_clean_draw(bContext *C, wmOperator *op)
 
 static int sculpt_silhouette_exec(bContext *C, wmOperator *op)
 {
+       int v_start, e_start, l_start, p_start;
        SilhouetteData *sil = op->customdata;
+       Object *ob = CTX_data_active_object(C);
+       Mesh *me = ob->data;
+
        if (!sil) {
-               sil = silhouette_data_new(C, op, true);
+               sil = silhouette_data_new(C);
+               silhouette_set_ref_plane(sil);
                op->customdata = sil;
        }
-       sculpt_silhouette_calc_mesh(C, op);
-       sculpt_silhouette_stroke_done(C, op);
+
+       /*TODO: Add undo for fillets etc*/
+       if (sil->current_stroke->totvert > 3) {
+               /*sculpt_undo_push_begin("draw Silhouette");*/
+               v_start = me->totvert;
+               e_start = me->totedge;
+               l_start = me->totloop;
+               p_start = me->totpoly;
+               sculpt_silhouette_calc_mesh(C, op);
+               sculpt_silhouette_stroke_done(C, op);
+
+               /*sculpt_undo_silhouette_push(ob, v_start, e_start, l_start, p_start);
+               sculpt_undo_push_end(C);*/
+       }
 
        return OPERATOR_FINISHED;
 }
@@ -6349,24 +7949,19 @@ static int sculpt_silhouette_exec(bContext *C, wmOperator *op)
 static int sculpt_silhouette_modal(bContext *C, wmOperator *op, const wmEvent *event)
 {
        float mouse[2];
-       float z_vec[3];
        SilhouetteData *sil = op->customdata;
        copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
        printf(".");
        if (event->val == KM_RELEASE) {
                sculpt_silhouette_clean_draw(C, op);
                if (sil->state == SIL_DRAWING) {
-                       /*RNA_float_set_array(op->ptr, "points", sil->current_stroke->points);*/
-                       RNA_int_set(op->ptr,"totvert", sil->current_stroke->totvert);
-                       ED_view3d_global_to_vector(sil->ar->regiondata, (float[3]){0.0f,0.0f,0.0f}, z_vec);
-                       RNA_float_set_array(op->ptr, "z_vec", z_vec);
-                       RNA_float_set_array(op->ptr, "anchor", sil->anchor);
+                       silhouette_set_ref_plane(sil);
                        return sculpt_silhouette_exec(C, op);
                }
                return OPERATOR_FINISHED;
        } else {
                if (sil->state == SIL_DRAWING) {
-                       sculpt_silhouette_stroke_update(C,mouse,op->customdata);
+                       sculpt_silhouette_stroke_update(mouse, op->customdata);
                }
                return OPERATOR_RUNNING_MODAL;
        }
@@ -6411,7 +8006,7 @@ static int sculpt_silhouette_invoke(bContext *C, wmOperator *op, const wmEvent *
 
        SilhouetteData *sil_data;
 
-       sil_data = silhouette_data_new(C, op, false);
+       sil_data = silhouette_data_new(C);
 
        op->customdata = sil_data;
 
@@ -6435,8 +8030,6 @@ static int sculpt_silhouette_poll(bContext *UNUSED(C))
 
 static void SCULPT_OT_silhouette_draw(wmOperatorType *ot)
 {
-       PropertyRNA *prop;
-
        /* identifiers */
        ot->name = "Draw Silhouette";
        ot->idname = "SCULPT_OT_silhouette_draw";
@@ -6450,32 +8043,7 @@ static void SCULPT_OT_silhouette_draw(wmOperatorType *ot)
        ot->cancel = sculpt_silhouette_stroke_done;
 
        /* flags */
-       ot->flag = OPTYPE_BLOCKING | OPTYPE_REGISTER | OPTYPE_UNDO;
-
-       /* properties */
-       prop = RNA_def_int(ot->srna, "ss_level", 3, 1, 16, "Subsurface Level", "", 1, 8);
-       RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
-       prop = RNA_def_float(ot->srna, "depth", 1.5f, 0.0f, 100000000.0f,
-                                                "Depth", "Shape depth", 0.0f, 100.0f);
-       RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
-       prop = RNA_def_float(ot->srna, "smoothness", 0.75f, 0.0f, 1.0f,
-                                                "Smoothness", "Smoothness factor", 0.0f, 1.0f);
-       RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
-       /* TODO: RNA points max size 30 */
-       /*prop = RNA_def_float_vector(ot->srna, "points", 3 * 1024, NULL, -FLT_MAX, FLT_MAX, "3D Points", "Stroke Mouse locations", -FLT_MAX, FLT_MAX);
-       RNA_def_property_flag(prop, PROP_HIDDEN);*/
-
-       prop = RNA_def_int(ot->srna, "totvert", 0, 0, INT_MAX, "stroke point count", "", 0, INT_MAX);
-       RNA_def_property_flag(prop, PROP_HIDDEN);
-
-       prop = RNA_def_float_vector(ot->srna, "z_vec", 3, NULL, -FLT_MAX, FLT_MAX, "Z Vector", "Silhouette orientation", -FLT_MAX, FLT_MAX);
-       RNA_def_property_flag(prop, PROP_HIDDEN);
-
-       prop = RNA_def_float_vector(ot->srna, "anchor", 3, NULL, -FLT_MAX, FLT_MAX, "Anchor", "Silhouette position", -FLT_MAX, FLT_MAX);
-       RNA_def_property_flag(prop, PROP_HIDDEN);
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 /* end Silhouette */