Merge branch 'master' into soc-2017-sculpting_improvements
authorwitt <sebastian.witt@rwth-aachen.de>
Mon, 12 Jun 2017 08:12:49 +0000 (10:12 +0200)
committerwitt <sebastian.witt@rwth-aachen.de>
Mon, 12 Jun 2017 08:12:49 +0000 (10:12 +0200)
Keep the branch updated to make merging it easier later.

14 files changed:
release/scripts/startup/bl_ui/space_view3d_toolbar.py
source/blender/blenkernel/BKE_brush.h
source/blender/blenkernel/BKE_pbvh.h
source/blender/blenkernel/intern/brush.c
source/blender/blenkernel/intern/pbvh.c
source/blender/blenkernel/intern/pbvh_bmesh.c
source/blender/editors/sculpt_paint/paint_intern.h
source/blender/editors/sculpt_paint/paint_ops.c
source/blender/editors/sculpt_paint/paint_stroke.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/sculpt_paint/sculpt_intern.h
source/blender/editors/space_view3d/view3d_draw.c
source/blender/makesdna/DNA_brush_types.h
source/blender/makesrna/intern/rna_brush.c

index 2e291d3d471535871e6fd1fdceb32476ff0c63b1..b2c6f7a4455e09cbf73d6ebadc11b120748e6e6c 100644 (file)
@@ -1437,16 +1437,13 @@ class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
             col.separator()
             col.prop(brush, "rate", text="Rate", slider=True)
 
-        if brush.use_space:
+        if brush.use_space or brush.use_line or brush.use_curve:
             col.separator()
             row = col.row(align=True)
             row.prop(brush, "spacing", text="Spacing")
             row.prop(brush, "use_pressure_spacing", toggle=True, text="")
-
-        if brush.use_line or brush.use_curve:
             col.separator()
-            row = col.row(align=True)
-            row.prop(brush, "spacing", text="Spacing")
+            col.prop(brush, "use_adaptive_space", text="Adaptive Spacing")
 
         if brush.use_curve:
             col.separator()
index 8bd4bdf89e18d0d911d776bf423e5f571b5380a1..afc172ebd759087ef230fab7d6e3ff0a4574a290 100644 (file)
@@ -105,6 +105,7 @@ void BKE_brush_weight_set(const struct Scene *scene, struct Brush *brush, float
 int  BKE_brush_use_locked_size(const struct Scene *scene, const struct Brush *brush);
 int  BKE_brush_use_alpha_pressure(const struct Scene *scene, const struct Brush *brush);
 int  BKE_brush_use_size_pressure(const struct Scene *scene, const struct Brush *brush);
+int  BKE_brush_use_adaptive_spacing(const struct Brush *brush);
 
 /* scale unprojected radius to reflect a change in the brush's 2D size */
 void BKE_brush_scale_unprojected_radius(
index 927303f8b3c6d89a39fd5aa6e273d19e699e6b6a..d6bdca81b38f2aea4a351e36cfe482199c543768 100644 (file)
@@ -29,6 +29,7 @@
 #include "BLI_bitmap.h"
 #include "BLI_ghash.h"
 #include "BLI_utildefines.h"
+#include "DNA_mesh_types.h"
 
 struct CCGElem;
 struct CCGKey;
@@ -61,6 +62,7 @@ typedef void (*BKE_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float *
 /* Building */
 
 PBVH *BKE_pbvh_new(void);
+void BKE_pbvh_attach_mesh(PBVH *pbvh, PBVHNode *node, Mesh *me, int totprim, float *max_bmin, float *max_bmax);
 void BKE_pbvh_build_mesh(
         PBVH *bvh,
         const struct MPoly *mpoly, const struct MLoop *mloop,
@@ -71,6 +73,7 @@ void BKE_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems,
                           struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats,
                           unsigned int **grid_hidden);
 void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading, struct BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset);
+void BKE_pbvh_build_tmp_bmesh(PBVH *bvh, struct BMesh *bm, bool smooth_shading);
 
 void BKE_pbvh_free(PBVH *bvh);
 void BKE_pbvh_free_layer_disp(PBVH *bvh);
@@ -172,6 +175,8 @@ typedef enum {
        PBVH_UpdateTopology = 256,
 } PBVHNodeFlags;
 
+bool BKE_pbvh_node_is_valid(PBVHNode *node);
+bool BKE_pbvh_node_is_leaf(PBVHNode *node);
 void BKE_pbvh_node_mark_update(PBVHNode *node);
 void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node);
 void BKE_pbvh_node_mark_redraw(PBVHNode *node);
@@ -190,9 +195,15 @@ void BKE_pbvh_node_get_verts(
         PBVH *bvh, PBVHNode *node,
         const int **r_vert_indices, struct MVert **r_verts);
 
+int BKE_pbvh_recalc_looptri_from_me(PBVH *pbvh, Mesh *me);
+PBVHNode *BKE_search_closest_pbvh_leaf_node(PBVH *pbvh, PBVHNode *p_node, float *target_bmin, float *target_bmax);
+
 void BKE_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
 void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
 
+void BKE_pbvh_node_get_children(PBVH *pbvh, PBVHNode *node, PBVHNode **left, PBVHNode **right);
+PBVHNode *BKE_pbvh_node_get_root(PBVH *pbvh);
+
 float BKE_pbvh_node_get_tmin(PBVHNode *node);
 
 /* test if AABB is at least partially inside the planes' volume */
index 57b707a31d3e1d8bfd4fd467c8aaa38f4f8eba65..1a9295d579e3accb86411b09998e2a8c99b103f4 100644 (file)
@@ -94,7 +94,7 @@ static void brush_defaults(Brush *brush)
        zero_v3(brush->secondary_rgb);
 
        /* BRUSH STROKE SETTINGS */
-       brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN);
+       brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN | BRUSH_ADAPTIVE_SPACE);
        brush->spacing = 10; /* how far each brush dot should be spaced as a percentage of brush diameter */
 
        brush->smooth_stroke_radius = 75;
@@ -104,6 +104,8 @@ static void brush_defaults(Brush *brush)
 
        brush->jitter = 0.0f;
 
+       brush->adaptive_space_factor = 1;
+
        /* BRUSH TEXTURE SETTINGS */
        BKE_texture_mtex_default(&brush->mtex);
        BKE_texture_mtex_default(&brush->mask_mtex);
@@ -844,6 +846,12 @@ int BKE_brush_use_alpha_pressure(const Scene *scene, const Brush *brush)
               (brush->flag & BRUSH_ALPHA_PRESSURE);
 }
 
+
+int BKE_brush_use_adaptive_spacing(const Brush *brush)
+{
+       return (brush->flag & BRUSH_ADAPTIVE_SPACE); //FIXME make sure we are in view3D
+}
+
 void BKE_brush_unprojected_radius_set(Scene *scene, Brush *brush, float unprojected_radius)
 {
        UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
index 53dfffe2b97f3bb566ecde0f9aad749860a8c4a5..e90a921805fee7d5cc7876353b370e9f123e0821 100644 (file)
@@ -38,6 +38,7 @@
 #include "BKE_global.h"
 #include "BKE_mesh.h" /* for BKE_mesh_calc_normals */
 #include "BKE_paint.h"
+#include "DNA_mesh_types.h"
 
 #include "GPU_buffers.h"
 
@@ -514,6 +515,55 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
        build_sub(bvh, 0, cb, prim_bbc, 0, totprim);
 }
 
+/**
+ * Attach a new mesh to a node of the PBVH
+ * vertdata etc needs to be already in the basemesh
+ */
+void BKE_pbvh_attach_mesh(PBVH *pbvh, PBVHNode *node, Mesh *me, int totprim, float *max_bmin, float *max_bmax){
+       BB new_BB;
+       copy_v3_v3(new_BB.bmin, max_bmin);
+       copy_v3_v3(new_BB.bmax, max_bmax);
+       int d_prim = totprim-pbvh->totprim;
+
+       /*for(int i = 0; i < pbvh->totprim; i++){
+               printf("%i,",pbvh->prim_indices[i]);
+       }*/
+
+       if(me->totvert <= pbvh->leaf_limit){
+               pbvh->totvert = me->totvert;
+               pbvh->totprim = totprim;
+               MEM_freeN(pbvh->prim_indices);
+
+               pbvh->prim_indices = MEM_mallocN(sizeof(int) * pbvh->totprim,
+                                                                               "bvh prim indices");
+
+               //TODO: parent nodes need to be scaled as well
+               node->totprim += d_prim;
+               node->prim_indices = pbvh->prim_indices;
+
+               //Fill with all prim to test
+               for(int i = 0; i < pbvh->totprim; i++){
+                       pbvh->prim_indices[i] = i;
+               }
+
+               BB_expand_with_bb( &node->vb, &new_BB);
+
+               pbvh->verts = me->mvert;
+               pbvh->mloop = me->mloop;
+               pbvh->mpoly = me->mpoly;
+
+               build_mesh_leaf_node(pbvh, node);
+
+               MEM_freeN(node->draw_buffers);
+               node->draw_buffers = NULL;
+
+               BKE_pbvh_node_mark_rebuild_draw(node);
+               printf("Attached new shape to pbvh.\n");
+       }else{
+               //TODO: Attach to multiple nodes.
+       }
+}
+
 /**
  * Do a full rebuild with on Mesh data structure.
  *
@@ -1337,6 +1387,14 @@ BMesh *BKE_pbvh_get_bmesh(PBVH *bvh)
 
 /***************************** Node Access ***********************************/
 
+bool BKE_pbvh_node_is_valid(PBVHNode *node){
+       return node->flag; //TODO: check diffrent!
+}
+
+bool BKE_pbvh_node_is_leaf(PBVHNode *node){
+       return node->flag & PBVH_Leaf;
+}
+
 void BKE_pbvh_node_mark_update(PBVHNode *node)
 {
        node->flag |= PBVH_UpdateNormals | PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
@@ -1428,6 +1486,69 @@ void BKE_pbvh_node_get_grids(
        }
 }
 
+float get_bb_distance_sqr(BB a, BB b){
+       float dist = 0.0f;
+       for(int i = 0; i < 3; i++){
+               if(a.bmin[i] >= b.bmax[i]){
+                       dist += (b.bmax[i] - a.bmin[i]) * (b.bmax[i] - a.bmin[i]);
+               }else if(a.bmax[i] < b.bmin[i]){
+                       dist += (b.bmin[i] - a.bmax[i]) * (b.bmin[i] - a.bmax[i]);
+               }
+       }
+       return dist;
+}
+
+int BKE_pbvh_recalc_looptri_from_me(PBVH *pbvh, Mesh *me){
+       MEM_freeN(pbvh->looptri);
+       MLoopTri *looptri = NULL;
+       int looptri_num = poly_to_tri_count(me->totpoly, me->totloop);
+       looptri = MEM_mallocN(sizeof(*looptri) * looptri_num, __func__);
+
+       BKE_mesh_recalc_looptri(
+                                                       me->mloop, me->mpoly,
+                                                       me->mvert,
+                                                       me->totloop, me->totpoly,
+                                                       looptri);
+       /*for(int i = 0; i < looptri_num; i++){
+               printf("Tri (%i,%i,%i), Poly %i\n", looptri[i].tri[0], looptri[i].tri[1], looptri[i].tri[2], looptri[i].poly);
+       }*/
+
+       pbvh->looptri = looptri;
+       return looptri_num;
+}
+
+PBVHNode *BKE_search_closest_pbvh_leaf_node(PBVH *pbvh, PBVHNode *p_node, float *target_bmin, float *target_bmax){
+       BB new_BB;
+       copy_v3_v3(new_BB.bmin,target_bmin);
+       copy_v3_v3(new_BB.bmax,target_bmax);
+       BB_expand_with_bb(&p_node->vb,&new_BB);
+       if(BKE_pbvh_node_is_leaf(p_node)){
+               return p_node;
+       }
+       PBVHNode *left = NULL, *right = NULL;
+       BB bb_left, bb_right, bb_target;
+
+       copy_v3_v3(bb_target.bmin,target_bmin);
+       copy_v3_v3(bb_target.bmax,target_bmax);
+
+       BKE_pbvh_node_get_children(pbvh, p_node, &left, &right);
+       if((!left && !right)){
+               return p_node;
+       }else if(!left){
+               return BKE_search_closest_pbvh_leaf_node(pbvh, right, bb_target.bmin, bb_target.bmax);
+       }else if(!right){
+               return BKE_search_closest_pbvh_leaf_node(pbvh, left, bb_target.bmin, bb_target.bmax);
+       }
+       BKE_pbvh_node_get_BB(left,&bb_left.bmin,&bb_left.bmax);
+       BKE_pbvh_node_get_BB(right,&bb_right.bmin,&bb_right.bmax);
+       if(get_bb_distance_sqr(bb_target,bb_left) > get_bb_distance_sqr(bb_target,bb_right)){
+               return BKE_search_closest_pbvh_leaf_node(pbvh, right, bb_target.bmin, bb_target.bmax);
+       }else{
+               return BKE_search_closest_pbvh_leaf_node(pbvh, left, bb_target.bmin, bb_target.bmax);
+       }
+}
+
+
 void BKE_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3])
 {
        copy_v3_v3(bb_min, node->vb.bmin);
@@ -1440,6 +1561,15 @@ void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max
        copy_v3_v3(bb_max, node->orig_vb.bmax);
 }
 
+void BKE_pbvh_node_get_children(PBVH *pbvh, PBVHNode *node, PBVHNode **left, PBVHNode **right){
+       *left = pbvh->nodes+node->children_offset;
+       *right = pbvh->nodes+node->children_offset+1;
+}
+
+PBVHNode *BKE_pbvh_node_get_root(PBVH *pbvh){
+       return pbvh->nodes;
+}
+
 void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count)
 {
        if (node->proxy_count > 0) {
index c5e49883dc6a46b85a36f82eb6fa912cced8d820..755bec549f4a573f6704baebddd665f2a89d762d 100644 (file)
@@ -1850,6 +1850,71 @@ void BKE_pbvh_build_bmesh(
        MEM_freeN(nodeinfo);
 }
 
+/* Build a PBVH from a BMesh */
+void BKE_pbvh_build_tmp_bmesh(
+        PBVH *bvh, BMesh *bm, bool smooth_shading)
+{
+       bvh->cd_vert_node_offset = 0;
+       bvh->cd_face_node_offset = 0;
+       bvh->bm = bm;
+
+       bvh->type = PBVH_BMESH;
+
+       /* TODO: choose leaf limit better */
+       bvh->leaf_limit = 100;
+
+       if (smooth_shading)
+               bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
+
+       /* bounding box array of all faces, no need to recalculate every time */
+       BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC");
+       BMFace **nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo");
+       MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage");
+
+       BMIter iter;
+       BMFace *f;
+       int i;
+       BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) {
+               BBC *bbc = &bbc_array[i];
+               BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+               BMLoop *l_iter = l_first;
+
+               BB_reset((BB *)bbc);
+               do {
+                       BB_expand((BB *)bbc, l_iter->v->co);
+               } while ((l_iter = l_iter->next) != l_first);
+               BBC_update_centroid(bbc);
+
+               /* so we can do direct lookups on 'bbc_array' */
+               BM_elem_index_set(f, i);  /* set_dirty! */
+               nodeinfo[i] = f;
+       }
+
+       /* likely this is already dirty */
+       bm->elem_index_dirty |= BM_FACE;
+
+       /* setup root node */
+       struct FastNodeBuildInfo rootnode = {0};
+       rootnode.totface = bm->totface;
+
+       /* start recursion, assign faces to nodes accordingly */
+       pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, &rootnode, arena);
+
+       /* we now have all faces assigned to a node, next we need to assign those to the gsets of the nodes */
+
+       /* Start with all faces in the root node */
+       bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
+       bvh->totnode = 1;
+
+       /* take root node and visit and populate children recursively */
+       pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, &rootnode, 0);
+
+       BLI_memarena_free(arena);
+       MEM_freeN(bbc_array);
+       MEM_freeN(nodeinfo);
+}
+
+
 /* Collapse short edges, subdivide long edges */
 bool BKE_pbvh_bmesh_update_topology(
         PBVH *bvh, PBVHTopologyUpdateMode mode,
index 7e05ab929aeb2b9de0534feaff8a98a65e1682f7..57cf54837de0de0901b9ee323cdfdfbf9dc9b9f6 100644 (file)
@@ -32,6 +32,7 @@
 #ifndef __PAINT_INTERN_H__
 #define __PAINT_INTERN_H__
 
+
 struct ARegion;
 struct bContext;
 struct Brush;
@@ -76,6 +77,7 @@ bool paint_supports_smooth_stroke(struct Brush *br, enum PaintMode mode);
 bool paint_supports_texture(enum PaintMode mode);
 bool paint_supports_jitter(enum PaintMode mode);
 
+
 struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf);
 int paint_stroke_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
 int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
index f88b64129e7cd0591a7d98e83d06b19b4583aee8..19672c940c754cdc404d116355cbe4a9faa8a349 100644 (file)
@@ -1566,6 +1566,9 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
        /* Toggle dynamic topology */
        WM_keymap_add_item(keymap, "SCULPT_OT_dynamic_topology_toggle", DKEY, KM_PRESS, KM_CTRL, 0);
 
+       /* Draw Silhouette */
+       WM_keymap_add_item(keymap, "SCULPT_OT_silhouette_draw", LEFTMOUSE, KM_PRESS, KM_ALT, 0);
+
        /* Dynamic-topology detail size
         * 
         * This should be improved further, perhaps by showing a triangle
index 05270dbfa090397f639ef2ae851658331c33df41..158ada1a2ea95fd54582a7beea26a142c001f6fb 100644 (file)
 #include "IMB_imbuf_types.h"
 
 #include "paint_intern.h"
+#include "sculpt_intern.h"
 
 #include <float.h>
 #include <math.h>
 
+#include <stdio.h>
+
 //#define DEBUG_TIME
 
 #ifdef DEBUG_TIME
 #  include "PIL_time_utildefines.h"
 #endif
 
+/*Debug spacing calc define DEBUG_DRAW to get info about sampling etc.*/
+/*#define DEBUG_DRAW*/
+
+#ifdef DEBUG_DRAW
+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);
+
+void bl_debug_draw_point(const float pos[3],const float thickness){
+       float h = thickness*0.5;
+       float v1[] = {pos[0]-h,pos[1]-h,pos[2]};
+       float v2[] = {pos[0]-h,pos[1]+h,pos[2]};
+       float v3[] = {pos[0]+h,pos[1]-h,pos[2]};
+       float v4[] = {pos[0]+h,pos[1]+h,pos[2]};
+       bl_debug_draw_quad_add(v1,v2,v3,v4);
+}
+#endif
+
 typedef struct PaintSample {
        float mouse[2];
        float pressure;
@@ -101,8 +125,10 @@ typedef struct PaintStroke {
        int cur_sample;
 
        float last_mouse_position[2];
+       float last_v3_mouse_position[3];
        /* space distance covered so far */
        float stroke_distance;
+       float distance_since_last_dab;
 
        /* Set whether any stroke step has yet occurred
         * e.g. in sculpt mode, stroke doesn't start until cursor
@@ -444,6 +470,7 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
         * will create too many dabs */
        copy_v2_v2(stroke->last_mouse_position, mouse_in);
        stroke->last_pressure = pressure;
+       stroke->distance_since_last_dab = 0.0f;
 
        if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) {
                float delta[2];
@@ -474,6 +501,14 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
                return;
        }
 
+#ifdef DEBUG_DRAW
+       bl_debug_color_set(0x0000FF);
+       bl_debug_draw_point(ups->last_location,0.05f);
+       bl_debug_color_set(0x000000);
+#endif
+
+       copy_v3_v3(stroke->last_v3_mouse_position, location);
+
        /* Add to stroke */
        RNA_collection_add(op->ptr, "stroke", &itemptr);
        RNA_float_set(&itemptr, "size", ups->pixel_radius);
@@ -516,36 +551,56 @@ static bool paint_smooth_stroke(
        return true;
 }
 
-static float paint_space_stroke_spacing(const Scene *scene, PaintStroke *stroke, float size_pressure, float spacing_pressure)
+static const float MIN_BRUSH_SIZE_PIXELS = 1.0f;
+static const float MAGIC_50 = 50.0f;
+static const float MAGIC_1_5 = 1.5f;
+
+/* Brush spacing ignoring both pressure and brush angle to the geometry */
+static float paint_space_unadjusted_stroke_spacing(const Scene *scene, PaintStroke *stroke) {
+
+       const float size_clamp = max_ff(MIN_BRUSH_SIZE_PIXELS, BKE_brush_size_get(scene, stroke->brush));
+
+       return max_ff(MIN_BRUSH_SIZE_PIXELS, size_clamp * stroke->brush->spacing / MAGIC_50);
+}
+
+static float paint_space_stroke_adaptive_spacing(const Scene *scene, PaintStroke *stroke, float spacing)
+{
+       spacing = spacing * stroke->brush->adaptive_space_factor;
+
+       return spacing;
+}
+
+static float paint_space_stroke_pressure_spacing(const Scene *scene, PaintStroke *stroke, float size_pressure, float spacing_pressure, float spacing)
 {
        /* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel
         * causing very high step sizes, hanging blender [#32381] */
-       const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * size_pressure);
-       float spacing = stroke->brush->spacing;
+       //TODO size_clamp should probably be calculated at the start and used throughout
+       const float size_clamp = max_ff(MIN_BRUSH_SIZE_PIXELS, BKE_brush_size_get(scene, stroke->brush) * size_pressure);
+
 
-       /* apply spacing pressure */
-       if (stroke->brush->flag & BRUSH_SPACING_PRESSURE)
-               spacing = spacing * (1.5f - spacing_pressure);
+       spacing = spacing * (MAGIC_1_5 - spacing_pressure);
 
+       //TODO zoom_2d should be seperated out
        /* stroke system is used for 2d paint too, so we need to account for
         * the fact that brush can be scaled there. */
        spacing *= stroke->zoom_2d;
 
-       return max_ff(1.0, size_clamp * spacing / 50.0f);
+       return max_ff(MIN_BRUSH_SIZE_PIXELS, size_clamp * spacing / MAGIC_50);
 }
 
 
-
 static float paint_stroke_overlapped_curve(Brush *br, float x, float spacing)
 {
        int i;
        const int n = 100 / spacing;
-       const float h = spacing / 50.0f;
-       const float x0 = x - 1;
+       //TODO I think the refactoring and spacing integration elsewhere makes this no longer necessary
+       //const int n = 100 / ((br->flag&BRUSH_ADAPTIVE_SPACE ? br->adaptive_space_factor : 1.0f)  *  br->spacing);
+       const float h = spacing / MAGIC_50;
+       const float x0 = x - 1.0f;
 
        float sum;
 
-       sum = 0;
+       sum = 0.0f;
        for (i = 0; i < n; i++) {
                float xx;
 
@@ -585,32 +640,71 @@ static float paint_stroke_integrate_overlap(Brush *br, float factor)
 
 static float paint_space_stroke_spacing_variable(const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length)
 {
+       float spacing = paint_space_unadjusted_stroke_spacing(scene, stroke);
+
+       if (BKE_brush_use_adaptive_spacing(stroke->brush)) {
+               /*adapt the stroke spacing to account for geometry that curves away from the viewport*/
+               spacing = paint_space_stroke_adaptive_spacing(scene, stroke, spacing);
+       }
+
        if (BKE_brush_use_size_pressure(scene, stroke->brush)) {
                /* use pressure to modify size. set spacing so that at 100%, the circles
                 * are aligned nicely with no overlap. for this the spacing needs to be
                 * the average of the previous and next size. */
-               float s = paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
-               float q = s * dpressure / (2.0f * length);
+               float q = spacing * dpressure / (2.0f * length);
                float pressure_fac = (1.0f + q) / (1.0f - q);
 
                float last_size_pressure = stroke->last_pressure;
                float new_size_pressure = stroke->last_pressure * pressure_fac;
 
                /* average spacing */
-               float last_spacing = paint_space_stroke_spacing(scene, stroke, last_size_pressure, pressure);
-               float new_spacing = paint_space_stroke_spacing(scene, stroke, new_size_pressure, pressure);
+               float last_spacing = paint_space_stroke_pressure_spacing(scene, stroke, last_size_pressure, pressure, spacing);
+               float new_spacing = paint_space_stroke_pressure_spacing(scene, stroke, new_size_pressure, pressure, spacing);
+
+               spacing = 0.5f * (last_spacing + new_spacing);
 
-               return 0.5f * (last_spacing + new_spacing);
        }
-       else {
-               /* no size pressure */
-               return paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
+       return spacing;
+}
+
+/* Draw a dab in the sample region.
+ * sample_point is the end point.
+ * step_v2 is the vector between first point and the end point.
+ * draw dabs with spacing interpolated on the line between the two points.
+ */
+static int draw_spaced_dab(bContext *C, wmOperator *op,const float sample_point[2], float step_v2[2], float dist_last_dab, float spacing, float pressure, float *length_v3){
+       float draw_pos[2];
+       float interpol_fact;
+       float interpol_pos = -dist_last_dab;
+       int cnt = 0;
+
+       while((*length_v3)-interpol_pos >= spacing){
+               interpol_fact = 1.0f-((interpol_pos+spacing)/(*length_v3));
+               if(interpol_fact > 0.0f && interpol_fact <= 1.0f){
+                       mul_v2_v2fl(draw_pos,step_v2,-interpol_fact);
+                       add_v2_v2(draw_pos,sample_point);
+                       paint_brush_stroke_add_step(C, op, draw_pos, pressure);
+                       cnt ++;
+               }else{
+                       /*Cornercase should not happen. TODO: Delete?*/
+                       mul_v2_v2fl(draw_pos,step_v2,-1.0f);
+                       add_v2_v2(draw_pos,sample_point);
+                       paint_brush_stroke_add_step(C, op, draw_pos, pressure);
+                       *length_v3 = 0.0f;
+                       return cnt+1;
+               }
+               interpol_pos += spacing;
        }
+       /* transfer remaining space between end point and last dab to the next region*/
+       *length_v3 -= interpol_pos;
+
+       return cnt;
 }
 
-/* For brushes with stroke spacing enabled, moves mouse in steps
- * towards the final mouse location. */
-static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mouse[2], float final_pressure)
+/* Calculate spacing in screen space. (distance between last dab in screen space)
+ * This checks distance to the last dab. Maybe it should be distance drawn on screen?
+ */
+static int paint_space_stroke_screen_space(bContext *C, wmOperator *op, const float final_mouse[2], float final_pressure)
 {
        const Scene *scene = CTX_data_scene(C);
        PaintStroke *stroke = op->customdata;
@@ -620,7 +714,7 @@ static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mou
        float pressure, dpressure;
        float mouse[2], dmouse[2];
        float length;
-       float no_pressure_spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
+       float no_pressure_spacing = paint_space_unadjusted_stroke_spacing(scene, stroke);
 
        sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
 
@@ -652,6 +746,143 @@ static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mou
                        break;
                }
        }
+       
+       return cnt;
+}
+
+/* For brushes with adaptive stroke spacing enabled.
+ * Calculate spacing in object space. Distance drawn on surface rather than distance drawn on screen.
+ */
+static int paint_space_stroke_object_space(bContext *C, wmOperator *op, const float final_mouse[2], float final_pressure)
+{
+       const Scene *scene = CTX_data_scene(C);
+       PaintStroke *stroke = op->customdata;
+       UnifiedPaintSettings *ups = stroke->ups;
+       int cnt = 0;
+
+       float pressure, dpressure;
+       float mouse_v3[3], diff_mouse_v3[3];
+
+       float length, length_v3;
+       float no_pressure_spacing = paint_space_unadjusted_stroke_spacing(scene, stroke);
+
+       int steps;
+       float length_v2,step_size;
+       float diff_path_v2[2], step_pos_v2[2];
+       float start_step_v3[3], end_step_v3[3];
+
+       bool off_mesh = false;
+       float min_res = 0.1f;
+
+       pressure = stroke->last_pressure;
+       dpressure = final_pressure - stroke->last_pressure;
+
+       if(stroke->get_location){
+               if(!stroke->get_location(C, mouse_v3, final_mouse)){
+                       off_mesh = true;
+               }
+       }
+
+       sub_v3_v3v3(diff_mouse_v3, mouse_v3, stroke->last_v3_mouse_position);
+
+       /* accumulate path or 3d max distance from last dab?
+        * accumulative version here:
+        */
+
+       /*length_v3 is the distance between the last samplepoint and the current*/
+       length_v3 = normalize_v3(diff_mouse_v3);
+
+       if(length_v3 > 0.0f){
+               float spacing = paint_space_stroke_spacing_variable(scene, stroke, pressure, dpressure, stroke->distance_since_last_dab);
+
+               /*check if more samplepoints are needed to better approximate the surface.*/
+               if(length_v3 > min_res){
+                       steps = ceilf(length_v3/min_res);
+                       sub_v2_v2v2(diff_path_v2,final_mouse,stroke->last_mouse_position);
+                       length_v2 = normalize_v2(diff_path_v2);
+                       if(off_mesh){
+                               step_size = 1.0f/min_res;
+                               steps = 10000;/*turns "for" into "while", maybe there is a better way?*/
+                       }else{
+                               step_size = length_v2/steps;
+                       }
+
+                       length_v3 = 0.0f;
+
+                       mul_v2_fl(diff_path_v2,step_size);
+
+                       copy_v3_v3(start_step_v3,stroke->last_v3_mouse_position);
+                       copy_v2_v2(step_pos_v2,stroke->last_mouse_position);
+
+#ifdef DEBUG_DRAW
+                       bl_debug_color_set(0x000000);
+#endif
+                       /*split up the current section into smaller parts*/
+                       for(int i = 0; i < steps; i++){
+                               if(i < steps-1){
+                                       add_v2_v2(step_pos_v2,diff_path_v2);
+                                       if(stroke->get_location){
+                                               if(!stroke->get_location(C, end_step_v3, step_pos_v2)){
+                                                       copy_v2_v2(stroke->last_mouse_position,step_pos_v2);
+                                                       copy_v3_v3(stroke->last_v3_mouse_position,end_step_v3);
+                                                       return cnt;
+                                               }
+                                       }
+                                       length_v3 = len_v3v3(end_step_v3,start_step_v3);
+#ifdef DEBUG_DRAW
+                                       bl_debug_draw_edge_add(end_step_v3,start_step_v3);
+#endif
+                                       copy_v3_v3(start_step_v3,end_step_v3);
+                               }else{
+                                       add_v2_v2(step_pos_v2,diff_path_v2);
+                                       length_v3 = len_v3v3(end_step_v3,mouse_v3);
+#ifdef DEBUG_DRAW
+                                       bl_debug_color_set(0xff0000);
+                                       bl_debug_draw_edge_add(end_step_v3,mouse_v3);
+#endif
+                               }
+
+                               /*Dab*/
+                               length = stroke->distance_since_last_dab + length_v3;
+                               if(length >= spacing){
+                                       pressure = stroke->last_pressure + (spacing / length) * dpressure;
+                                       ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, (spacing/stroke->brush->adaptive_space_factor) / no_pressure_spacing);
+                                       stroke->stroke_distance += spacing;
+
+                                       cnt += draw_spaced_dab(C, op, step_pos_v2, diff_path_v2, stroke->distance_since_last_dab, spacing, pressure, &length_v3);
+
+                                       stroke->distance_since_last_dab = length_v3;
+                                       pressure = stroke->last_pressure;
+                                       dpressure = final_pressure - stroke->last_pressure;
+                               }else{
+                                       stroke->distance_since_last_dab += length_v3;
+                               }
+                               /*end Dab*/
+                       }
+               }else{
+                       /*Dab*/
+                       length = stroke->distance_since_last_dab + length_v3;
+                       if(length >= spacing){
+                               sub_v2_v2v2(diff_path_v2,final_mouse,stroke->last_mouse_position);
+
+                               pressure = stroke->last_pressure + (spacing / length) * dpressure;
+                               ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, (spacing/stroke->brush->adaptive_space_factor) / no_pressure_spacing);//paint_stroke_integrate_overlap(stroke->brush, spacing / no_pressure_spacing);
+                               stroke->stroke_distance += length;
+
+                               cnt += draw_spaced_dab(C, op, final_mouse, diff_path_v2, stroke->distance_since_last_dab, spacing, pressure, &length_v3);
+
+                               stroke->distance_since_last_dab = length_v3;
+                               pressure = stroke->last_pressure;
+                               dpressure = final_pressure - stroke->last_pressure;
+                       }else{
+                               stroke->distance_since_last_dab += length_v3;
+                       }
+                       /*end Dab*/
+               }
+       }
+
+       copy_v2_v2(stroke->last_mouse_position,final_mouse);
+       copy_v3_v3(stroke->last_v3_mouse_position,mouse_v3);
 
        return cnt;
 }
@@ -960,7 +1191,12 @@ static void paint_stroke_line_end(bContext *C, wmOperator *op, PaintStroke *stro
                stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
 
                paint_brush_stroke_add_step(C, op, stroke->last_mouse_position, 1.0);
-               paint_space_stroke(C, op, mouse, 1.0);
+
+               if(BKE_brush_use_adaptive_spacing(stroke->brush)){
+                       paint_space_stroke_object_space(C,op, mouse, 1.0f);
+               }else{
+                       paint_space_stroke_screen_space(C,op, mouse, 1.0f);
+               }
        }
 }
 
@@ -971,7 +1207,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
        if (br->flag & BRUSH_CURVE) {
                UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
                const Scene *scene = CTX_data_scene(C);
-               const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
+               const float spacing = paint_space_unadjusted_stroke_spacing(scene, stroke);
                PaintCurve *pc = br->paint_curve;
                PaintCurvePoint *pcp;
                float length_residue = 0.0f;
@@ -1125,6 +1361,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
        if (!stroke->stroke_started) {
                stroke->last_pressure = sample_average.pressure;
                copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
+               stroke->get_location(C,stroke->last_v3_mouse_position,stroke->last_mouse_position);
                stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
                BLI_assert((stroke->stroke_started & ~1) == 0);  /* 0/1 */
 
@@ -1191,8 +1428,13 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
                if (paint_smooth_stroke(stroke, &sample_average, mode, mouse, &pressure)) {
                        if (stroke->stroke_started) {
                                if (paint_space_stroke_enabled(br, mode)) {
-                                       if (paint_space_stroke(C, op, mouse, pressure))
-                                               redraw = true;
+                                       if (BKE_brush_use_adaptive_spacing(stroke->brush)) {
+                                               if (paint_space_stroke_object_space(C, op, mouse, pressure))
+                                                       redraw = true;
+                                       }else{
+                                               if (paint_space_stroke_screen_space(C, op, mouse, pressure))
+                                                       redraw = true;
+                                       }
                                }
                                else {
                                        float dmouse[2];
index 44cc2720a328a26a92c8ddf9731234b1653b0293..e8146bd2188a61fdf8fbe953acde79e3dd6acb17 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+/*Maybe move silhouette GL Drawing into a seperate file*/
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "ED_space_api.h"
+#include "bmesh.h"
+#include "bmesh_tools.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_bvh.h"
+#include "ED_mesh.h"
+
+#define DEBUG_DRAW
+#ifdef DEBUG_DRAW
+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);
+
+void bl_debug_draw_point(const float pos[3],const float thickness){
+       float h = thickness*0.5;
+       float v1[] = {pos[0]-h,pos[1]-h,pos[2]};
+       float v2[] = {pos[0]-h,pos[1]+h,pos[2]};
+       float v3[] = {pos[0]+h,pos[1]-h,pos[2]};
+       float v4[] = {pos[0]+h,pos[1]+h,pos[2]};
+       bl_debug_draw_quad_add(v1,v2,v3,v4);
+}
+#endif
+
 /** \name Tool Capabilities
  *
  * Avoid duplicate checks, internal logic only,
@@ -172,7 +202,7 @@ static bool sculpt_brush_needs_rake_rotation(const Brush *brush)
 struct SculptRakeData {
        float follow_dist;
        float follow_co[3];
-};
+} SculptRakeData;
 
 typedef enum StrokeFlags {
        CLIP_X = 1,
@@ -214,8 +244,8 @@ typedef struct StrokeCache {
        float projection_mat[4][4];
 
        /* Clean this up! */
-       ViewContext *vc;
-       Brush *brush;
+       struct ViewContext *vc;
+       struct Brush *brush;
 
        float special_rotation;
        float grab_delta[3], grab_delta_symmetry[3];
@@ -253,7 +283,7 @@ typedef struct StrokeCache {
        float anchored_location[3];
 
        float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
-       Dial *dial;
+       struct Dial *dial;
        
        char saved_active_brush_name[MAX_ID_NAME];
        char saved_mask_brush_tool;
@@ -270,6 +300,19 @@ typedef struct StrokeCache {
        rcti current_r; /* current redraw rectangle */
 } StrokeCache;
 
+/* reduce brush spacing step size when the geometry curves away from the view */
+static void set_adaptive_space_factor(Sculpt *sd)
+{
+       Brush *brush = BKE_paint_brush(&(sd->paint));
+
+       /*TODO: Reasonable 2D View 3D conversion
+        * Currently somewhere about 1bu / 200px
+        */
+
+       brush->adaptive_space_factor = 1.0f/200.0f;
+}
+
+
 /************** Access to original unmodified vertex data *************/
 
 typedef struct {
@@ -1891,6 +1934,8 @@ static void smooth(
                return;
        }
 
+       set_adaptive_space_factor(sd);
+
        for (iteration = 0; iteration <= count; ++iteration) {
                const float strength = (iteration != count) ? 1.0f : last;
 
@@ -1975,6 +2020,8 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
 {
        Brush *brush = BKE_paint_brush(&sd->paint);
 
+       set_adaptive_space_factor(sd);
+
        /* threaded loop over nodes */
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
@@ -2044,6 +2091,8 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
        mul_v3_v3(offset, ss->cache->scale);
        mul_v3_fl(offset, bstrength);
 
+       set_adaptive_space_factor(sd);
+
        /* threaded loop over nodes */
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
@@ -2132,6 +2181,8 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
         * Without this we get a 'flat' surface surrounding the pinch */
        sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
 
+       set_adaptive_space_factor(sd);
+
        /* threaded loop over nodes */
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
@@ -2180,6 +2231,8 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
 {
        Brush *brush = BKE_paint_brush(&sd->paint);
 
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
        };
@@ -2239,6 +2292,8 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
                sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
        }
 
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
            .grab_delta = grab_delta,
@@ -2293,6 +2348,8 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
        cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
        cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
 
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
            .cono = cono,
@@ -2394,6 +2451,9 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
                sculpt_project_v3_cache_init(&spvc, grab_delta);
        }
 
+
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
            .spvc = &spvc, .grab_delta = grab_delta,
@@ -2454,6 +2514,8 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
        cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
        cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
 
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
            .cono = cono,
@@ -2515,6 +2577,8 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
        static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 };
        const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
 
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
            .angle = angle,
@@ -2597,6 +2661,8 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
 
        mul_v3_v3v3(offset, ss->cache->scale, ss->cache->sculpt_normal_symm);
 
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
            .offset = offset,
@@ -2652,6 +2718,8 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
 {
        Brush *brush = BKE_paint_brush(&sd->paint);
 
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
        };
@@ -2851,6 +2919,8 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
        mul_v3_fl(temp, displace);
        add_v3_v3(area_co, temp);
 
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
            .area_no = area_no, .area_co = area_co,
@@ -2934,6 +3004,8 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
 
        /* add_v3_v3v3(p, ss->cache->location, area_no); */
 
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
            .area_no = area_no, .area_co = area_co,
@@ -3043,6 +3115,8 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
        mul_m4_m4m4(tmat, mat, scale);
        invert_m4_m4(mat, tmat);
 
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
            .area_no_sp = area_no_sp, .area_co = area_co, .mat = mat,
@@ -3121,6 +3195,8 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
        mul_v3_fl(temp, displace);
        add_v3_v3(area_co, temp);
 
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
            .area_no = area_no, .area_co = area_co,
@@ -3199,6 +3275,8 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
        mul_v3_fl(temp, displace);
        add_v3_v3(area_co, temp);
 
+       set_adaptive_space_factor(sd);
+
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
            .area_no = area_no, .area_co = area_co,
@@ -3254,6 +3332,8 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
        mul_v3_v3v3(offset, gravity_vector, ss->cache->scale);
        mul_v3_fl(offset, bstrength);
 
+       set_adaptive_space_factor(sd);
+
        /* threaded loop over nodes */
        SculptThreadedTaskData data = {
            .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
@@ -4929,6 +5009,555 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/* 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 struct {
+       float bmin[3], bmax[3];
+} BB;
+
+#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 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;
+       Scene *scene;
+
+       float add_col[3];
+       float last_mouse_pos[2];
+} SilhouetteData;
+
+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;
+
+       /*TODO: */
+       /*if (data->original)
+               BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
+       else*/
+               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;
+               }
+       }
+
+       //float tmp[3] = {bb_min[0]*0.5f+bb_max[0]*0.5f,bb_min[1]*0.5f+bb_max[1]*0.5f,bb_min[2]*0.5f+bb_max[2]*0.5f};
+       //printf("node found at: (%f,%f,%f)\n",bb_min[0]*0.5f+bb_max[0]*0.5f,bb_min[1]*0.5f+bb_max[1]*0.5f,bb_min[2]*0.5f+bb_max[2]*0.5f);
+       return true;
+}
+
+void silhouette_stroke_free(SilhouetteStroke *stroke){
+       if(stroke){
+               if(stroke->points){
+                       MEM_SAFE_FREE(stroke->points);
+               }
+               MEM_SAFE_FREE(stroke);
+       }
+       printf("Stroke freed.\n");
+       //MEM_SAFE_FREE(stroke);
+}
+
+SilhouetteStroke *silhouette_stroke_new(int max_verts){
+       SilhouetteStroke *stroke = MEM_callocN(sizeof(SilhouetteStroke), "SilhouetteStroke");
+       stroke->points = 0;
+       stroke->points = MEM_callocN(sizeof(float)*2*max_verts,"SilhouetteStrokePoints");//TODO: Dynamic length
+       stroke->totvert = 0;
+       stroke->max_verts = max_verts;
+       printf("Init silhouette Data\n");
+       return stroke;
+}
+
+SilhouetteData *silhouette_data_new(bContext *C,
+                                                         wmOperator *op)
+{
+       SilhouetteData *sil = MEM_callocN(sizeof(SilhouetteData), "SilhouetteData");
+       Object *obedit = CTX_data_edit_object(C);
+       Scene *scene = CTX_data_scene(C);
+       sil->ar = CTX_wm_region(C);
+       sil->current_stroke = 0;
+
+       sil->current_stroke = silhouette_stroke_new(1024);
+
+       view3d_set_viewcontext(C, &sil->vc);
+
+       sil->add_col[0] = 1.00; /* add mode color is light red */
+       sil->add_col[1] = 0.39;
+       sil->add_col[2] = 0.39;
+
+
+       /* assign the drawing handle for drawing preview line... */
+       sil->scene = scene;
+       sil->ob = obedit;
+
+       return sil;
+}
+
+void silhouette_data_free(struct wmOperator *op)
+{
+       SilhouetteData *data;
+       data = op->customdata;
+       if(data){
+               silhouette_stroke_free(data->current_stroke);
+               MEM_SAFE_FREE(data);
+       }
+}
+
+void silhouette_stroke_add_point(SilhouetteStroke *stroke, float point[2]){
+       if(stroke->totvert < stroke->max_verts){
+               stroke->points[stroke->totvert*2] = point[0];
+               stroke->points[stroke->totvert*2+1] = point[1];
+               stroke->totvert ++;
+       }else{
+               printf("Stroke reached maximum vert count.\n");
+       }
+}
+
+static void sculpt_silhouette_stroke_update(bContext *C, float mouse[2], SilhouetteData *sil)
+{
+       SilhouetteStroke *stroke = sil->current_stroke;
+
+       sil->last_mouse_pos[0] = mouse[0];//*(2.0f/(float)sil->ar->winx)-1.0f;
+       sil->last_mouse_pos[1] = mouse[1];//*(2.0f/(float)sil->ar->winy)-1.0f;
+       silhouette_stroke_add_point(stroke,sil->last_mouse_pos);
+       ED_region_tag_redraw(sil->ar);
+       copy_v2_v2(sil->last_mouse_pos,mouse);
+       //printf("Mouse Pos: (%f,%f)",mouse[0],mouse[1]);
+       /* Update stroke*/
+}
+
+static void silhouette_set_ref_plane(const bContext *C, float p[3]){
+       Scene *scene = CTX_data_scene(C);
+       View3D *v3d = CTX_wm_view3d(C);
+       const float *fp = ED_view3d_cursor3d_get(scene, v3d);
+
+       /* the reference point used depends on the owner... */
+       copy_v3_v3(p, fp);
+}
+
+void silhouette_create_shape_mesh(const bContext *C, Mesh *me, SilhouetteData *sil, SilhouetteStroke *stroke, View3D *v3d, BB *shape_bb){
+       float v_offset[3] = {0.0f,0.0f,1.0f};
+       ED_view3d_global_to_vector(sil->ar->regiondata, (float[3]){0.0f,0.0f,0.0f}, v_offset);
+
+       float v1[3], zDepth[3] = {0.0f,0.0f,0.0f};
+       int vstart = me->totvert, estart = me->totedge, lstart = me->totloop, pstart = me->totpoly;
+       ED_mesh_vertices_add(me, NULL, stroke->totvert*2);
+       ED_mesh_edges_add(me, NULL, stroke->totvert*3-2);
+       ED_mesh_loops_add(me, NULL, stroke->totvert*4-4);
+       ED_mesh_polys_add(me, NULL, stroke->totvert-1);
+       for(int i = 0; i < stroke->totvert; i++){
+               //Add Verts
+               MVert ref_v;
+               ref_v.flag = 0; ref_v.bweight = 0;
+               ED_view3d_win_to_3d(v3d, sil->ar, zDepth, stroke->points+i*2, v1);
+               copy_v3_v3(ref_v.co,v1);
+               me->mvert[vstart] = ref_v;
+               vstart ++;
+               add_v3_v3(ref_v.co,v_offset);
+               me->mvert[vstart] = ref_v;
+               vstart ++;
+
+               //Add Edges
+               MEdge ref_e;
+               ref_e.crease = 0; ref_e.bweight = 0; ref_e.flag = 0;
+               ref_e.v1 = vstart-2;
+               ref_e.v2 = vstart-1;
+               me->medge[estart] = ref_e;
+               estart ++;
+               if(i < stroke->totvert-1){
+                       ref_e.v1 = vstart-2;
+                       ref_e.v2 = vstart;
+                       me->medge[estart] = ref_e;
+                       estart ++;
+                       ref_e.v1 = vstart-1;
+                       ref_e.v2 = vstart+1;
+                       me->medge[estart] = ref_e;
+                       estart ++;
+               }
+
+               //Add Loops
+               MLoop ref_l;
+               if(i < stroke->totvert-1){
+                       ref_l.v = vstart-2;
+                       ref_l.e = estart-3;
+                       me->mloop[lstart] = ref_l;
+                       lstart ++;
+                       ref_l.v = vstart-1;
+                       ref_l.e = estart-1;
+                       me->mloop[lstart] = ref_l;
+                       lstart ++;
+                       ref_l.v = vstart+1;
+                       ref_l.e = estart;
+                       me->mloop[lstart] = ref_l;
+                       lstart ++;
+                       ref_l.v = vstart;
+                       ref_l.e = estart-2;
+                       me->mloop[lstart] = ref_l;
+                       lstart ++;
+               }
+
+               //Add Poly
+               MPoly ref_p;
+               ref_p.mat_nr = 0; ref_p.flag = 0; ref_p.pad = 0;
+               if(i < stroke->totvert-1){
+                       ref_p.loopstart = lstart-4;
+                       ref_p.totloop = 4;
+                       me->mpoly[pstart] = ref_p;
+                       pstart ++;
+               }
+       }
+
+       //ED_mesh_update(me, C, 1, 1);
+
+       //Extend BB
+       for(int i = 0; i < 3; i++){
+               if(v_offset[i] > 0){
+                       shape_bb->bmax[i] += v_offset[i];
+               }else{
+                       shape_bb->bmin[i] += v_offset[i];
+               }
+       }
+}
+
+void debug_mesh(Mesh *me){
+       printf("Logging Mesh:\n");
+       printf("Verts in mesh %i\n",me->totvert);
+       printf("Edges in mesh %i\n",me->totedge);
+       printf("Loops in mesh %i\n",me->totloop);
+       printf("Polys in mesh %i\n",me->totpoly);
+
+       printf("\nVert log:\n");
+       for(int i = 0; i < me->totvert; i++){
+               printf("\nVert %i (%f,%f,%f)", i, me->mvert[i].co[0], me->mvert[i].co[1], me->mvert[i].co[2]);
+       }
+
+       printf("\nEdge log:\n");
+       for(int i = 0; i < me->totedge;i++){
+               printf("Edge %i, v1v2(%i,%i)\n",i,me->medge[i].v1,me->medge[i].v2);
+       }
+
+       printf("\nLoop Log:\n");
+       for(int i = 0; i < me->totloop; i++){
+               printf("Loop %i, v(%i), e(%i)\n", i, me->mloop[i].v, me->mloop[i].e);
+       }
+
+       printf("\nPoly log:\n");
+       for(int i = 0; i < me->totpoly; i++){
+               printf("Poly %i, start(%i), totloop(%i)\n", i, me->mpoly[i].loopstart, me->mpoly[i].totloop);
+       }
+}
+
+static void sculpt_silhouette_stroke_done(const bContext *C, wmOperator *op)
+{
+       /*finalize stroke*/
+       Object *ob = CTX_data_active_object(C);
+       SculptSession *ss = ob->sculpt;
+       Scene *scene = CTX_data_scene(C);
+       SilhouetteData *sil = op->customdata;
+       View3D *v3d = CTX_wm_view3d(C);
+       RegionView3D *rv3d = sil->ar->regiondata;
+
+       /* PBVH stuff*/
+       PBVH *pbvh = ss->pbvh;
+       SculptSearchBBData pbvh_search_data;
+       BB shape_bb;
+       PBVHNode **nodes = NULL;
+       Mesh *me = ob->data;
+       int totnode;
+
+       float cursor[3];
+
+       silhouette_set_ref_plane(C, cursor);
+
+       float zfact = ED_view3d_calc_zfac(rv3d, cursor, NULL);
+
+       printf("zfact: %f\n",zfact);
+
+       SilhouetteStroke *stroke = sil->current_stroke;
+       for(int i = 0; i < stroke->totvert; i ++){
+               if(i+1 < stroke->totvert){
+                       float v1[3], v2[3];
+                       v1[0] = stroke->points[i*2];
+                       v1[1] = stroke->points[i*2+1];
+                       v1[2] = 0.0f;
+                       v2[0] = stroke->points[i*2+2];
+                       v2[1] = stroke->points[i*2+3];
+                       v2[2] = 0.0f;
+
+                       float zDepth[3] = {0.0f,0.0f,0.0f};
+
+                       ED_view3d_win_to_3d(v3d, sil->ar, zDepth, stroke->points+i*2, v1);
+                       ED_view3d_win_to_3d(v3d, sil->ar, zDepth, stroke->points+i*2+2, v2);
+
+                       if(i == 0){
+                               copy_v3_v3(shape_bb.bmin,v1);
+                               copy_v3_v3(shape_bb.bmax,v1);
+                       }else{
+                               for(int d = 0; d < 3; d++){
+                                       if(shape_bb.bmin[d] > v1[d]){
+                                               shape_bb.bmin[d] = v1[d];
+                                       }
+                                       if(shape_bb.bmax[d] < v1[d]){
+                                               shape_bb.bmax[d] = v1[d];
+                                       }
+                                       if(shape_bb.bmin[d] > v2[d]){
+                                               shape_bb.bmin[d] = v2[d];
+                                       }
+                                       if(shape_bb.bmax[d] < v2[d]){
+                                               shape_bb.bmax[d] = v2[d];
+                                       }
+                               }
+                       }
+#ifdef DEBUG_DRAW
+                       bl_debug_draw_edge_add(v1,v2);
+#endif
+               }
+       }
+
+       /* Find nodes intersecting with the BB of the new shape */
+       pbvh_search_data.ss = ss;
+       pbvh_search_data.bb_target = &shape_bb;
+       BKE_pbvh_search_gather(ss->pbvh, sculpt_search_BB_cb, &pbvh_search_data, &nodes, &totnode);
+
+       printf("Searched and found %i nodes.\n",totnode);
+       if(totnode > 0){
+               printf("The found node is:\n");
+#ifdef DEBUG_DRAW
+               bl_debug_draw_BB_add(&shape_bb,0x00FF00);
+               for(int i = 0; i < totnode; i++){
+                       BB tmp_bb;
+                       BKE_pbvh_node_get_BB(nodes[i],&tmp_bb.bmin,&tmp_bb.bmax);
+                       bl_debug_draw_BB_add(&tmp_bb,0x000000);
+               }
+#endif
+       }else{
+               PBVHNode *root = NULL;
+               PBVHNode *closest_node;
+
+               silhouette_create_shape_mesh(C, me, sil, stroke, v3d, &shape_bb);
+
+               int totprim = BKE_pbvh_recalc_looptri_from_me(pbvh, me);
+
+
+
+               root = BKE_pbvh_node_get_root(pbvh);
+               closest_node = BKE_search_closest_pbvh_leaf_node(pbvh, root, &shape_bb.bmin, &shape_bb.bmax);
+               BB res_bb;
+               BKE_pbvh_node_get_BB(closest_node,&res_bb.bmin,&res_bb.bmax);
+
+               bl_debug_draw_BB_add(&res_bb,0xFF0000);
+               bl_debug_draw_BB_add(&shape_bb,0xFF0000);
+
+               //Todo: unique verts and prim renwe etc.
+               BKE_pbvh_attach_mesh(pbvh, closest_node, me, totprim, &shape_bb.bmin, &shape_bb.bmax);
+       }
+
+       /*cleanup*/
+       WM_cursor_modal_restore(CTX_wm_window(C));
+       ED_region_draw_cb_exit(sil->ar->type,sil->draw_handle);
+       silhouette_data_free(op);
+       op->customdata = NULL;
+}
+
+static int sculpt_silhouette_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+       float mouse[2];
+       copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
+       printf(".");
+       if (event->val == KM_RELEASE) {
+               sculpt_silhouette_stroke_done(C,op);
+               return OPERATOR_FINISHED;
+       }else{
+               sculpt_silhouette_stroke_update(C,mouse,op->customdata);
+               return OPERATOR_RUNNING_MODAL;
+       }
+}
+
+static void sculpt_silhouette_draw(const bContext *C,struct ARegion *ar, void *arg){
+       View3D *v3d = CTX_wm_view3d(C);
+       SilhouetteData *sil = arg;
+
+       /*view3d_operator_needs_opengl(C);*/
+       if(!sil){
+               return;
+       }
+       const SilhouetteStroke *stroke = sil->current_stroke;
+       if(!stroke){
+               return;
+       }
+       float t_mouse[2];
+
+       RegionView3D *rv3d = ar->regiondata;
+
+       glMultMatrixf(rv3d->persinv);
+
+       glLineWidth(1.0f);
+       glEnable(GL_BLEND);
+       glEnable(GL_LINE_SMOOTH);
+
+       /* set brush color */
+       glColor4f(sil->add_col[0],sil->add_col[1],sil->add_col[2], 0.2f);
+
+       if(stroke->points){
+               glBegin(GL_POLYGON); //starts drawing of points
+               for(int i = 0; i < stroke->totvert; i++){
+                       glVertex2f(stroke->points[2*i]*(2.0f/((float)ar->winx))-1.0f,stroke->points[2*i+1]*(2.0f/((float)ar->winy))-1.0f);
+               }
+               glEnd();
+       }
+
+       /* restore GL state */
+       glDisable(GL_BLEND);
+       glDisable(GL_LINE_SMOOTH);
+}
+
+static int sculpt_silhouette_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+       printf("Drawing Silhouette\n");
+
+       SilhouetteData *sil_data;
+
+       sil_data = silhouette_data_new(C,op);
+
+       op->customdata = sil_data;
+
+       /* For tablet rotation Needed?
+       ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
+
+       if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
+               paint_stroke_data_free(op);
+               return OPERATOR_PASS_THROUGH;
+       }*/
+       ED_region_tag_redraw(sil_data->ar);
+
+       sil_data->draw_handle = ED_region_draw_cb_activate(sil_data->ar->type, sculpt_silhouette_draw, op->customdata, REGION_DRAW_PRE_VIEW);
+
+       /* add modal handler */
+       WM_event_add_modal_handler(C, op);
+
+       return OPERATOR_RUNNING_MODAL;
+}
+
+static int sculpt_silhouette_exec(bContext *C, wmOperator *op)
+{
+       printf("Called exec!");
+       if (false){
+               sculpt_silhouette_stroke_done(C,op);
+               return OPERATOR_CANCELLED;
+       }
+
+       sculpt_silhouette_stroke_done(C,op);
+       return OPERATOR_FINISHED;
+}
+
+
+static void SCULPT_OT_silhouette_draw(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Draw Silhouette";
+       ot->idname = "SCULPT_OT_silhouette_draw";
+       ot->description = "Draw a new silhoutte for the sculpt";
+
+       /* api callbacks */
+       ot->invoke = sculpt_silhouette_invoke;
+       ot->modal = sculpt_silhouette_modal;
+       ot->exec = sculpt_silhouette_exec;
+       ot->poll = sculpt_poll;
+       ot->cancel = sculpt_silhouette_stroke_done;
+
+       /* flags */
+       ot->flag = OPTYPE_BLOCKING;
+
+       /* properties */
+
+       paint_stroke_operator_properties(ot);
+
+       RNA_def_boolean(ot->srna, "ignore_background_click", 0,
+                                       "Ignore Background Click",
+                                       "Clicks on the background do not start the stroke");
+}
+/* end Silhouette */
+
 /************************** Dynamic Topology **************************/
 
 static void sculpt_dynamic_topology_triangulate(BMesh *bm)
@@ -5735,6 +6364,7 @@ void ED_operatortypes_sculpt(void)
        WM_operatortype_append(SCULPT_OT_brush_stroke);
        WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
        WM_operatortype_append(SCULPT_OT_set_persistent_base);
+       WM_operatortype_append(SCULPT_OT_silhouette_draw);
        WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
        WM_operatortype_append(SCULPT_OT_optimize);
        WM_operatortype_append(SCULPT_OT_symmetrize);
index 108fe3532e31340a744475030116775dbd16237e..f1475b179c57d7fd615e95de829d192ecb07363e 100644 (file)
 #include "DNA_listBase.h"
 #include "DNA_vec_types.h"
 #include "DNA_key_types.h"
-
+#include "DNA_customdata_types.h"
 #include "BLI_bitmap.h"
 #include "BKE_pbvh.h"
 
 struct bContext;
-struct KeyBlock;
 struct Object;
 struct SculptUndoNode;
 
@@ -64,7 +63,7 @@ void sculpt_dynamic_topology_disable(struct bContext *C,
 
 /* Undo */
 
-typedef enum {
+typedef enum SculptUndoType {
        SCULPT_UNDO_COORDS,
        SCULPT_UNDO_HIDDEN,
        SCULPT_UNDO_MASK,
@@ -76,7 +75,7 @@ typedef enum {
 typedef struct SculptUndoNode {
        struct SculptUndoNode *next, *prev;
 
-       SculptUndoType type;
+       enum SculptUndoType type;
 
        char idname[MAX_ID_NAME];   /* name instead of pointer*/
        void *node;                 /* only during push, not valid afterwards! */
index 250e6559b8f268bd60b37e56614ef75e84eb8772..71e1d2272f5e5618d7d2ebf9ecc9a8cd54ebd7c1 100644 (file)
@@ -112,7 +112,7 @@ static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *
 
 /* handy utility for drawing shapes in the viewport for arbitrary code.
  * could add lines and points too */
-// #define DEBUG_DRAW
+#define DEBUG_DRAW
 #ifdef DEBUG_DRAW
 static void bl_debug_draw(void);
 /* add these locally when using these functions for testing */
index f4a1677efc457d7f4a0ab554b6ed35c5d168ed40..2f70e763b1532d7487e3081c3d017ee1e90ea1bf 100644 (file)
@@ -119,6 +119,8 @@ typedef struct Brush {
 
        float unprojected_radius;
 
+       float adaptive_space_factor;
+
        /* soften/sharpen */
        float sharp_threshold;
        int blur_kernel_radius;
@@ -135,6 +137,8 @@ typedef struct Brush {
 
        float mask_stencil_pos[2];
        float mask_stencil_dimension[2];
+
+       float pad;
 } Brush;
 
 typedef struct PaletteColor {
index ac348c1750cc5ddb1abf9e5361033d7807f149e1..0188155858c37d2a186e1be6221f06b05df39812 100644 (file)
@@ -1224,7 +1224,6 @@ static void rna_def_brush(BlenderRNA *brna)
                                 "Automatically adjust strength to give consistent results for different spacings");
        RNA_def_property_update(prop, 0, "rna_Brush_update");
 
-       /* adaptive space is not implemented yet */
        prop = RNA_def_property(srna, "use_adaptive_space", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ADAPTIVE_SPACE);
        RNA_def_property_ui_text(prop, "Adaptive Spacing",