[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [15931] trunk/blender/source/blender/src/ drawgpencil.c: Grease Pencil Drawing:
Joshua Leung
aligorith at gmail.com
Sun Aug 3 13:55:51 CEST 2008
Revision: 15931
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=15931
Author: aligorith
Date: 2008-08-03 13:55:45 +0200 (Sun, 03 Aug 2008)
Log Message:
-----------
Grease Pencil Drawing:
Some WIP code for 'nicer' drawing of thick 2d-strokes that will hopefully result in smoother lines, particularly with abrupt direction changes. Currently the code is hidden behind the rt button (for rt != 0), as in some cases, it still looks rather bad.
Modified Paths:
--------------
trunk/blender/source/blender/src/drawgpencil.c
Modified: trunk/blender/source/blender/src/drawgpencil.c
===================================================================
--- trunk/blender/source/blender/src/drawgpencil.c 2008-08-03 11:40:09 UTC (rev 15930)
+++ trunk/blender/source/blender/src/drawgpencil.c 2008-08-03 11:55:45 UTC (rev 15931)
@@ -310,6 +310,8 @@
/* ************************************************** */
/* GREASE PENCIL DRAWING */
+/* ----- General Defines ------ */
+
/* flags for sflag */
enum {
GP_DRAWDATA_NOSTATUS = (1<<0), /* don't draw status info */
@@ -317,7 +319,9 @@
GP_DRAWDATA_ONLYV2D = (1<<2), /* only draw 'canvas' strokes */
};
-/* draw stroke in buffer */
+/* ----- Tool Buffer Drawing ------ */
+
+/* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
static void gp_draw_stroke_buffer (tGPspoint *points, int totpoints, short thickness, short dflag, short sflag)
{
tGPspoint *pt;
@@ -377,115 +381,232 @@
}
}
-/* draw a given stroke */
-static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, short debug, int winx, int winy)
+/* ----- Existing Strokes Drawing (3D and Point) ------ */
+
+/* draw a given stroke - just a single dot (only one point) */
+static void gp_draw_stroke_point (bGPDspoint *points, short sflag, int winx, int winy)
{
+ /* draw point */
+ if (sflag & GP_STROKE_3DSPACE) {
+ glBegin(GL_POINTS);
+ glVertex3f(points->x, points->y, points->z);
+ glEnd();
+ }
+ else if (sflag & GP_STROKE_2DSPACE) {
+ glBegin(GL_POINTS);
+ glVertex2f(points->x, points->y);
+ glEnd();
+ }
+ else {
+ const float x= (points->x / 1000 * winx);
+ const float y= (points->y / 1000 * winy);
+
+ glBegin(GL_POINTS);
+ glVertex2f(x, y);
+ glEnd();
+ }
+}
+
+/* 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 dflag, short sflag, short debug, int winx, int winy)
+{
bGPDspoint *pt;
+ float oldpressure = 0.0f;
int i;
- /* error checking */
- if ((points == NULL) || (totpoints <= 0))
- return;
-
- /* check if stroke can be drawn */
- if ((dflag & GP_DRAWDATA_ONLY3D) && !(sflag & GP_STROKE_3DSPACE))
- return;
- if (!(dflag & GP_DRAWDATA_ONLY3D) && (sflag & GP_STROKE_3DSPACE))
- return;
- if ((dflag & GP_DRAWDATA_ONLYV2D) && !(sflag & GP_STROKE_2DSPACE))
- return;
- if (!(dflag & GP_DRAWDATA_ONLYV2D) && (sflag & GP_STROKE_2DSPACE))
- return;
-
- /* if drawing a single point, draw it larger */
- if (totpoints == 1) {
- /* draw point */
- if (sflag & GP_STROKE_3DSPACE) {
- glBegin(GL_POINTS);
- glVertex3f(points->x, points->y, points->z);
+ /* draw stroke curve */
+ glBegin(GL_LINE_STRIP);
+ for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
+ if (fabs(pt->pressure - oldpressure) > 0.2f) {
glEnd();
- }
- else if (sflag & GP_STROKE_2DSPACE) {
- glBegin(GL_POINTS);
- glVertex2f(points->x, points->y);
- glEnd();
- }
- else {
- const float x= (points->x / 1000 * winx);
- const float y= (points->y / 1000 * winy);
+ glLineWidth(pt->pressure * thickness);
+ glBegin(GL_LINE_STRIP);
- glBegin(GL_POINTS);
- glVertex2f(x, y);
- glEnd();
+ glVertex3f(pt->x, pt->y, pt->z);
+
+ oldpressure = pt->pressure;
}
+ else
+ glVertex3f(pt->x, pt->y, pt->z);
}
- else {
- float oldpressure = 0.0f;
+ glEnd();
+
+ /* draw debug points of curve on top? */
+ if (debug) {
+ glBegin(GL_POINTS);
+ for (i=0, pt=points; i < totpoints && pt; i++, pt++)
+ glVertex3f(pt->x, pt->y, pt->z);
+ glEnd();
+ }
+}
+
+/* ----- Fancy 2D-Stroke Drawing ------ */
+
+/* draw a given stroke in 2d */
+static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, short debug, int winx, int winy)
+{
+ /* if thickness is less than 3, 'smooth' opengl lines look better */
+ if ((thickness < 3) || (G.rt==0)) {
+ bGPDspoint *pt;
+ int i;
- /* draw stroke curve */
glBegin(GL_LINE_STRIP);
for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
- float x, y, z;
+ if (sflag & GP_STROKE_2DSPACE) {
+ glVertex2f(pt->x, pt->y);
+ }
+ else {
+ const float x= (pt->x / 1000 * winx);
+ const float y= (pt->y / 1000 * winy);
+
+ glVertex2f(x, y);
+ }
+ }
+ glEnd();
+ }
+ else { /* tesselation code: currently only enabled with rt != 0 */
+ bGPDspoint *pt1, *pt2;
+ float p0[2], p1[2], pm[2];
+ int i;
+
+ glShadeModel(GL_FLAT);
+ glBegin(GL_QUAD_STRIP);
+
+ for (i=0, pt1=points, pt2=points+1; i < (totpoints-1); i++, pt1++, pt2++) {
+ float s0[2], s1[2]; /* segment 'center' points */
+ float t0[2], t1[2]; /* tesselated coordinates */
+ float m1[2], m2[2]; /* gradient and normal */
+ float pthick, dist; /* thickness at segment point, and length of segment */
+ float sminorang; /* minor angle between strokes */
- if (sflag & GP_STROKE_3DSPACE) {
- x= pt->x;
- y= pt->y;
- z= pt->z;
+ /* 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_2DSPACE) {
- x= pt->x;
- y= pt->y;
- z= 0;
- }
else {
- x= (pt->x / 1000 * winx);
- y= (pt->y / 1000 * winy);
- z= 0;
+ s0[0]= (pt1->x / 1000 * winx);
+ s0[1]= (pt1->y / 1000 * winy);
+ s1[0]= (pt2->x / 1000 * winx);
+ s1[1]= (pt2->y / 1000 * winy);
+ }
+
+ /* calculate gradient and normal - 'angle'=(ny/nx) */
+ m1[1]= s1[1] - s0[1];
+ m1[0]= s1[0] - s0[0];
+ dist = Vec2Lenf(s0, s1);
+ m2[1]= -(m1[0]) / dist;
+ m2[0]= m1[1] / dist;
+
+ /* if the first segment, initialise the first segment using segment's normal */
+ if (i == 0) {
+ pthick= (pt1->pressure * thickness);
+
+ // TODO: also draw/do a round end-cap first
+
+ p0[0]= s0[0] - (pthick * m2[0]);
+ p0[1]= s0[1] - (pthick * m2[1]);
+ p1[0]= s1[0] + (pthick * m2[0]);
+ p1[1]= s1[1] + (pthick * m2[1]);
+
+ Vec2Copyf(pm, m1);
}
- if (fabs(pt->pressure - oldpressure) > 0.2f) {
- glEnd();
- glLineWidth(pt->pressure * thickness);
- glBegin(GL_LINE_STRIP);
+ /* if the minor angle between the current segment and the previous one is less than 90 degrees */
+ if (i)
+ sminorang= NormalizedVecAngle2_2D(pm, m1);
+ else
+ sminorang= 0.0f;
+
+ if ((IS_EQ(sminorang, 0)==0) && (abs(sminorang) < M_PI_2) )
+ {
+ float closep[2];
- if (sflag & GP_STROKE_3DSPACE)
- glVertex3f(x, y, z);
+ /* recalculate startpoint of segment, where the new start-line:
+ * - starts a new gl-quad-strip
+ * - uses the vert of old startpoint closer to our endpoint
+ * - distance between new startpoints = distance between old startpoints
+ * - new startpoints occur on same gradient as old segment does (has potential for some 'minor' overlap, but ok)
+ */
+
+ /* find the closer vertex, and distance between startpoints */
+ if (Vec2Lenf(p0, s1) > Vec2Lenf(p1, s1))
+ Vec2Copyf(closep, p1);
else
- glVertex2f(x, y);
+ Vec2Copyf(closep, p0);
+
+ /* determine which side this closer vertex should be on */
+ pthick= (pt1->pressure * thickness * 2);
+ if ( ((closep[0] - s0[0]) > 0) || ((closep[1] - s0[1]) > 0) ) {
+ /* assumes this is the 'second' point, (i.e. the 'plus' one), so the other is subtracting */
+ p0[0]= closep[0] - (pthick * pm[0]);
+ p0[1]= closep[1] - (pthick * pm[1]);
+ p1[0]= closep[0];
+ p1[1]= closep[1];
+ }
+ else if ( ((closep[0] - s0[0]) < 0) || ((closep[1] - s0[1]) < 0) ) {
+ /* assumes this is the 'first' point, (i.e. the 'minus' one), so the other is adding */
+ p0[0]= closep[0];
+ p0[1]= closep[1];
+ p1[0]= closep[0] + (pthick * pm[0]);
+ p1[1]= closep[1] + (pthick * pm[1]);
+ }
- oldpressure = pt->pressure;
+ /* reset gl-states! */
+ glEnd();
+ glBegin(GL_QUAD_STRIP);
}
- else {
- if (sflag & GP_STROKE_3DSPACE)
- glVertex3f(x, y, z);
- else
- glVertex2f(x, y);
+
+ /* do the end of this segment */
+ pthick= (pt2->pressure * thickness);
+ t0[0] = s1[0] - (pthick * m2[0]);
+ t0[1] = s1[1] - (pthick * m2[1]);
+ t1[0] = s1[0] + (pthick * m2[0]);
+ t1[1] = s1[1] + (pthick * m2[1]);
+
+ /* draw this segment */
+ glVertex2f(p0[0], p0[1]);
+ glVertex2f(p1[0], p1[1]);
+ glVertex2f(t0[0], t0[1]);
+ glVertex2f(t1[0], t1[1]);
+
+ // TODO: draw end cap if last segment
+ if (i == totpoints-2) {
+
}
+
+ /* store current points for next segment to use */
+ Vec2Copyf(p0, t0);
+ Vec2Copyf(p1, t1);
+ Vec2Copyf(pm, m1);
}
+
glEnd();
+ }
+
+ /* draw debug points of curve on top? (original stroke points) */
+ if (debug) {
+ bGPDspoint *pt;
+ int i;
- /* draw debug points of curve on top? */
- if (debug) {
- glBegin(GL_POINTS);
- for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
- if (sflag & GP_STROKE_3DSPACE) {
- glVertex3f(pt->x, pt->y, pt->z);
- }
- else if (sflag & GP_STROKE_2DSPACE) {
- glVertex2f(pt->x, pt->y);
- }
- else {
- const float x= (pt->x / 1000 * winx);
- const float y= (pt->y / 1000 * winy);
-
- glVertex2f(x, y);
- }
+ glBegin(GL_POINTS);
+ for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
+ if (sflag & GP_STROKE_2DSPACE) {
+ glVertex2f(pt->x, pt->y);
}
- glEnd();
+ else {
+ const float x= (pt->x / 1000 * winx);
+ const float y= (pt->y / 1000 * winy);
+
+ glVertex2f(x, y);
+ }
}
+ glEnd();
}
}
+/* ----- General Drawing ------ */
+
/* draw a set of strokes */
static void gp_draw_strokes (bGPDframe *gpf, int winx, int winy, int dflag, short debug,
short lthick, float color[4])
@@ -495,9 +616,26 @@
/* set color first (may need to reset it again later too) */
glColor4f(color[0], color[1], color[2], color[3]);
- for (gps= gpf->strokes.first; gps; gps= gps->next) {
- /* just draw the stroke once */
- gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy);
+ for (gps= gpf->strokes.first; gps; gps= gps->next) {
+ /* check if stroke can be drawn */
+ 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;
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list