Fix #123220: Export GP SVG/PDF crash when active object is not GP

`GpencilIOParams.ob` is set to `CTX_data_active_object` at the beginning
of the export [which is not ensured to be a valid `OB_GPENCIL_LEGACY`
object, non-valid objects are filtered out later in
`create_object_list`]. From this (potential non-greasepencil) object's
data, a "global `bGPdata` is stored in `GpencilIOParams`.

From here, it can only go downwards as `stroke_point_radius_get`,
`export_stroke_to_polyline`, `BKE_gpencil_stroke_perimeter_from_view`
all use this "global" `bGPdata`.

Two possible solutions might exist:
- [1] just cancel the operator if the active object is not a
`OB_GPENCIL_LEGACY` object
- [2] make sure we use corresponding `bGPdata` when iterating over
valid objects to export

This PR chooses [2] since it also seems wrong to always use the
`bGPdata` from the active object for certain calculations when iterating
many objects. For example, the export ignores different values for
`Thickness Scale` on different objects and always takes the value from
the active object, which does not seem to be by design.

NOTE: this changes behavior (see above) but for the better
Pull Request: https://projects.blender.org/blender/blender/pulls/123224
This commit is contained in:
Philipp Oeser
2024-06-18 16:44:08 +02:00
committed by Philipp Oeser
parent 9d5f46b1b8
commit 751745b2de
6 changed files with 23 additions and 17 deletions
@@ -251,14 +251,14 @@ float2 GpencilIO::gpencil_3D_point_to_2D(const float3 co)
return result;
}
float GpencilIO::stroke_point_radius_get(bGPDlayer *gpl, bGPDstroke *gps)
float GpencilIO::stroke_point_radius_get(bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps)
{
bGPDspoint *pt = &gps->points[0];
const float2 screen_co = gpencil_3D_point_to_2D(&pt->x);
/* Radius. */
bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view(
rv3d_->viewmat, gpd_, gpl, gps, 3, diff_mat_.ptr(), 0.0f);
rv3d_->viewmat, gpd, gpl, gps, 3, diff_mat_.ptr(), 0.0f);
pt = &gps_perimeter->points[0];
const float2 screen_ex = gpencil_3D_point_to_2D(&pt->x);
@@ -79,7 +79,7 @@ class GpencilIO {
float2 gpencil_3D_point_to_2D(const float3 co);
/** Get radius of point. */
float stroke_point_radius_get(bGPDlayer *gpl, bGPDstroke *gps);
float stroke_point_radius_get(bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps);
/** Create a list of selected objects sorted from back to front */
void create_object_list();
@@ -192,24 +192,24 @@ void GpencilExporterPDF::export_gpencil_layers()
/* Fill. */
if ((is_fill) && (params_.flag & GP_EXPORT_FILL)) {
/* Fill is exported as polygon for fill and stroke in a different shape. */
export_stroke_to_polyline(gpl, gps_duplicate, is_stroke, true, false);
export_stroke_to_polyline(gpd_eval, gpl, gps_duplicate, is_stroke, true, false);
}
/* Stroke. */
if (is_stroke) {
if (is_normalized) {
export_stroke_to_polyline(gpl, gps_duplicate, is_stroke, false, true);
export_stroke_to_polyline(gpd_eval, gpl, gps_duplicate, is_stroke, false, true);
}
else {
bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view(
rv3d_->viewmat, gpd_, gpl, gps_duplicate, 3, diff_mat_.ptr(), 0.0f);
rv3d_->viewmat, gpd_eval, gpl, gps_duplicate, 3, diff_mat_.ptr(), 0.0f);
/* Sample stroke. */
if (params_.stroke_sample > 0.0f) {
BKE_gpencil_stroke_sample(gpd_eval, gps_perimeter, params_.stroke_sample, false, 0);
}
export_stroke_to_polyline(gpl, gps_perimeter, is_stroke, false, false);
export_stroke_to_polyline(gpd_eval, gpl, gps_perimeter, is_stroke, false, false);
BKE_gpencil_free_stroke(gps_perimeter);
}
@@ -220,7 +220,8 @@ void GpencilExporterPDF::export_gpencil_layers()
}
}
void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
void GpencilExporterPDF::export_stroke_to_polyline(bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
const bool is_stroke,
const bool do_fill,
@@ -238,7 +239,7 @@ void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
copy_v3_v3(&pt_dst->x, &pt_src->x);
pt_dst->pressure = avg_pressure;
const float radius = stroke_point_radius_get(gpl, gps_temp);
const float radius = stroke_point_radius_get(gpd, gpl, gps_temp);
BKE_gpencil_free_stroke(gps_temp);
@@ -47,7 +47,7 @@ class GpencilExporterPDF : public GpencilExporter {
* \param do_fill: True if the stroke is only fill
*/
void export_stroke_to_polyline(
bGPDlayer *gpl, bGPDstroke *gps, bool is_stroke, bool do_fill, bool normalize);
bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, bool is_stroke, bool do_fill, bool normalize);
/**
* Set color.
* \param do_fill: True if the stroke is only fill.
@@ -213,17 +213,17 @@ void GpencilExporterSVG::export_gpencil_layers()
if ((is_fill) && (params_.flag & GP_EXPORT_FILL)) {
/* Fill is always exported as polygon because the stroke of the fill is done
* in a different SVG command. */
export_stroke_to_polyline(gpl, gps_duplicate, node_gpl, is_stroke, true);
export_stroke_to_polyline(gpd_eval, gpl, gps_duplicate, node_gpl, is_stroke, true);
}
/* Stroke. */
if (is_stroke) {
if (is_normalized) {
export_stroke_to_polyline(gpl, gps_duplicate, node_gpl, is_stroke, false);
export_stroke_to_polyline(gpd_eval, gpl, gps_duplicate, node_gpl, is_stroke, false);
}
else {
bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view(
rv3d_->viewmat, gpd_, gpl, gps_duplicate, 3, diff_mat_.ptr(), 0.0f);
rv3d_->viewmat, gpd_eval, gpl, gps_duplicate, 3, diff_mat_.ptr(), 0.0f);
/* Sample stroke. */
if (params_.stroke_sample > 0.0f) {
@@ -286,7 +286,8 @@ void GpencilExporterSVG::export_stroke_to_path(bGPDlayer *gpl,
node_gps.append_attribute("d").set_value(txt.c_str());
}
void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
void GpencilExporterSVG::export_stroke_to_polyline(bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
pugi::xml_node node_gpl,
const bool is_stroke,
@@ -304,7 +305,7 @@ void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
copy_v3_v3(&pt_dst->x, &pt_src->x);
pt_dst->pressure = avg_pressure;
const float radius = stroke_point_radius_get(gpl, gps_temp);
const float radius = stroke_point_radius_get(gpd, gpl, gps_temp);
BKE_gpencil_free_stroke(gps_temp);
@@ -88,8 +88,12 @@ class GpencilExporterSVG : public GpencilExporter {
* \param node_gpl: Node of the layer.
* \param do_fill: True if the stroke is only fill
*/
void export_stroke_to_polyline(
bGPDlayer *gpl, bGPDstroke *gps, pugi::xml_node node_gpl, bool is_stroke, bool do_fill);
void export_stroke_to_polyline(bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
pugi::xml_node node_gpl,
bool is_stroke,
bool do_fill);
/**
* Set color SVG string for stroke