diff options
Diffstat (limited to 'source/blender/editors/gpencil/drawgpencil.c')
-rw-r--r-- | source/blender/editors/gpencil/drawgpencil.c | 693 |
1 files changed, 544 insertions, 149 deletions
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 76502a43eb7..eb2ffb13f20 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -58,6 +58,10 @@ #include "ED_gpencil.h" #include "ED_view3d.h" +#include "UI_resources.h" + +#include "gpencil_intern.h" + /* ************************************************** */ /* GREASE PENCIL DRAWING */ @@ -71,6 +75,9 @@ typedef enum eDrawStrokeFlags { GP_DRAWDATA_ONLYI2D = (1 << 3), /* only draw 'image' strokes */ GP_DRAWDATA_IEDITHACK = (1 << 4), /* special hack for drawing strokes in Image Editor (weird coordinates) */ GP_DRAWDATA_NO_XRAY = (1 << 5), /* don't draw xray in 3D view (which is default) */ + GP_DRAWDATA_NO_ONIONS = (1 << 6), /* no onionskins should be drawn (for animation playback) */ + GP_DRAWDATA_VOLUMETRIC = (1 << 7), /* draw strokes as "volumetric" circular billboards */ + GP_DRAWDATA_FILL = (1 << 8), /* fill insides/bounded-regions of strokes */ } eDrawStrokeFlags; @@ -142,6 +149,200 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn } } +/* --------- 2D Stroke Drawing Helpers --------- */ + +/* helper function to calculate x-y drawing coordinates for 2D points */ +static void gp_calc_2d_stroke_xy(bGPDspoint *pt, short sflag, int offsx, int offsy, int winx, int winy, float r_co[2]) +{ + if (sflag & GP_STROKE_2DSPACE) { + r_co[0] = pt->x; + r_co[1] = pt->y; + } + else if (sflag & GP_STROKE_2DIMAGE) { + const float x = (float)((pt->x * winx) + offsx); + const float y = (float)((pt->y * winy) + offsy); + + r_co[0] = x; + r_co[1] = y; + } + else { + const float x = (float)(pt->x / 100 * winx) + offsx; + const float y = (float)(pt->y / 100 * winy) + offsy; + + r_co[0] = x; + r_co[1] = y; + } +} + +/* ----------- Volumetric Strokes --------------- */ + +/* draw a 2D buffer stroke in "volumetric" style + * NOTE: the stroke buffer doesn't have any coordinate offsets/transforms + */ +static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, short thickness, short dflag, short sflag) +{ + GLUquadricObj *qobj = gluNewQuadric(); + float modelview[4][4]; + + tGPspoint *pt; + int i; + + /* error checking */ + if ((points == NULL) || (totpoints <= 0)) + return; + + /* check if buffer can be drawn */ + if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D)) + return; + + /* get basic matrix - should be camera space (i.e "identity") */ + glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview); + + /* draw points */ + glPushMatrix(); + + for (i = 0, pt = points; i < totpoints; i++, pt++) { + /* set the transformed position */ + // TODO: scale should change based on zoom level, which requires proper translation mult too! + modelview[3][0] = pt->x; + modelview[3][1] = pt->y; + + glLoadMatrixf((float *)modelview); + + /* draw the disk using the current state... */ + gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1); + + + modelview[3][0] = modelview[3][1] = 0.0f; + } + + glPopMatrix(); + gluDeleteQuadric(qobj); +} + +/* draw a 2D strokes in "volumetric" style */ +static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, + int offsx, int offsy, int winx, int winy) +{ + GLUquadricObj *qobj = gluNewQuadric(); + float modelview[4][4]; + float baseloc[3]; + + bGPDspoint *pt; + int i; + + + /* get basic matrix */ + glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview); + copy_v3_v3(baseloc, modelview[3]); + + /* draw points */ + glPushMatrix(); + + for (i = 0, pt = points; i < totpoints; i++, pt++) { + /* set the transformed position */ + float co[2]; + + gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co); + translate_m4(modelview, co[0], co[1], 0.0f); + + glLoadMatrixf((float *)modelview); + + /* draw the disk using the current state... */ + gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1); + + /* restore matrix */ + copy_v3_v3(modelview[3], baseloc); + } + + glPopMatrix(); + gluDeleteQuadric(qobj); +} + +/* draw a 3D stroke in "volumetric" style */ +static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag) +{ + GLUquadricObj *qobj = gluNewQuadric(); + + float base_modelview[4][4], modelview[4][4]; + float base_loc[3]; + + bGPDspoint *pt; + int i; + + + /* Get the basic modelview matrix we use for performing calculations */ + glGetFloatv(GL_MODELVIEW_MATRIX, (float *)base_modelview); + copy_v3_v3(base_loc, base_modelview[3]); + + /* Create the basic view-aligned billboard matrix we're going to actually draw qobj with: + * - We need to knock out the rotation so that we are + * simply left with a camera-facing billboard + * - The scale factors here are chosen so that the thickness + * is relatively reasonable. Otherwise, it gets far too + * large! + */ + scale_m4_fl(modelview, 0.1f); + + /* draw each point as a disk... */ + glPushMatrix(); + + for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { + /* apply translation to base_modelview, so that the translated point is put in the right place */ + translate_m4(base_modelview, pt->x, pt->y, pt->z); + + /* copy the translation component to the billboard matrix we're going to use, + * then reset the base matrix to the original values so that we can do the same + * for the next point without accumulation/pollution effects + */ + copy_v3_v3(modelview[3], base_modelview[3]); /* copy offset value */ + copy_v3_v3(base_modelview[3], base_loc); /* restore */ + + /* apply our billboard matrix for drawing... */ + glLoadMatrixf((float *)modelview); + + /* draw the disk using the current state... */ + gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1); + } + + glPopMatrix(); + gluDeleteQuadric(qobj); +} + + +/* --------------- Stroke Fills ----------------- */ + +/* draw fills for shapes */ +static void gp_draw_stroke_fill(bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, + int offsx, int offsy, int winx, int winy) +{ + bGPDspoint *pt; + int i; + + BLI_assert(totpoints >= 3); + + /* As an initial implementation, we use the OpenGL filled polygon drawing + * here since it's the easiest option to implement for this case. It does + * come with limitations (notably for concave shapes), though it shouldn't + * be much of an issue in most cases. + */ + glBegin(GL_POLYGON); + + for (i = 0, pt = points; i < totpoints; i++, pt++) { + if (sflag & GP_STROKE_3DSPACE) { + glVertex3fv(&pt->x); + } + else { + float co[2]; + + gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co); + glVertex2fv(co); + } + } + + glEnd(); +} + /* ----- Existing Strokes Drawing (3D and Point) ------ */ /* draw a given stroke - just a single dot (only one point) */ @@ -158,18 +359,7 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla float co[2]; /* get coordinates of point */ - if (sflag & GP_STROKE_2DSPACE) { - co[0] = points->x; - co[1] = points->y; - } - else if (sflag & GP_STROKE_2DIMAGE) { - co[0] = (points->x * winx) + offsx; - co[1] = (points->y * winy) + offsy; - } - else { - co[0] = (points->x / 100 * winx) + offsx; - co[1] = (points->y / 100 * winy) + offsy; - } + gp_calc_2d_stroke_xy(points, sflag, offsx, offsy, winx, winy, co); /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok * - also mandatory in if Image Editor 'image-based' dot @@ -198,7 +388,7 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla } /* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */ -static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, short debug) +static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug, short sflag) { bGPDspoint *pt; float curpressure = points[0].pressure; @@ -231,6 +421,7 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness glEnd(); /* draw debug points of curve on top? */ + /* XXX: for now, we represent "selected" strokes in the same way as debug, which isn't used anymore */ if (debug) { glBegin(GL_POINTS); for (i = 0, pt = points; i < totpoints && pt; i++, pt++) @@ -242,8 +433,8 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness /* ----- Fancy 2D-Stroke Drawing ------ */ /* draw a given stroke in 2d */ -static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, - short debug, int offsx, int offsy, int winx, int winy) +static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, + bool debug, int offsx, int offsy, int winx, int winy) { /* otherwise thickness is twice that of the 3D view */ float thickness = (float)thickness_s * 0.5f; @@ -259,21 +450,10 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, glBegin(GL_LINE_STRIP); for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { - if (sflag & GP_STROKE_2DSPACE) { - glVertex2f(pt->x, pt->y); - } - else if (sflag & GP_STROKE_2DIMAGE) { - const float x = (pt->x * winx) + offsx; - const float y = (pt->y * winy) + offsy; - - glVertex2f(x, y); - } - else { - const float x = (pt->x / 100 * winx) + offsx; - const float y = (pt->y / 100 * winy) + offsy; - - glVertex2f(x, y); - } + float co[2]; + + gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co); + glVertex2fv(co); } glEnd(); } @@ -297,22 +477,8 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, float pthick; /* thickness at segment point */ /* get x and y coordinates from points */ - if (sflag & GP_STROKE_2DSPACE) { - s0[0] = pt1->x; s0[1] = pt1->y; - s1[0] = pt2->x; s1[1] = pt2->y; - } - else if (sflag & GP_STROKE_2DIMAGE) { - s0[0] = (pt1->x * winx) + offsx; - s0[1] = (pt1->y * winy) + offsy; - s1[0] = (pt2->x * winx) + offsx; - s1[1] = (pt2->y * winy) + offsy; - } - else { - s0[0] = (pt1->x / 100 * winx) + offsx; - s0[1] = (pt1->y / 100 * winy) + offsy; - s1[0] = (pt2->x / 100 * winx) + offsx; - s1[1] = (pt2->y / 100 * winy) + offsy; - } + gp_calc_2d_stroke_xy(pt1, sflag, offsx, offsy, winx, winy, s0); + gp_calc_2d_stroke_xy(pt2, sflag, offsx, offsy, winx, winy, s1); /* calculate gradient and normal - 'angle'=(ny/nx) */ m1[1] = s1[1] - s0[1]; @@ -446,52 +612,57 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, glBegin(GL_POINTS); for (i = 0, pt = points; i < totpoints && pt; i++, pt++) { - if (sflag & GP_STROKE_2DSPACE) { - glVertex2fv(&pt->x); - } - else if (sflag & GP_STROKE_2DIMAGE) { - const float x = (float)((pt->x * winx) + offsx); - const float y = (float)((pt->y * winy) + offsy); - - glVertex2f(x, y); - } - else { - const float x = (float)(pt->x / 100 * winx) + offsx; - const float y = (float)(pt->y / 100 * winy) + offsy; - - glVertex2f(x, y); - } + float co[2]; + + gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co); + glVertex2fv(co); } glEnd(); } } -/* ----- General Drawing ------ */ +/* ----- Strokes Drawing ------ */ + +/* Helper for doing all the checks on whether a stroke can be drawn */ +static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag) +{ + /* skip stroke if it isn't in the right display space for this drawing context */ + /* 1) 3D Strokes */ + if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE)) + return false; + if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE)) + return false; + + /* 2) Screen Space 2D Strokes */ + if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE)) + return false; + if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE)) + return false; + + /* 3) Image Space (2D) */ + if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE)) + return false; + if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE)) + return false; + + + /* skip stroke if it doesn't have any valid data */ + if ((gps->points == NULL) || (gps->totpoints < 1)) + return false; + + /* stroke can be drawn */ + return true; +} /* draw a set of strokes */ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag, - short debug, short lthick, const float color[4]) + bool debug, short lthick, const float color[4], const float fill_color[4]) { bGPDstroke *gps; - /* set color first (may need to reset it again later too) */ - glColor4fv(color); - for (gps = gpf->strokes.first; gps; gps = gps->next) { - /* check if stroke can be drawn - checks here generally fall into pairs */ - if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE)) - continue; - if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE)) - continue; - if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE)) - continue; - if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE)) - continue; - if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE)) - continue; - if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE)) - continue; - if ((gps->points == NULL) || (gps->totpoints < 1)) + /* check if stroke can be drawn */ + if (gp_can_draw_stroke(gps, dflag) == false) continue; /* check which stroke-drawer to use */ @@ -513,11 +684,27 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int #endif } - if (gps->totpoints == 1) { - gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + /* 3D Fill */ + if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) { + glColor4fv(fill_color); + gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + } + + /* 3D Stroke */ + glColor4fv(color); + + if (dflag & GP_DRAWDATA_VOLUMETRIC) { + /* volumetric stroke drawing */ + gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, lthick, dflag, gps->flag); } else { - gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug); + /* 3D Lines - OpenGL primitives-based */ + if (gps->totpoints == 1) { + gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + } + else { + gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug, gps->flag); + } } if (no_xray) { @@ -532,14 +719,229 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int } } else { - if (gps->totpoints == 1) { - gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + /* 2D - Fill */ + if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) { + gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + } + + /* 2D Strokes... */ + glColor4fv(color); + + if (dflag & GP_DRAWDATA_VOLUMETRIC) { + /* blob/disk-based "volumetric" drawing */ + gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + } + else { + /* normal 2D strokes */ + if (gps->totpoints == 1) { + gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy); + } + else { + gp_draw_stroke_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy); + } + } + } + } +} + +/* Draw selected verts for strokes being edited */ +static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, const float tcolor[3]) +{ + bGPDstroke *gps; + + const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY); + int mask_orig = 0; + + /* set up depth masks... */ + if (dflag & GP_DRAWDATA_ONLY3D) { + if (no_xray) { + glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); + glDepthMask(0); + glEnable(GL_DEPTH_TEST); + + /* first arg is normally rv3d->dist, but this isn't + * available here and seems to work quite well without */ + bglPolygonOffset(1.0f, 1.0f); +#if 0 + glEnable(GL_POLYGON_OFFSET_LINE); + glPolygonOffset(-1.0f, -1.0f); +#endif + } + } + + + /* draw stroke verts */ + for (gps = gpf->strokes.first; gps; gps = gps->next) { + bGPDspoint *pt; + float vsize, bsize; + int i; + + /* check if stroke can be drawn */ + if (gp_can_draw_stroke(gps, dflag) == false) + continue; + + /* Optimisation: only draw points for selected strokes + * We assume that selected points can only occur in + * strokes that are selected too. + */ + if ((gps->flag & GP_STROKE_SELECT) == 0) + continue; + + /* Get size of verts: + * - The selected state needs to be larger than the unselected state so that + * they stand out more. + * - We use the theme setting for size of the unselected verts + */ + bsize = UI_GetThemeValuef(TH_VERTEX_SIZE); + if ((int)bsize > 8) { + vsize = 10.0f; + bsize = 8.0f; + } + else { + vsize = bsize + 2; + } + + /* First Pass: Draw all the verts (i.e. these become the unselected state) */ + if (tcolor != NULL) { + /* for now, we assume that the base color of the points is not too close to the real color */ + glColor3fv(tcolor); + } + else { + /* this doesn't work well with the default theme and black strokes... */ + UI_ThemeColor(TH_VERTEX); + } + glPointSize(bsize); + + glBegin(GL_POINTS); + for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) { + if (gps->flag & GP_STROKE_3DSPACE) { + glVertex3fv(&pt->x); } else { - gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy); + float co[2]; + + gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co); + glVertex2fv(co); + } + } + glEnd(); + + + /* Second Pass: Draw only verts which are selected */ + UI_ThemeColor(TH_VERTEX_SELECT); + glPointSize(vsize); + + glBegin(GL_POINTS); + for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + if (gps->flag & GP_STROKE_3DSPACE) { + glVertex3fv(&pt->x); + } + else { + float co[2]; + + gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co); + glVertex2fv(co); + } + } + } + glEnd(); + } + + + /* clear depth mask */ + if (dflag & GP_DRAWDATA_ONLY3D) { + if (no_xray) { + glDepthMask(mask_orig); + glDisable(GL_DEPTH_TEST); + + bglPolygonOffset(0.0, 0.0); +#if 0 + glDisable(GL_POLYGON_OFFSET_LINE); + glPolygonOffset(0, 0); +#endif + } + } +} + +/* ----- General Drawing ------ */ + +/* draw onion-skinning for a layer */ +static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, + int cfra, int dflag, short debug, short lthick) +{ + const float alpha = gpl->color[3]; + float color[4]; + + /* 1) Draw Previous Frames First */ + if (gpl->flag & GP_LAYER_GHOST_PREVCOL) { + copy_v3_v3(color, gpl->gcolor_prev); + } + else { + copy_v3_v3(color, gpl->color); + } + + if (gpl->gstep) { + bGPDframe *gf; + float fac; + + /* draw previous frames first */ + for (gf = gpf->prev; gf; gf = gf->prev) { + /* check if frame is drawable */ + if ((gpf->framenum - gf->framenum) <= gpl->gstep) { + /* alpha decreases with distance from curframe index */ + fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1)); + color[3] = alpha * fac * 0.66f; + gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color); + } + else + break; + } + } + else { + /* draw the strokes for the ghost frames (at half of the alpha set by user) */ + if (gpf->prev) { + color[3] = (alpha / 7); + gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, color, color); + } + } + + + /* 2) Now draw next frames */ + if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) { + copy_v3_v3(color, gpl->gcolor_next); + } + else { + copy_v3_v3(color, gpl->color); + } + + if (gpl->gstep_next) { + bGPDframe *gf; + float fac; + + /* now draw next frames */ + for (gf = gpf->next; gf; gf = gf->next) { + /* check if frame is drawable */ + if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) { + /* alpha decreases with distance from curframe index */ + fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1)); + color[3] = alpha * fac * 0.66f; + gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color); } + else + break; + } + } + else { + /* draw the strokes for the ghost frames (at half of the alpha set by user) */ + if (gpf->next) { + color[3] = (alpha / 4); + gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, color, color); } } + + /* 3) restore alpha */ + glColor4fv(gpl->color); } /* draw grease-pencil datablock */ @@ -561,9 +963,8 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { bGPDframe *gpf; - short debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? 1 : 0; + bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false; short lthick = gpl->thickness; - float color[4], tcolor[4]; /* don't draw layer if hidden */ if (gpl->flag & GP_LAYER_HIDE) @@ -576,72 +977,54 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, /* set color, stroke thickness, and point size */ glLineWidth(lthick); - copy_v4_v4(color, gpl->color); // just for copying 4 array elements - copy_v4_v4(tcolor, gpl->color); // additional copy of color (for ghosting) - glColor4fv(color); glPointSize((float)(gpl->thickness + 2)); - /* apply xray layer setting */ - if (gpl->flag & GP_LAYER_NO_XRAY) dflag |= GP_DRAWDATA_NO_XRAY; - else dflag &= ~GP_DRAWDATA_NO_XRAY; + /* Add layer drawing settings to the set of "draw flags" + * NOTE: If the setting doesn't apply, it *must* be cleared, + * as dflag's carry over from the previous layer + */ +#define GP_DRAWFLAG_APPLY(condition, draw_flag_value) { \ + if (condition) dflag |= (draw_flag_value); \ + else dflag &= ~(draw_flag_value); \ + } (void)0 + + /* xray... */ + GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY); + + /* volumetric strokes... */ + GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC); + + /* fill strokes... */ + // XXX: this is not a very good limit + GP_DRAWFLAG_APPLY((gpl->fill[3] > 0.001f), GP_DRAWDATA_FILL); +#undef GP_DRAWFLAG_APPLY /* draw 'onionskins' (frame left + right) */ - if (gpl->flag & GP_LAYER_ONIONSKIN) { - /* drawing method - only immediately surrounding (gstep = 0), - * or within a frame range on either side (gstep > 0)*/ - if (gpl->gstep) { - bGPDframe *gf; - float fac; - - /* draw previous frames first */ - for (gf = gpf->prev; gf; gf = gf->prev) { - /* check if frame is drawable */ - if ((gpf->framenum - gf->framenum) <= gpl->gstep) { - /* alpha decreases with distance from curframe index */ - fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1)); - tcolor[3] = color[3] * fac * 0.66f; - gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); - } - else - break; - } - - /* now draw next frames */ - for (gf = gpf->next; gf; gf = gf->next) { - /* check if frame is drawable */ - if ((gf->framenum - gpf->framenum) <= gpl->gstep) { - /* alpha decreases with distance from curframe index */ - fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep + 1)); - tcolor[3] = color[3] * fac * 0.66f; - gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); - } - else - break; - } - - /* restore alpha */ - glColor4fv(color); - } - else { - /* draw the strokes for the ghost frames (at half of the alpha set by user) */ - if (gpf->prev) { - tcolor[3] = (color[3] / 7); - gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); - } - - if (gpf->next) { - tcolor[3] = (color[3] / 4); - gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); - } - - /* restore alpha */ - glColor4fv(color); - } + if ((gpl->flag & GP_LAYER_ONIONSKIN) && !(dflag & GP_DRAWDATA_NO_ONIONS)) { + /* Drawing method - only immediately surrounding (gstep = 0), + * or within a frame range on either side (gstep > 0) + */ + gp_draw_onionskins(gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, lthick); } /* draw the strokes already in active frame */ - tcolor[3] = color[3]; - gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor); + gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, gpl->color, gpl->fill); + + /* Draw verts of selected strokes + * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering + * - locked layers can't be edited, so there's no point showing these verts + * as they will have no bearings on what gets edited + * - only show when in editmode, since operators shouldn't work otherwise + * (NOTE: doing it this way means that the toggling editmode shows visible change immediately) + */ + /* XXX: perhaps we don't want to show these when users are drawing... */ + if ((G.f & G_RENDER_OGL) == 0 && + (gpl->flag & GP_LAYER_LOCKED) == 0 && + (gpd->flag & GP_DATA_STROKE_EDITMODE)) + { + gp_draw_strokes_edit(gpf, offsx, offsy, winx, winy, dflag, + (gpl->color[3] < 0.95f) ? gpl->color : NULL); + } /* Check if may need to draw the active stroke cache, only if this layer is the active layer * that is being edited. (Stroke buffer is currently stored in gp-data) @@ -649,9 +1032,21 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) && (gpf->flag & GP_FRAME_PAINT)) { + /* Set color for drawing buffer stroke - since this may not be set yet */ + glColor4fv(gpl->color); + /* Buffer stroke needs to be drawn with a different linestyle - * to help differentiate them from normal strokes. */ - gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag); + * to help differentiate them from normal strokes. + * + * It should also be noted that sbuffer contains temporary point types + * i.e. tGPspoints NOT bGPDspoints + */ + if (gpl->flag & GP_LAYER_VOLUMETRIC) { + gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag); + } + else { + gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag); + } } } |