- grease pencil mode for drawing onto geometry (using the z-buffer), access in the...
authorCampbell Barton <ideasman42@gmail.com>
Fri, 1 Jan 2010 15:05:31 +0000 (15:05 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 1 Jan 2010 15:05:31 +0000 (15:05 +0000)
- account for parts of the line going off into infinity by making the stroke stretch between the last valid depth values (like an elastic band), if the endpoints are not over any geometry then use the closest valid depth.

source/blender/editors/gpencil/gpencil_buttons.c
source/blender/editors/gpencil/gpencil_paint.c
source/blender/editors/include/ED_view3d.h
source/blender/editors/space_view3d/view3d_edit.c
source/blender/makesdna/DNA_gpencil_types.h
source/blender/makesrna/intern/rna_gpencil.c

index 5deffbabb778e6e1340e32245761252f1288896e..54dd43160a6e1388929b6674b67a546c35c921ca 100644 (file)
@@ -229,7 +229,7 @@ static void draw_gpencil_panel (bContext *C, uiLayout *layout, bGPdata *gpd, Poi
 {
        PointerRNA gpd_ptr;
        bGPDlayer *gpl;
-       uiLayout *col;
+       uiLayout *col, *row;
        
        /* make new PointerRNA for Grease Pencil block */
        RNA_id_pointer_create((ID *)gpd, &gpd_ptr);
@@ -259,7 +259,11 @@ static void draw_gpencil_panel (bContext *C, uiLayout *layout, bGPdata *gpd, Poi
                uiItemL(col, "Drawing Settings:", 0);
                
                /* 'stick to view' option */
-               uiItemR(col, NULL, 0, &gpd_ptr, "view_space_draw", 0);
+               //uiItemR(col, NULL, 0, &gpd_ptr, "draw_mode", 0);
+               row= uiLayoutRow(layout, 1);
+               uiItemEnumR_string(row, NULL, 0, &gpd_ptr, "draw_mode", "VIEW");
+               uiItemEnumR_string(row, NULL, 0, &gpd_ptr, "draw_mode", "CURSOR");
+               uiItemEnumR_string(row, NULL, 0, &gpd_ptr, "draw_mode", "DEPTH");
 }      
 
 
index 3f9e3e04411201b1c801fc8b978355030170deff..86ca69f6cf66b85e672724ea4ca491b77cdf90db 100644 (file)
@@ -155,15 +155,7 @@ static int gpencil_draw_poll (bContext *C)
 static int gpencil_project_check (tGPsdata *p)
 {
        bGPdata *gpd= p->gpd;
-       
-       if(     (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) &&
-               (p->scene->toolsettings->snap_mode==SCE_SNAP_MODE_FACE) &&
-               (p->scene->toolsettings->snap_flag & SCE_SNAP_PROJECT) )
-       {
-               return 1;
-       }
-
-       return 0;
+       return ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) && (p->gpd->flag & GP_DATA_VIEWDEPTH)) ? 1:0;
 }
 
 /* ******************************************* */
@@ -220,13 +212,13 @@ static short gp_stroke_filtermval (tGPsdata *p, int mval[2], int pmval[2])
 
 /* convert screen-coordinates to buffer-coordinates */
 // XXX this method needs a total overhaul!
-static void gp_stroke_convertcoords (tGPsdata *p, short mval[], float out[])
+static void gp_stroke_convertcoords (tGPsdata *p, short mval[], float out[], float *depth)
 {
        bGPdata *gpd= p->gpd;
        
        /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
        if (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) {
-               if(gpencil_project_check(p) && (view_autodist_simple(p->ar, mval, out))) {
+               if(gpencil_project_check(p) && (view_autodist_simple(p->ar, mval, out, depth))) {
                        /* projecting onto 3D-Geometry
                         *      - nothing more needs to be done here, since view_autodist_simple() has already done it
                         */
@@ -501,7 +493,7 @@ static void gp_stroke_newfrombuffer (tGPsdata *p)
                        ptc= gpd->sbuffer;
                        
                        /* convert screen-coordinates to appropriate coordinates (and store them) */
-                       gp_stroke_convertcoords(p, &ptc->x, &pt->x);
+                       gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
                        
                        /* copy pressure */
                        pt->pressure= ptc->pressure;
@@ -514,23 +506,107 @@ static void gp_stroke_newfrombuffer (tGPsdata *p)
                        ptc= ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1);
                        
                        /* convert screen-coordinates to appropriate coordinates (and store them) */
-                       gp_stroke_convertcoords(p, &ptc->x, &pt->x);
+                       gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
                        
                        /* copy pressure */
                        pt->pressure= ptc->pressure;
                }
        }
        else {
+               float *depth_arr= NULL;
+
+               /* get an array of depths, far depths are blended */
+               if(gpencil_project_check(p)) {
+                       short mval[2];
+                       int interp_depth = 0;
+                       int found_depth = 0;
+
+                       depth_arr= MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points");
+
+                       for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size; i++, ptc++, pt++) {
+                               mval[0]= ptc->x; mval[1]= ptc->y;
+                               if(view_autodist_depth(p->ar, mval, depth_arr+i) == 0)
+                                       interp_depth= TRUE;
+                               else
+                                       found_depth= TRUE;
+                       }
+
+                       if(found_depth==FALSE) {
+                               /* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
+                               for (i=gpd->sbuffer_size-1; i >= 0; i--)
+                                       depth_arr[i] = 0.9999f;
+                       }
+                       else if(interp_depth) {
+                               /* found invalid depths, interpolate */
+                               float valid_last= FLT_MAX;
+                               int valid_ofs= 0;
+
+                               float *depth_arr_up= MEM_callocN(sizeof(float) * gpd->sbuffer_size, "depth_points_up");
+                               float *depth_arr_down= MEM_callocN(sizeof(float) * gpd->sbuffer_size, "depth_points_down");
+
+                               int *depth_tot_up= MEM_callocN(sizeof(int) * gpd->sbuffer_size, "depth_tot_up");
+                               int *depth_tot_down= MEM_callocN(sizeof(int) * gpd->sbuffer_size, "depth_tot_down");
+
+                               for (i=0; i < gpd->sbuffer_size; i++) {
+                                       if(depth_arr[i] == FLT_MAX) {
+                                               depth_arr_up[i]= valid_last;
+                                               depth_tot_up[i]= ++valid_ofs;
+                                       }
+                                       else {
+                                               valid_last= depth_arr[i];
+                                               valid_ofs= 0;
+                                       }
+                               }
+
+                               valid_last= FLT_MAX;
+                               valid_ofs= 0;
+
+                               for (i=gpd->sbuffer_size-1; i >= 0; i--) {
+                                       if(depth_arr[i] == FLT_MAX) {
+                                               depth_arr_down[i]= valid_last;
+                                               depth_tot_down[i]= ++valid_ofs;
+                                       }
+                                       else {
+                                               valid_last= depth_arr[i];
+                                               valid_ofs= 0;
+                                       }
+                               }
+
+                               /* now blend */
+                               for (i=0; i < gpd->sbuffer_size; i++) {
+                                       if(depth_arr[i] == FLT_MAX) {
+                                               if(depth_arr_up[i] != FLT_MAX && depth_arr_down[i] != FLT_MAX) {
+                                                       depth_arr[i]= ((depth_arr_up[i] * depth_tot_down[i]) +  (depth_arr_down[i] * depth_tot_up[i])) / (float)(depth_tot_down[i] + depth_tot_up[i]);
+                                               } else if (depth_arr_up[i] != FLT_MAX) {
+                                                       depth_arr[i]= depth_arr_up[i];
+                                               } else if (depth_arr_down[i] != FLT_MAX) {
+                                                       depth_arr[i]= depth_arr_down[i];
+                                               }
+                                       }
+                               }
+
+                               MEM_freeN(depth_arr_up);
+                               MEM_freeN(depth_arr_down);
+
+                               MEM_freeN(depth_tot_up);
+                               MEM_freeN(depth_tot_down);
+                       }
+               }
+
+
+               pt= gps->points;
+
                /* convert all points (normal behaviour) */
-               for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++) {
+               for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++, pt++) {
                        /* convert screen-coordinates to appropriate coordinates (and store them) */
-                       gp_stroke_convertcoords(p, &ptc->x, &pt->x);
+                       gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr+i:NULL);
                        
                        /* copy pressure */
                        pt->pressure= ptc->pressure;
-                       
-                       pt++;
                }
+
+               if(depth_arr)
+                       MEM_freeN(depth_arr);
        }
        
        /* add stroke to frame */
index de5a9fe4e07cdeeca29078cdf51dda4d627920d9..2e439f8fdef049d78d475d93e7b5173924a57adf 100644 (file)
@@ -128,7 +128,8 @@ int view_autodist(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, s
 
 /* only draw so view_autodist_simple can be called many times after */
 int view_autodist_init(struct Scene *scene, struct ARegion *ar, struct View3D *v3d);
-int view_autodist_simple(struct ARegion *ar, short *mval, float mouse_worldloc[3]);
+int view_autodist_simple(struct ARegion *ar, short *mval, float mouse_worldloc[3], float *force_depth);
+int view_autodist_depth(struct ARegion *ar, short *mval, float *depth);
 
 /* select */
 #define MAXPICKBUF      10000
index 9b0712ac25580bbc45a86aef2426c981834e087f..bfd2ecb4939e62e3690d51f5a0b91caacebf85ba 100644 (file)
@@ -2282,7 +2282,7 @@ int view_autodist_init(Scene *scene, ARegion *ar, View3D *v3d) //, float *autodi
 }
 
 // no 4x4 sampling, run view_autodist_init first
-int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3] ) //, float *autodist )
+int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3], float *force_depth) //, float *autodist )
 {
        RegionView3D *rv3d= ar->regiondata;
        bglMats mats; /* ZBuffer depth vars, could cache? */
@@ -2295,15 +2295,18 @@ int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3] ) //,
        if (mval[1] >= rv3d->depths->h) return 0;
 
        /* Get Z Depths, needed for perspective, nice for ortho */
-       bgl_get_mats(&mats);
-       depth= rv3d->depths->depths[mval[1]*rv3d->depths->w+mval[0]];
+       if(force_depth)
+               depth= *force_depth;
+       else
+               depth= rv3d->depths->depths[mval[1]*rv3d->depths->w+mval[0]];
 
-       if (depth==MAXFLOAT)
+       if (depth==FLT_MAX)
                return 0;
 
        cent[0] = (double)mval[0];
        cent[1] = (double)mval[1];
 
+       bgl_get_mats(&mats);
        if (!gluUnProject(cent[0], cent[1], depth, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
                return 0;
 
@@ -2313,6 +2316,29 @@ int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3] ) //,
        return 1;
 }
 
+int view_autodist_depth(struct ARegion *ar, short *mval, float *depth)
+{
+       RegionView3D *rv3d= ar->regiondata;
+       *depth= FLT_MAX;
+
+       if (mval[0] < 0) return 0;
+       if (mval[1] < 0) return 0;
+       if (mval[0] >= rv3d->depths->w) return 0;
+       if (mval[1] >= rv3d->depths->h) return 0;
+
+       /* Get Z Depths, needed for perspective, nice for ortho */
+       *depth= rv3d->depths->depths[mval[1]*rv3d->depths->w+mval[0]];
+
+       /* float error means we need to shave off some */
+
+       if(*depth >= 1.0) {
+               *depth= FLT_MAX;
+       }
+
+       return (*depth==FLT_MAX) ? 0:1;
+               return 0;
+}
+
 /* ********************* NDOF ************************ */
 /* note: this code is confusing and unclear... (ton) */
 /* **************************************************** */
index 4bae9935ea738fe262c3eea87266bab5b9a2cf11..9ba3c243d2089c3beacd3695ff7eb830fe70bc17 100644 (file)
@@ -146,5 +146,7 @@ typedef struct bGPdata {
 #define GP_DATA_EDITPAINT      (1<<3)
        /* new strokes are added in viewport space */
 #define GP_DATA_VIEWALIGN      (1<<4)
+       /* Project into the screens Z values */
+#define GP_DATA_VIEWDEPTH      (1<<5)
 
 #endif /*  DNA_GPENCIL_TYPES_H */
index 129fad4e98cefc5c03edbedb7a7a41cac8a9fad7..d55f5f21e72d2fe1b93b422ff5451bf7ab526c04 100644 (file)
@@ -220,6 +220,12 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
        StructRNA *srna;
        PropertyRNA *prop;
        
+       static EnumPropertyItem draw_mode_items[] = {
+               {GP_DATA_VIEWALIGN, "CURSOR", 0, "Cursor", ""},
+               {0, "VIEW", 0, "View", ""}, /* weired, GP_DATA_VIEWALIGN is inverted */
+               {GP_DATA_VIEWALIGN|GP_DATA_VIEWDEPTH, "DEPTH", 0, "Depth", ""},
+               {0, NULL, 0, NULL, NULL}};
+
        srna= RNA_def_struct(brna, "GreasePencil", "ID");
        RNA_def_struct_sdna(srna, "bGPdata");
        RNA_def_struct_ui_text(srna, "Grease Pencil", "Freehand annotation sketchbook.");
@@ -232,9 +238,10 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Layers", "Similar to layers in Photoshop.");
        
        /* Flags */
-       prop= RNA_def_property(srna, "view_space_draw", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_DATA_VIEWALIGN);
-       RNA_def_property_ui_text(prop, "Stick to View", "Newly drawn strokes get added in view space (i.e. sketches stick to data when view is manipulated).");
+       prop= RNA_def_property(srna, "draw_mode", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+       RNA_def_property_enum_items(prop, draw_mode_items);
+       RNA_def_property_ui_text(prop, "Draw Mode", "");
 }
 
 /* --- */