Fix #120655: GPv3: Conversion: invalid handling of generated 'offset radius' nodetree.

Previous code would re-create a node-tree everytime conversion code was
called (on main file read, but also on all link/append operations).

Worse, it would assing a local generated nodetree to converted linked
GPv3 objects.

This commit solves both issues in a similar way as what was done for the
legacy mesh 'auto smooth' generated node tree.

It also slightly refactors the conversion code by adding a single struct
containing all 'runtime' conversion data (two mappings currently). This
struct is then passed to internal conversion functions as reference.
This commit is contained in:
Bastien Montagne
2024-04-16 17:56:50 +02:00
parent f465943872
commit c3ee098c78

View File

@@ -59,6 +59,16 @@
namespace blender::bke::greasepencil::convert {
/**
* Data shared accross most of GP conversion code.
*/
struct ConversionData {
/** A mapping between a library and a generated 'offset radius' node group. */
Map<Library *, bNodeTree *> offset_radius_ntree_by_library;
/** A mapping between a legacy GPv2 ID and its converted GPv3 ID. */
Map<bGPdata *, GreasePencil *> legacy_to_greasepencil_data;
};
/* -------------------------------------------------------------------- */
/** \name Animation conversion helpers.
*
@@ -704,10 +714,14 @@ static void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pe
}
}
static bNodeTree *add_offset_radius_node_tree(Main &bmain)
constexpr const char *OFFSET_RADIUS_NODETREE_NAME = "Offset Radius GPv3 Conversion";
static bNodeTree *offset_radius_node_tree_add(Main &bmain, Library *library)
{
using namespace blender;
bNodeTree *group = ntreeAddTree(&bmain, DATA_("Offset Radius"), "GeometryNodeTree");
/* NOTE: DO NOT translate this ID name, it is used to find a potentially already existing
* nodetree. */
bNodeTree *group = BKE_node_tree_add_in_lib(
&bmain, library, OFFSET_RADIUS_NODETREE_NAME, "GeometryNodeTree");
if (!group->geometry_node_asset_traits) {
group->geometry_node_asset_traits = MEM_new<GeometryNodeAssetTraits>(__func__);
@@ -818,9 +832,9 @@ static void thickness_factor_to_modifier(const bGPdata &src_object_data, Object
static void layer_adjustments_to_modifiers(Main &bmain,
bGPdata &src_object_data,
Object &dst_object)
Object &dst_object,
ConversionData &conversion_data)
{
bNodeTree *offset_radius_node_tree = nullptr;
/* Handling of animation here is a bit complex, since paths needs to be updated, but also
* FCurves need to be transferred from legacy GPData animation to Object animation.
@@ -991,10 +1005,34 @@ static void layer_adjustments_to_modifiers(Main &bmain,
* GPv2 used a conversion of 1 "px" = 0.001. */
/* Note: this offset may be negative. */
const float radius_offset = float(thickness_px) / 2000.0f;
if (!offset_radius_node_tree) {
offset_radius_node_tree = add_offset_radius_node_tree(bmain);
BKE_ntree_update_main_tree(&bmain, offset_radius_node_tree, nullptr);
}
const auto offset_radius_ntree_ensure = [&](Library *owner_library) {
if (bNodeTree **ntree = conversion_data.offset_radius_ntree_by_library.lookup_ptr(
owner_library))
{
/* Node tree has already been found/created for this versioning call. */
return *ntree;
}
/* Try to find an existing group added by previous versioning to avoid adding duplicates.
*/
LISTBASE_FOREACH (bNodeTree *, ntree_iter, &bmain.nodetrees) {
if (ntree_iter->id.lib != owner_library) {
continue;
}
if (STREQ(ntree_iter->id.name + 2, OFFSET_RADIUS_NODETREE_NAME)) {
conversion_data.offset_radius_ntree_by_library.add_new(owner_library, ntree_iter);
return ntree_iter;
}
}
bNodeTree *new_ntree = offset_radius_node_tree_add(bmain, owner_library);
/* Remove the default user. The count is tracked manually when assigning to modifiers. */
id_us_min(&new_ntree->id);
conversion_data.offset_radius_ntree_by_library.add_new(owner_library, new_ntree);
BKE_ntree_update_main_tree(&bmain, new_ntree, nullptr);
return new_ntree;
};
bNodeTree *offset_radius_node_tree = offset_radius_ntree_ensure(dst_object.id.lib);
auto *md = reinterpret_cast<NodesModifierData *>(BKE_modifier_new(eModifierType_Nodes));
char modifier_name[MAX_NAME];
@@ -2567,21 +2605,15 @@ static void legacy_gpencil_sanitize_annotations(Main &bmain)
}
}
static void legacy_gpencil_object_ex(
Main &bmain,
Object &object,
std::optional<blender::Map<bGPdata *, GreasePencil *>> legacy_to_greasepencil_data)
static void legacy_gpencil_object_ex(Main &bmain, Object &object, ConversionData &conversion_data)
{
BLI_assert((GS(static_cast<ID *>(object.data)->name) == ID_GD_LEGACY));
bGPdata *gpd = static_cast<bGPdata *>(object.data);
GreasePencil *new_grease_pencil = nullptr;
bool do_gpencil_data_conversion = true;
if (legacy_to_greasepencil_data) {
new_grease_pencil = legacy_to_greasepencil_data->lookup_default(gpd, nullptr);
do_gpencil_data_conversion = (new_grease_pencil == nullptr);
}
GreasePencil *new_grease_pencil = conversion_data.legacy_to_greasepencil_data.lookup_default(
gpd, nullptr);
const bool do_gpencil_data_conversion = (new_grease_pencil == nullptr);
if (!new_grease_pencil) {
new_grease_pencil = static_cast<GreasePencil *>(
@@ -2598,15 +2630,13 @@ static void legacy_gpencil_object_ex(
if (do_gpencil_data_conversion) {
legacy_gpencil_to_grease_pencil(bmain, *new_grease_pencil, *gpd);
if (legacy_to_greasepencil_data) {
legacy_to_greasepencil_data->add(gpd, new_grease_pencil);
}
conversion_data.legacy_to_greasepencil_data.add(gpd, new_grease_pencil);
}
legacy_object_modifiers(bmain, object);
/* Layer adjustments should be added after all other modifiers. */
layer_adjustments_to_modifiers(bmain, *gpd, object);
layer_adjustments_to_modifiers(bmain, *gpd, object, conversion_data);
/* Thickness factor is applied after all other changes to the radii. */
thickness_factor_to_modifier(*gpd, object);
@@ -2615,22 +2645,23 @@ static void legacy_gpencil_object_ex(
void legacy_gpencil_object(Main &bmain, Object &object)
{
legacy_gpencil_object_ex(bmain, object, std::nullopt);
ConversionData conversion_data;
legacy_gpencil_object_ex(bmain, object, conversion_data);
}
void legacy_main(Main &bmain, BlendFileReadReport & /*reports*/)
{
ConversionData conversion_data;
/* Ensure that annotations are fully separated from object usages of legacy GPv2 data. */
legacy_gpencil_sanitize_annotations(bmain);
/* Allows to convert a legacy GPencil data only once, in case it's used by several objects. */
Map<bGPdata *, GreasePencil *> legacy_to_greasepencil_data;
LISTBASE_FOREACH (Object *, object, &bmain.objects) {
if (object->type != OB_GPENCIL_LEGACY) {
continue;
}
legacy_gpencil_object_ex(bmain, *object, std::make_optional(legacy_to_greasepencil_data));
legacy_gpencil_object_ex(bmain, *object, conversion_data);
}
/* Potential other usages of legacy bGPdata IDs also need to be remapped to their matching new
@@ -2646,14 +2677,14 @@ void legacy_main(Main &bmain, BlendFileReadReport & /*reports*/)
if ((legacy_gpd->flag & GP_DATA_ANNOTATIONS) != 0) {
continue;
}
GreasePencil *new_grease_pencil = legacy_to_greasepencil_data.lookup_default(legacy_gpd,
nullptr);
GreasePencil *new_grease_pencil = conversion_data.legacy_to_greasepencil_data.lookup_default(
legacy_gpd, nullptr);
if (!new_grease_pencil) {
new_grease_pencil = static_cast<GreasePencil *>(
BKE_id_new_in_lib(&bmain, legacy_gpd->id.lib, ID_GP, legacy_gpd->id.name + 2));
id_us_min(&new_grease_pencil->id);
legacy_gpencil_to_grease_pencil(bmain, *new_grease_pencil, *legacy_gpd);
legacy_to_greasepencil_data.add(legacy_gpd, new_grease_pencil);
conversion_data.legacy_to_greasepencil_data.add(legacy_gpd, new_grease_pencil);
}
gpd_remapper.add(&legacy_gpd->id, &new_grease_pencil->id);
}