- grease pencil mode for drawing onto geometry (using the z-buffer), access in the 3D view panel.

- 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.
This commit is contained in:
Campbell Barton 2010-01-01 15:05:31 +00:00
parent c58f2dfc9d
commit 30aff3b830
6 changed files with 143 additions and 27 deletions

@ -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");
}

@ -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 */

@ -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

@ -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) */
/* **************************************************** */

@ -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 */

@ -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", "");
}
/* --- */