[Bf-blender-cvs] [505340202e9] master: Fix T66452: Convert Curve to Grease Pencil Strokes

Antonio Vazquez noreply at git.blender.org
Sat Aug 31 17:48:48 CEST 2019


Commit: 505340202e960776f694ccfc7ed2c959c38a02c1
Author: Antonio Vazquez
Date:   Sat Aug 31 17:26:48 2019 +0200
Branches: master
https://developer.blender.org/rB505340202e960776f694ccfc7ed2c959c38a02c1

Fix T66452: Convert Curve to Grease Pencil Strokes

This commit adds support to convert curves to Grease Pencil strokes and create the materials too.

Also, there is a new python API. This API is required by the modified SVG import addon to create strokes( see T67065).

All curves selected in one operation are converted in the same Grease Pencil object.

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

M	source/blender/blenkernel/BKE_gpencil.h
M	source/blender/blenkernel/intern/gpencil.c
M	source/blender/editors/object/object_add.c
M	source/blender/makesrna/intern/rna_object_api.c

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

diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 75e98ee31de..310eba86231 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -237,6 +237,14 @@ void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int
 float BKE_gpencil_multiframe_falloff_calc(
     struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff);
 
+void BKE_gpencil_convert_curve(struct Main *bmain,
+                               struct Scene *scene,
+                               struct Object *ob_gp,
+                               struct Object *ob_cu,
+                               const bool gpencil_lines,
+                               const bool use_collections,
+                               const bool only_stroke);
+
 extern void (*BKE_gpencil_batch_cache_dirty_tag_cb)(struct bGPdata *gpd);
 extern void (*BKE_gpencil_batch_cache_free_cb)(struct bGPdata *gpd);
 
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 456bc0c88f9..e057a1874d4 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -48,14 +48,18 @@
 
 #include "BKE_action.h"
 #include "BKE_animsys.h"
+#include "BKE_curve.h"
+#include "BKE_collection.h"
+#include "BKE_colortools.h"
 #include "BKE_deform.h"
 #include "BKE_gpencil.h"
-#include "BKE_colortools.h"
 #include "BKE_icons.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
-#include "BKE_object.h"
 #include "BKE_material.h"
+#include "BKE_object.h"
+
+#include "BLI_math_color.h"
 
 #include "DEG_depsgraph.h"
 
@@ -2572,3 +2576,373 @@ void BKE_gpencil_merge_distance_stroke(bGPDframe *gpf,
     BKE_gpencil_dissolve_points(gpf, gps, GP_SPOINT_TAG);
   }
 }
+
+/* Helper: Check materials with same color. */
+static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Material *r_mat)
+{
+  Material *ma = NULL;
+  float color_cu[4];
+  linearrgb_to_srgb_v3_v3(color_cu, color);
+  float hsv1[4];
+  rgb_to_hsv_v(color_cu, hsv1);
+  hsv1[3] = color[3];
+
+  for (int i = 1; i <= ob_gp->totcol; i++) {
+    ma = give_current_material(ob_gp, i);
+    MaterialGPencilStyle *gp_style = ma->gp_style;
+    /* Check color with small tolerance (better in HSV). */
+    float hsv2[4];
+    rgb_to_hsv_v(gp_style->fill_rgba, hsv2);
+    hsv2[3] = gp_style->fill_rgba[3];
+    if ((gp_style->fill_style == GP_STYLE_FILL_STYLE_SOLID) && (compare_v4v4(hsv1, hsv2, 0.01f))) {
+      r_mat = ma;
+      return i - 1;
+    }
+  }
+
+  r_mat = NULL;
+  return -1;
+}
+
+/* Helper: Add gpencil material using curve material as base. */
+static Material *gpencil_add_from_curve_material(Main *bmain,
+                                                 Object *ob_gp,
+                                                 float cu_color[4],
+                                                 const bool gpencil_lines,
+                                                 const bool fill,
+                                                 int *r_idx)
+{
+  Material *mat_gp = BKE_gpencil_object_material_new(
+      bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx);
+  MaterialGPencilStyle *gp_style = mat_gp->gp_style;
+
+  /* Stroke color. */
+  if (gpencil_lines) {
+    ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f);
+    gp_style->flag |= GP_STYLE_STROKE_SHOW;
+  }
+  else {
+    linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color);
+    gp_style->flag &= ~GP_STYLE_STROKE_SHOW;
+  }
+
+  /* Fill color. */
+  linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color);
+  /* Fill is false if the original curve hasn't material assigned, so enable it. */
+  if (fill) {
+    gp_style->flag |= GP_STYLE_FILL_SHOW;
+  }
+
+  /* Check at least one is enabled. */
+  if (((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0) &&
+      ((gp_style->flag & GP_STYLE_FILL_SHOW) == 0)) {
+    gp_style->flag |= GP_STYLE_STROKE_SHOW;
+  }
+
+  return mat_gp;
+}
+
+/* Helper: Create new stroke section. */
+static void gpencil_add_new_points(bGPDstroke *gps,
+                                   float *coord_array,
+                                   float pressure,
+                                   int init,
+                                   int totpoints,
+                                   float init_co[3],
+                                   bool last)
+{
+  for (int i = 0; i < totpoints; i++) {
+    bGPDspoint *pt = &gps->points[i + init];
+    copy_v3_v3(&pt->x, &coord_array[3 * i]);
+    /* Be sure the last point is not on top of the first point of the curve or
+     * the close of the stroke will produce glitches. */
+    if ((last) && (i > 0) && (i == totpoints - 1)) {
+      float dist = len_v3v3(init_co, &pt->x);
+      if (dist < 0.1f) {
+        /* Interpolate between previous point and current to back slightly. */
+        bGPDspoint *pt_prev = &gps->points[i + init - 1];
+        interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f);
+      }
+    }
+
+    pt->pressure = pressure;
+    pt->strength = 1.0f;
+  }
+}
+
+/* Helper: Get the first collection that includes the object. */
+static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob)
+{
+  Collection *mycol = NULL;
+  FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
+    for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+      if ((mycol == NULL) && (cob->ob == ob)) {
+        mycol = collection;
+      }
+    }
+  }
+  FOREACH_SCENE_COLLECTION_END;
+
+  return mycol;
+}
+
+/* Helper: Convert one spline to grease pencil stroke. */
+static void gpencil_convert_spline(Main *bmain,
+                                   Scene *scene,
+                                   Object *ob_gp,
+                                   Object *ob_cu,
+                                   const bool gpencil_lines,
+                                   const bool use_collections,
+                                   const bool only_stroke,
+                                   bGPDframe *gpf,
+                                   Nurb *nu)
+{
+  Curve *cu = (Curve *)ob_cu->data;
+  bool cyclic = true;
+
+  /* Create Stroke. */
+  bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
+  gps->thickness = 1.0f;
+  gps->gradient_f = 1.0f;
+  ARRAY_SET_ITEMS(gps->gradient_s, 1.0f, 1.0f);
+  ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND);
+  gps->inittime = 0.0f;
+
+  /* Enable recalculation flag by default. */
+  gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+  gps->flag &= ~GP_STROKE_SELECT;
+  gps->flag |= GP_STROKE_3DSPACE;
+
+  gps->mat_nr = 0;
+  /* Count total points
+   * The total of points must consider that last point of each segment is equal to the first
+   * point of next segment.
+   */
+  int totpoints = 0;
+  int segments = 0;
+  int resolu = nu->resolu + 1;
+  segments = nu->pntsu;
+  if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) {
+    segments--;
+    cyclic = false;
+  }
+  totpoints = (resolu * segments) - (segments - 1);
+
+  /* Initialize triangle memory to dummy data. */
+  gps->tot_triangles = 0;
+  gps->triangles = NULL;
+
+  /* Materials
+   * Notice: The color of the material is the color of viewport and not the final shader color.
+   */
+  Material *mat_gp = NULL;
+  bool fill = true;
+  /* Check if grease pencil has a material with same color.*/
+  float color[4];
+  if ((cu->mat) && (*cu->mat)) {
+    Material *mat_cu = *cu->mat;
+    copy_v4_v4(color, &mat_cu->r);
+  }
+  else {
+    /* Gray (unassigned from SVG add-on) */
+    zero_v4(color);
+    add_v3_fl(color, 0.6f);
+    color[3] = 1.0f;
+    fill = false;
+  }
+
+  /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and
+   * there is only one color, the stroke must not be closed, fill to false and use for
+   * stroke the fill color.
+   */
+  bool do_stroke = false;
+  if (ob_cu->totcol == 1) {
+    Material *ma_stroke = give_current_material(ob_cu, 1);
+    if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) {
+      do_stroke = true;
+    }
+  }
+
+  int r_idx = gpencil_check_same_material_color(ob_gp, color, mat_gp);
+  if ((ob_cu->totcol > 0) && (r_idx < 0)) {
+    Material *mat_curve = give_current_material(ob_cu, 1);
+    mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx);
+
+    if ((mat_curve) && (mat_curve->gp_style != NULL)) {
+      MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style;
+      MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style;
+
+      copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba);
+      gp_style_gp->fill_style = gp_style_cur->fill_style;
+      gp_style_gp->mix_factor = gp_style_cur->mix_factor;
+      gp_style_gp->gradient_angle = gp_style_cur->gradient_angle;
+    }
+
+    /* If object has more than 1 material, use second material for stroke color. */
+    if ((!only_stroke) && (ob_cu->totcol > 1) && (give_current_material(ob_cu, 2))) {
+      mat_curve = give_current_material(ob_cu, 2);
+      linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
+      mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
+    }
+    else if ((only_stroke) || (do_stroke)) {
+      /* Also use the first color if the fill is none for stroke color. */
+      if (ob_cu->totcol > 0) {
+        mat_curve = give_current_material(ob_cu, 1);
+        linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
+        mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
+        /* Set stroke to on. */
+        mat_gp->gp_style->flag |= GP_STYLE_STROKE_SHOW;
+        /* Set fill to off. */
+        mat_gp->gp_style->flag &= ~GP_STYLE_FILL_SHOW;
+      }
+    }
+  }
+  CLAMP_MIN(r_idx, 0);
+
+  /* Assign material index to stroke. */
+  gps->mat_nr = r_idx;
+
+  /* Add stroke to frame.*/
+  BLI_addtail(&gpf->strokes, gps);
+
+  /* Read all segments of the curve. */
+  float *coord_array = NULL;
+  float init_co[3];
+
+  if (nu->type == CU_BEZIER) {
+    /* Allocate memory for storage points. */
+    gps->totpoints = totpoints;
+    gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list