[Bf-blender-cvs] [85898fb122d] greasepencil-object: GPencil: Add option to export SVG in constant thickness lines
Antonio Vazquez
noreply at git.blender.org
Mon Jul 27 23:01:16 CEST 2020
Commit: 85898fb122d2e2c160a18a3dd9c9ac3a5af44edb
Author: Antonio Vazquez
Date: Mon Jul 27 22:57:29 2020 +0200
Branches: greasepencil-object
https://developer.blender.org/rB85898fb122d2e2c160a18a3dd9c9ac3a5af44edb
GPencil: Add option to export SVG in constant thickness lines
===================================================================
M source/blender/editors/io/io_gpencil.c
M source/blender/io/gpencil/gpencil_io_exporter.h
M source/blender/io/gpencil/intern/gpencil_io_base.cc
M source/blender/io/gpencil/intern/gpencil_io_base.h
M source/blender/io/gpencil/intern/gpencil_io_svg.cc
M source/blender/io/gpencil/intern/gpencil_io_svg.h
===================================================================
diff --git a/source/blender/editors/io/io_gpencil.c b/source/blender/editors/io/io_gpencil.c
index 9783697575c..6d21f6f6161 100644
--- a/source/blender/editors/io/io_gpencil.c
+++ b/source/blender/editors/io/io_gpencil.c
@@ -148,10 +148,12 @@ static int wm_gpencil_export_exec(bContext *C, wmOperator *op)
const bool only_active_frame = RNA_boolean_get(op->ptr, "only_active_frame");
const bool use_fill = RNA_boolean_get(op->ptr, "use_fill");
+ const bool use_norm_thickness = RNA_boolean_get(op->ptr, "use_normalized_thickness");
/* Set flags. */
int flag = 0;
SET_FLAG_FROM_TEST(flag, use_fill, GP_EXPORT_FILL);
+ SET_FLAG_FROM_TEST(flag, use_norm_thickness, GP_EXPORT_NORM_THICKNESS);
struct GpencilExportParams params = {
.C = C,
@@ -238,6 +240,7 @@ static void ui_gpencil_export_settings(uiLayout *layout, PointerRNA *imfptr)
sub = uiLayoutColumn(col, true);
uiItemR(sub, imfptr, "use_fill", 0, NULL, ICON_NONE);
+ uiItemR(sub, imfptr, "use_normalized_thickness", 0, NULL, ICON_NONE);
}
static void wm_gpencil_export_draw(bContext *C, wmOperator *op)
@@ -339,6 +342,11 @@ void WM_OT_gpencil_export(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "only_active_frame", true, "Active Frame", "Export only active frame");
RNA_def_boolean(ot->srna, "use_fill", true, "Fill", "Export filled areas");
+ RNA_def_boolean(ot->srna,
+ "use_normalized_thickness",
+ false,
+ "Normalize",
+ "Export strokes with constant thickness along the stroke");
/* This dummy prop is used to check whether we need to init the start and
* end frame values to that of the scene's, otherwise they are reset at
diff --git a/source/blender/io/gpencil/gpencil_io_exporter.h b/source/blender/io/gpencil/gpencil_io_exporter.h
index eb779112fe4..1d30b4b45de 100644
--- a/source/blender/io/gpencil/gpencil_io_exporter.h
+++ b/source/blender/io/gpencil/gpencil_io_exporter.h
@@ -53,6 +53,8 @@ struct GpencilExportParams {
typedef enum eGpencilExportParams_Flag {
/* Export Filled strokes. */
GP_EXPORT_FILL = (1 << 0),
+ /* Export normalized thickness. */
+ GP_EXPORT_NORM_THICKNESS = (1 << 1),
} eGpencilExportParams_Flag;
bool gpencil_io_export(const struct GpencilExportParams *params);
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.cc b/source/blender/io/gpencil/intern/gpencil_io_base.cc
index e3917e304df..773329e80af 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.cc
@@ -25,6 +25,7 @@
#include "BKE_context.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
#include "BKE_main.h"
#include "BLI_blenlib.h"
@@ -35,6 +36,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
#ifdef WIN32
# include "utfconv.h"
@@ -92,6 +94,29 @@ bool GpencilExporter::gpencil_3d_point_to_screen_space(struct ARegion *region,
return false;
}
+/**
+ * Get average pressure
+ * \param gps: Pointer to stroke
+ * \retun value
+ */
+float GpencilExporter::stroke_average_pressure(struct bGPDstroke *gps)
+{
+ bGPDspoint *pt = NULL;
+
+ if (gps->totpoints == 1) {
+ pt = &gps->points[0];
+ return pt->pressure;
+ }
+
+ float tot = 0.0f;
+ for (int i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ tot += pt->pressure;
+ }
+
+ return tot / (float)gps->totpoints;
+}
+
/**
* Check if the thickness of the stroke is constant
* \param gps: Pointer to stroke
@@ -116,6 +141,35 @@ bool GpencilExporter::is_stroke_thickness_constant(struct bGPDstroke *gps)
return true;
}
+float GpencilExporter::point_radius(const struct bGPDlayer *gpl,
+ struct bGPDstroke *gps,
+ float diff_mat[4][4])
+{
+ RegionView3D *rv3d = (RegionView3D *)params.region->regiondata;
+ bGPDspoint *pt = NULL;
+ float v1[2], screen_co[2], screen_ex[2];
+
+ pt = &gps->points[0];
+ gpencil_3d_point_to_screen_space(params.region, diff_mat, &pt->x, screen_co);
+ /* Invert Y axis. */
+ screen_co[1] = params.region->winy - screen_co[1];
+
+ /* Radius. */
+ bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view(
+ rv3d, gpd, gpl, gps, 3, diff_mat);
+
+ pt = &gps_perimeter->points[0];
+ gpencil_3d_point_to_screen_space(params.region, diff_mat, &pt->x, screen_ex);
+ /* Invert Y axis. */
+ screen_ex[1] = params.region->winy - screen_ex[1];
+
+ sub_v2_v2v2(v1, screen_co, screen_ex);
+ float radius = len_v2(v1);
+ BKE_gpencil_free_stroke(gps_perimeter);
+
+ return radius;
+}
+
/**
* Convert a color to Hex value (#FFFFFF)
* \param color: Original RGB color
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.h b/source/blender/io/gpencil/intern/gpencil_io_base.h
index 1dfce8b4f36..31a31c2080d 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.h
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.h
@@ -31,6 +31,9 @@
struct Main;
struct ARegion;
+struct bGPDlayer;
+struct bGPDstroke;
+
namespace blender {
namespace io {
namespace gpencil {
@@ -48,6 +51,8 @@ class GpencilExporter {
float r_co[2]);
bool is_stroke_thickness_constant(struct bGPDstroke *gps);
+ float stroke_average_pressure(struct bGPDstroke *gps);
+ float point_radius(const struct bGPDlayer *gpl, struct bGPDstroke *gps, float diff_mat[4][4]);
std::string rgb_to_hex(float color[3]);
std::string to_lower_string(char *input_text);
diff --git a/source/blender/io/gpencil/intern/gpencil_io_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_svg.cc
index f70c2311af3..0afa8165e39 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_svg.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_svg.cc
@@ -20,6 +20,8 @@
#include <iostream>
#include <string>
+#include "MEM_guardedalloc.h"
+
#include "BKE_context.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_geom.h"
@@ -232,23 +234,35 @@ void GpencilExporterSVG::export_layers(void)
export_point(gpl_node, gpl, gps, diff_mat);
}
else {
+ bool is_normalized = ((params.flag & GP_EXPORT_NORM_THICKNESS) != 0);
+
/* Fill. */
if ((is_fill) && (params.flag & GP_EXPORT_FILL)) {
- export_stroke_path(gpl_node, gps, diff_mat, true);
+ if (is_normalized) {
+ export_stroke_polyline(gpl_node, gpl, gps, gp_style, diff_mat, true);
+ }
+ else {
+ export_stroke_path(gpl_node, gps, diff_mat, true);
+ }
}
/* Stroke. */
if (is_stroke) {
- bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view(
- rv3d, gpd, gpl, gps, 3, diff_mat);
+ if (is_normalized) {
+ export_stroke_polyline(gpl_node, gpl, gps, gp_style, diff_mat, false);
+ }
+ else {
+ bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view(
+ rv3d, gpd, gpl, gps, 3, diff_mat);
- /* Reproject and sample stroke. */
- // ED_gpencil_project_stroke_to_view(params.C, gpl, gps_perimeter);
- BKE_gpencil_stroke_sample(gps_perimeter, 0.03f, false);
+ /* Reproject and sample stroke. */
+ // ED_gpencil_project_stroke_to_view(params.C, gpl, gps_perimeter);
+ BKE_gpencil_stroke_sample(gps_perimeter, 0.03f, false);
- export_stroke_path(gpl_node, gps_perimeter, diff_mat, false);
+ export_stroke_path(gpl_node, gps_perimeter, diff_mat, false);
- BKE_gpencil_free_stroke(gps_perimeter);
+ BKE_gpencil_free_stroke(gps_perimeter);
+ }
}
}
}
@@ -340,6 +354,77 @@ void GpencilExporterSVG::export_stroke_path(pugi::xml_node gpl_node,
gps_node.append_attribute("d").set_value(txt.c_str());
}
+/**
+ * Export a stroke using polyline or polygon
+ * \param gpl_node: Node of the layer.
+ * \param gps: Stroke to export.
+ * \param diff_mat: Transformation matrix.
+ * \param is_fill: True if the stroke is only fill
+ */
+void GpencilExporterSVG::export_stroke_polyline(pugi::xml_node gpl_node,
+ struct bGPDlayer *gpl,
+ struct bGPDstroke *gps,
+ struct MaterialGPencilStyle *gp_style,
+ float diff_mat[4][4],
+ const bool is_fill)
+{
+ const bool is_thickness_const = is_stroke_thickness_constant(gps);
+ const bool cyclic = ((gps->flag & GP_STROKE_CYCLIC) != 0);
+
+ bGPDspoint *pt = &gps->points[0];
+ float avg_pressure = pt->pressure;
+ if (!is_thickness_const) {
+ avg_pressure = stroke_average_pressure(gps);
+ }
+
+ /* Get the thickness in pixels using a simple 1 point stroke. */
+ bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, false);
+ gps_temp->totpoints = 1;
+ gps_temp->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
+ bGPDspoint *pt_src = &gps->points[0];
+ bGPDspoint *pt_dst = &gps_temp->points[0];
+ copy_v3_v3(&pt_dst->x, &pt_src->x);
+ pt_dst->pressure = avg_pressure;
+
+ float radius = point_radius(gpl, gps_temp, diff_mat);
+
+ BKE_gpencil_free_stroke(gps_temp);
+
+ pugi::xml_node gps_node = gpl_node.append_child(is_fill || cyclic ? "polygon" : "polyline");
+
+ float col[3];
+ if (is_fill) {
+ linearrgb_to_srgb_v3_v3(col, gp_style->fill_rgba);
+ std::string stroke_hex = rgb_to_hex(col);
+ gps_node.append_attribute("fill").set_value(stroke_hex.c_str());
+ gps_node.append_attribute("stroke").set_value("none");
+ }
+ else {
+ linearrgb_to_srgb_v3_v3(col, gp_style->stroke_rgba);
+ std::string stroke_hex = rgb_to_hex(col);
+ gps_node.append_attribute("fill").set_value("none");
+ gps_node.append_attribute("stroke").set_value(stroke_hex.c_str());
+ }
+
+ float thickness = is_fill ? 1.0f : radius;
+ gps_node.append_attribute("stroke-width").set_value(thickness);
+
+ std::string txt;
+ for (int i = 0; i < gps->totpoints; i++) {
+ if (i > 0) {
+ txt.append("
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list