Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/gpencil/drawgpencil.c')
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c693
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);
+ }
}
}