[Bf-blender-cvs] [03df48a28a3] greasepencil-object: WIP: add basic support for stroke filling using draw_manager

Antonio Vazquez noreply at git.blender.org
Wed Apr 12 12:12:19 CEST 2017


Commit: 03df48a28a35aca61245a75a5735eb84f7c9bf7d
Author: Antonio Vazquez
Date:   Wed Apr 12 12:11:34 2017 +0200
Branches: greasepencil-object
https://developer.blender.org/rB03df48a28a35aca61245a75a5735eb84f7c9bf7d

WIP: add basic support for stroke filling using draw_manager

===================================================================

M	source/blender/draw/engines/gpencil/gpencil_draw.c
M	source/blender/draw/engines/gpencil/gpencil_mode.c
M	source/blender/draw/engines/gpencil/gpencil_mode.h

===================================================================

diff --git a/source/blender/draw/engines/gpencil/gpencil_draw.c b/source/blender/draw/engines/gpencil/gpencil_draw.c
index 7819f928431..4f8669643fe 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw.c
@@ -63,6 +63,8 @@
 
 #include "BIF_glutil.h"
 
+#include "DRW_render.h"
+
 #include "GPU_immediate.h"
 #include "GPU_draw.h"
 
@@ -160,3 +162,232 @@ bool gpencil_can_draw_stroke(const bGPDstroke *gps)
 	/* stroke can be drawn */
 	return true;
 }
+
+/* calc bounding box in 2d using flat projection data */
+static void gpencil_calc_2d_bounding_box(const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], bool expand)
+{
+	minv[0] = points2d[0][0];
+	minv[1] = points2d[0][1];
+	maxv[0] = points2d[0][0];
+	maxv[1] = points2d[0][1];
+
+	for (int i = 1; i < totpoints; i++)
+	{
+		/* min */
+		if (points2d[i][0] < minv[0]) {
+			minv[0] = points2d[i][0];
+		}
+		if (points2d[i][1] < minv[1]) {
+			minv[1] = points2d[i][1];
+		}
+		/* max */
+		if (points2d[i][0] > maxv[0]) {
+			maxv[0] = points2d[i][0];
+		}
+		if (points2d[i][1] > maxv[1]) {
+			maxv[1] = points2d[i][1];
+		}
+	}
+	/* If not expanded, use a perfect square */
+	if (expand == false) {
+		if (maxv[0] > maxv[1]) {
+			maxv[1] = maxv[0];
+		}
+		else {
+			maxv[0] = maxv[1];
+		}
+	}
+}
+
+/* calc texture coordinates using flat projected points */
+static void gpencil_calc_stroke_uv(const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], float(*r_uv)[2])
+{
+	float d[2];
+	d[0] = maxv[0] - minv[0];
+	d[1] = maxv[1] - minv[1];
+	for (int i = 0; i < totpoints; i++)
+	{
+		r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0];
+		r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1];
+	}
+}
+
+/* Get points of stroke always flat to view not affected by camera view or view position */
+static void gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction)
+{
+	const bGPDspoint *pt0 = &points[0];
+	const bGPDspoint *pt1 = &points[1];
+	const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+
+	float locx[3];
+	float locy[3];
+	float loc3[3];
+	float normal[3];
+
+	/* local X axis (p0 -> p1) */
+	sub_v3_v3v3(locx, &pt1->x, &pt0->x);
+
+	/* point vector at 3/4 */
+	sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
+
+	/* vector orthogonal to polygon plane */
+	cross_v3_v3v3(normal, locx, loc3);
+
+	/* local Y axis (cross to normal/x axis) */
+	cross_v3_v3v3(locy, normal, locx);
+
+	/* Normalize vectors */
+	normalize_v3(locx);
+	normalize_v3(locy);
+
+	/* Get all points in local space */
+	for (int i = 0; i < totpoints; i++) {
+		const bGPDspoint *pt = &points[i];
+		float loc[3];
+
+		/* Get local space using first point as origin */
+		sub_v3_v3v3(loc, &pt->x, &pt0->x);
+
+		points2d[i][0] = dot_v3v3(loc, locx);
+		points2d[i][1] = dot_v3v3(loc, locy);
+	}
+
+	/* Concave (-1), Convex (1), or Autodetect (0)? */
+	*r_direction = (int)locy[2];
+}
+
+/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */
+static void gp_triangulate_stroke_fill(bGPDstroke *gps)
+{
+	BLI_assert(gps->totpoints >= 3);
+
+	/* allocate memory for temporary areas */
+	gps->tot_triangles = gps->totpoints - 2;
+	unsigned int(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation");
+	float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points");
+	float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
+
+	int direction = 0;
+
+	/* convert to 2d and triangulate */
+	gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
+	BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)gps->totpoints, direction, (unsigned int(*)[3])tmp_triangles);
+
+	/* calc texture coordinates automatically */
+	float minv[2];
+	float maxv[2];
+	/* first needs bounding box data */
+	gpencil_calc_2d_bounding_box((const float(*)[2])points2d, gps->totpoints, minv, maxv, false);
+	/* calc uv data */
+	gpencil_calc_stroke_uv((const float(*)[2])points2d, gps->totpoints, minv, maxv, uv);
+
+	/* Number of triangles */
+	gps->tot_triangles = gps->totpoints - 2;
+	/* save triangulation data in stroke cache */
+	if (gps->tot_triangles > 0) {
+		if (gps->triangles == NULL) {
+			gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, "GP Stroke triangulation");
+		}
+		else {
+			gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles);
+		}
+
+		for (int i = 0; i < gps->tot_triangles; i++) {
+			bGPDtriangle *stroke_triangle = &gps->triangles[i];
+			stroke_triangle->v1 = tmp_triangles[i][0];
+			stroke_triangle->v2 = tmp_triangles[i][1];
+			stroke_triangle->v3 = tmp_triangles[i][2];
+			/* copy texture coordinates */
+			copy_v2_v2(stroke_triangle->uv1, uv[tmp_triangles[i][0]]);
+			copy_v2_v2(stroke_triangle->uv2, uv[tmp_triangles[i][1]]);
+			copy_v2_v2(stroke_triangle->uv3, uv[tmp_triangles[i][2]]);
+		}
+	}
+	else {
+		/* No triangles needed - Free anything allocated previously */
+		if (gps->triangles)
+			MEM_freeN(gps->triangles);
+
+		gps->triangles = NULL;
+	}
+
+	/* disable recalculation flag */
+	if (gps->flag & GP_STROKE_RECALC_CACHES) {
+		gps->flag &= ~GP_STROKE_RECALC_CACHES;
+	}
+
+	/* clear memory */
+	if (tmp_triangles) MEM_freeN(tmp_triangles);
+	if (points2d) MEM_freeN(points2d);
+	if (uv) MEM_freeN(uv);
+}
+
+/* add a new fill point and texture coordinates to vertex buffer */
+static void gpencil_set_fill_point(VertexBuffer *vbo, int idx, bGPDspoint *pt, float uv[2],
+	unsigned int pos_id, unsigned int text_id,
+	short UNUSED(flag),	int UNUSED(offsx), int UNUSED(offsy), int UNUSED(winx), int UNUSED(winy),
+	const float diff_mat[4][4])
+{
+	float fpt[3];
+
+	mul_v3_m4v3(fpt, diff_mat, &pt->x);
+#if 0
+	/* if 2d, need conversion */
+	if (!flag & GP_STROKE_3DSPACE) {
+		float co[2];
+		gp_calc_2d_stroke_fxy(fpt, flag, offsx, offsy, winx, winy, co);
+		copy_v2_v2(fpt, co);
+		fpt[2] = 0.0f; /* 2d always is z=0.0f */
+	}
+#endif
+	VertexBuffer_set_attrib(vbo, pos_id, idx, fpt);
+	VertexBuffer_set_attrib(vbo, text_id, idx, uv);
+}
+
+/* create batch geometry data for stroke shader */
+Batch *gpencil_get_fill_geom(bGPDstroke *gps, const float diff_mat[4][4], const float color[4])
+{
+	BLI_assert(gps->totpoints >= 3);
+	PaletteColor *palcolor = gps->palcolor;
+	int offsx = 0;
+	int offsy = 0;
+	const float *viewport = DRW_viewport_size_get();
+	int winx = (int)viewport[0];
+	int winy = (int)viewport[1];
+
+	/* Calculate triangles cache for filling area (must be done only after changes) */
+	if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
+		gp_triangulate_stroke_fill(gps);
+	}
+	BLI_assert(gps->tot_triangles >= 1);
+
+	static VertexFormat format = { 0 };
+	static unsigned int pos_id, text_id;
+	if (format.attrib_ct == 0) {
+		pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT);
+		text_id = VertexFormat_add_attrib(&format, "texCoord", COMP_F32, 2, KEEP_FLOAT);
+	}
+
+	VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
+	VertexBuffer_allocate_data(vbo, gps->tot_triangles * 3);
+
+	/* Draw all triangles for filling the polygon (cache must be calculated before) */
+	bGPDtriangle *stroke_triangle = gps->triangles;
+	int idx = 0;
+	for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
+		gpencil_set_fill_point(vbo, idx, &gps->points[stroke_triangle->v1], stroke_triangle->uv1,
+			pos_id, text_id, gps->flag,
+			offsx, offsy, winx, winy, diff_mat);
+		++idx;
+		gpencil_set_fill_point(vbo, idx, &gps->points[stroke_triangle->v2], stroke_triangle->uv2,
+			pos_id, text_id, gps->flag,
+			offsx, offsy, winx, winy, diff_mat);
+		++idx;
+		gpencil_set_fill_point(vbo, idx, &gps->points[stroke_triangle->v3], stroke_triangle->uv3,
+			pos_id, text_id, gps->flag,
+			offsx, offsy, winx, winy, diff_mat);
+		++idx;
+	}
+
+	return Batch_create(PRIM_TRIANGLES, vbo, NULL);
+}
diff --git a/source/blender/draw/engines/gpencil/gpencil_mode.c b/source/blender/draw/engines/gpencil/gpencil_mode.c
index 3273455b2f6..893939db58f 100644
--- a/source/blender/draw/engines/gpencil/gpencil_mode.c
+++ b/source/blender/draw/engines/gpencil/gpencil_mode.c
@@ -264,12 +264,18 @@ static void GPENCIL_cache_populate(void *vedata, Object *ob)
 
 				fillgrp = stl->storage->shgrps_fill[id];
 				strokegrp = stl->storage->shgrps_stroke[id];
-#if 0
+
 				/* fill */
-				struct Batch *fill_geom = DRW_cache_surface_get(ob); // TODO: replace with real funct
-				/* Add fill geom to a shading group */
-				DRW_shgroup_call_add(fillgrp, fill_geom, ob->obmat);
-#endif
+				if (gps->totpoints >= 3) {
+					float tfill[4];
+					interp_v3_v3v3(tfill, gps->palcolor->fill, gpl->tintcolor, gpl->tintcolor[3]);
+					tfill[3] = gps->palcolor->fill[3] * gpl->opacity;
+					if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gps->palcolor->fill_style > 0)) {
+						struct Batch *fill_geom = gpencil_get_fill_geom(gps, diff_mat, tfill);
+						DRW_shgroup_call_add(fillgrp, fill_geom, ob->obmat);
+					}
+				}
+
 				/* stroke */
 				interp_v3_v3v3(tcolor, gps->palcolor->rgb, gpl->tintcolor, gpl->tintcolor[3]);
 				tcolor[3] = gps->palcolor->rgb[3] * gpl->opacity;
diff --git a/source/blender/draw/engines/gpencil/gpencil_mode.h b/source/blender/draw/engines/gpencil/gpencil_mode.h
index 5fa2f304945..07bb82b3991 100644
--- a/source/blender/draw/engines/gpencil/gpencil_mode.h
+++ b/source/blender/draw/engines/gpencil/gpencil_mode.h
@@ -29,6 +29,7 @@
 struct Batch;
 
 struct Batch *gpencil_get_stroke_geom(struct bGPDstroke *gps, short thickness, const float diff_mat[4][4], const float ink[4]);
+struct Batch *gpencil_get_fill_geom(struct bGPDstroke *gps, const float diff_mat[4][4], const float color[4]);
 bool gpencil_can_draw_stroke(const struct bGPDstroke *gps);
 
 #endif /* __GPENCIL_MODE_H__ */
\ No newline at end of file




More information about the Bf-blender-cvs mailing list